Flow

A flow is a programmable automation workflow that defines how incoming or outgoing calls and messages are handled, including IVR menus, routing logic, and AI integrations.

API Reference: Flow endpoints

Overview

Note

AI Context

  • Complexity: Medium – Flows are JSON templates defining action sequences. Creating a flow is a simple CRUD operation; the complexity lies in designing the action logic.

  • Cost: Free. Creating, updating, and deleting flows does not incur charges. Charges only apply when a flow is executed (e.g., via a call or message).

  • Async: No. POST /flows, PUT /flows/{id}, and DELETE /flows/{id} are synchronous and return the result immediately.

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.

Note

AI Implementation Hint

A flow (managed via POST /flows, GET /flows) is a reusable template – it defines the action sequence but does not execute anything by itself. An activeflow (see GET /activeflows) is the runtime instance created when a flow is triggered by a call, message, or API request. Multiple activeflows can run simultaneously from the same flow template. Modifying a flow (PUT /flows/{id}) does not affect activeflows already in progress.

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.

Note

AI Implementation Hint

When creating a flow via POST /flows, you only need name, detail, and actions. Action IDs within the actions array are auto-generated by the server if omitted. You only need to set action id fields explicitly when using goto, branch, or other actions that reference other actions by ID. The type field is auto-set to flow and does not need to be specified.

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 (UUID): The flow’s unique identifier. Returned when creating via POST /flows or listing via GET /flows.

  • type (enum string): The flow’s type. See detail here.

  • name (String): The flow’s display name.

  • detail (String): A human-readable description of the flow.

  • actions (Array of Object): Ordered list of actions to execute. See detail here.

  • tm_create (String, ISO 8601): Timestamp when the flow was created.

  • tm_update (String, ISO 8601): Timestamp of the last update to the flow.

  • tm_delete (String, ISO 8601): Timestamp when the flow was deleted. Set to 9999-01-01 00:00:00.000000 if not deleted.

Note

AI Implementation Hint

Timestamps set to 9999-01-01 00:00:00.000000 indicate the event has not yet occurred. For tm_delete, this means the flow is still active.

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 (UUID): The action’s unique identifier within the flow. Auto-generated by the server if omitted on creation via POST /flows. Only set this explicitly when other actions need to reference it (e.g., goto, branch, condition_* target IDs).

  • next_id (UUID): Override for the next action to execute after this one. If empty or 00000000-0000-0000-0000-000000000000, the cursor moves to the next action in the array sequentially.

  • type (enum string): The action type. Determines what this action does and which option fields are valid. See Type.

  • option (Object): Action-specific configuration. Structure depends on the type field. See individual action type sections below.

  • tm_execute (String, timestamp): Timestamp when this action was last executed. Read-only, populated at runtime in activeflow responses.

Note

AI Implementation Hint

When building a flow’s actions array, you can omit id for most actions. Only set id on actions that are targets of goto, branch, or condition_* actions. The next_id field is rarely needed – it overrides the default sequential execution. Use goto actions instead for clearer flow control.

Type

type

Description

agent_call

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

amd

Answering machine detection. Detects whether the call was answered by a human or machine.

answer

Answer an incoming call. Required before media actions (talk, play) on inbound calls.

beep

Play a beep sound. Commonly used before recording to signal the caller.

branch

Read a variable value and jump to a matching target action ID. Use for IVR menu routing.

call

Start a new independent outgoing call with its own flow. Does not block the current flow.

chatbot_talk

Start an interactive chatbot conversation using STT/TTS.

condition_call_digits

Deprecated. Use condition_variable instead. Condition check on received digits.

condition_call_status

Deprecated. Use condition_variable instead. Condition check on call status.

condition_datetime

Condition check on current UTC time. Useful for business hours routing.

condition_variable

Condition check on any variable value. Supports ==, !=, >, >=, <, <=.

confbridge_join

Join the call to a confbridge (conference bridge).

conference_join

Join the call to a conference. Nested action – flow forks into the conference.

connect

Create outbound call(s) to destination(s) and bridge them with the current call.

conversation_send

Send a text message to an existing conversation.

digits_receive

Wait for DTMF digit input from the caller. Sets voipbin.call.digits variable.

digits_send

Send DTMF tones to the call.

echo

Echo the call’s audio stream back to the caller. Useful for testing.

external_media_start

Start an external media stream (RTP) to/from an external host.

external_media_stop

Stop the external media stream.

fetch

Fetch actions from a remote URL endpoint. Forks the flow with the fetched actions.

fetch_flow

Fetch actions from an existing VoIPBIN flow by ID. Forks the flow.

goto

Jump to another action by ID. Use loop_count to prevent infinite loops.

hangup

Hang up the current call.

hangup_relay

Hang up the call and relay the hangup cause to the referenced call.

message_send

Send an SMS/message to one or more destinations. Fire-and-forget.

play

Play audio file(s) from the given URL(s). Waits for playback to complete.

queue_join

Join the caller to a queue. Nested action – flow forks into the queue’s wait flow.

recording_start

Start recording the call audio. Sets voipbin.recording.id variable.

recording_stop

Stop the current call recording.

sleep

Pause flow execution for a specified duration (milliseconds).

stop

Stop the flow execution immediately.

stream_echo

Echo the RTP stream including DTMF digit reception.

talk

Generate audio via TTS from text or SSML and play it. Waits for playback to complete.

transcribe_start

Start real-time speech-to-text transcription of the call.

transcribe_stop

Stop real-time transcription.

transcribe_recording

Transcribe call recordings (post-call) and send results to webhook.

variable_set

Set a custom variable value for use in subsequent actions.

webhook_send

Send an HTTP request to an external URL. Can be sync (wait for response) or async.

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 (UUID): Target agent ID. Obtained from GET /agents.

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 (enum string): Action to take if a machine answered the call. See Machine handle.

  • async (Boolean): If false, the flow will block until AMD detection completes. If true, detection runs in the background. Default: false.

Machine handle

Type

Description

hangup

Hang up the call immediately if an answering machine is detected.

continue

Continue the flow execution regardless of whether a machine or human answered.

Example

{
    "type": "amd",
    "option": {
        "machine_handle": "hangup",
        "async": 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 (String): The variable name to read for branching. Available variables are listed here. Default: voipbin.call.digits. If empty, the default variable is used.

  • default_target_id (UUID): Action ID to jump to when no target_ids key matches the variable value. Must reference an id of another action in the same flow.

  • target_ids (Object): Map of variable value (String) to action ID (UUID). Each key is a possible variable value, and the corresponding value is the action id to jump to.

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 (Object): Source address. See Address.

  • destinations (Array of Object): Array of destination addresses. See Address.

  • flow_id (UUID): Flow ID to attach to the new call. Obtained from GET /flows. If not set, the actions array is used instead.

  • actions (Array of Object): Inline array of actions for the new call’s flow. Used only if flow_id is not set.

  • chained (Boolean): If true, the new call will be hung up when the master call hangs up. Default: false.

  • early_execution (Boolean): If true, VoIPBIN will execute the flow when the call starts ringing (before answer). Default: false.

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 (UUID): Chatbot ID. Obtained from the chatbot management API.

  • gender (enum string): Voice gender for TTS output. Values: male, female, neutral.

  • language (String): Language in BCP47 format (e.g., en-US).

  • duration (Integer): Maximum duration for the chatbot session, in seconds.

Confbridge Join

Join to the confbridge.

Parameters

{
    "type": "confbridge_join",
    "option": {
        "confbridge_id": "<string>"
    }
}
  • confbridge_id (UUID): Target confbridge ID to join.

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 (Integer): Expected length of received digits to match.

  • key (String): Digit string to match against received digits.

  • false_target_id (UUID): Action ID to jump to when the condition is not met. Must reference an id of another action in the same flow.

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 (enum string): Call status to match against. See Status.

  • false_target_id (UUID): Action ID to jump to when the condition is not met. Must reference an id of another action in the same flow.

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 (enum string): Comparison operator. One of ==, !=, >, >=, <, <=.

  • minute (Integer): Minute to match (0-59). Set to -1 to match all minutes (wildcard).

  • hour (Integer): Hour to match (0-23, UTC). Set to -1 to match all hours (wildcard).

  • day (Integer): Day of month to match (1-31). Set to -1 to match all days (wildcard).

  • month (Integer): Month to match (1-12). Set to 0 to match all months (wildcard).

  • weekdays (Array of Integer): List of weekday numbers. Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6. Empty array matches all days.

  • false_target_id (UUID): Action ID to jump to when the condition is not met. Must reference an id of another action in the same flow.

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 (enum string): Comparison operator. One of ==, !=, >, >=, <, <=.

  • variable (String): Variable name to check. Available variables are listed here.

  • value_type (enum string): Type of comparison value. One of string, number, length.

  • value_string (String): Comparison value when value_type is string.

  • value_number (Integer): Comparison value when value_type is number.

  • value_length (Integer): Comparison value when value_type is length. Compares the character length of the variable’s value.

  • false_target_id (UUID): Action ID to jump to when the condition is not met. Must reference an id of another action in the same flow.

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 (UUID): Conference ID to join. Obtained from GET /conferences or the response of POST /conferences.

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 (Object): Source address for the outbound call leg. See Address.

  • destinations (Array of Object): Array of destination addresses to ring. If multiple destinations are provided, all ring simultaneously (ring-all). See Address.

  • early_media (Boolean): If true, allows early media (audio before answer, e.g., ringback tone). Default: false.

  • relay_reason (Boolean): If true, relays the hangup reason from the connected call back to the master call. Default: false.

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 (UUID): Target conversation ID. Obtained from GET /conversations.

  • text (String): Text message content to send. Supports ${variable} substitution.

  • sync (Boolean): If true, the flow waits until the message is delivered. If false, the message is sent asynchronously and the flow continues immediately. Default: false.

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 (Integer): Maximum wait time in milliseconds for DTMF input. The flow continues to the next action after this duration expires. Example: 5000 for 5 seconds.

  • length (Integer): Maximum number of DTMF digits to collect before continuing. Default: 1. The flow continues as soon as this many digits are received.

  • key (String): Termination key. If set, this DTMF key (e.g., #) ends digit collection immediately. The termination key is included in the resulting voipbin.call.digits variable value.

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 (String): The digit string to send. Allowed characters: 0-9, A-D, #, *. Maximum 100 characters.

  • duration (Integer): Duration of each DTMF tone in milliseconds. Allowed range: 100-1000.

  • interval (Integer): Interval between sending consecutive keys in milliseconds. Allowed range: 0-5000.

Example

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

Echo

Echoing the call.

Parameters

{
    "type": "echo",
    "option": {
        "duration": <number>,
    }
}
  • duration (Integer): Echo duration in milliseconds.

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 (String): External media target host address (e.g., 192.168.1.100:8000).

  • encapsulation (String): Media encapsulation protocol. Default: rtp.

  • transport (String): Network transport protocol. Default: udp.

  • connection_type (String): Connection type. Default: client.

  • format (String): Audio codec format. Default: ulaw.

  • direction (enum string): Media direction. Default: both. Values: both, send, receive.

  • data (String): Reserved for future use.

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 (String): The URL to fetch flow actions from. Must be a publicly accessible HTTPS endpoint.

  • event_method (enum string): HTTP method to use for the fetch request. Values: GET, POST.

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 (UUID): The ID of the flow to fetch actions from. Obtained from GET /flows or the response of POST /flows.

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 (UUID): Action ID to jump to. Must reference an id of another action in the same flow.

  • loop_count (Integer): Maximum number of times this goto will execute. After exceeding the count, the goto is skipped and execution continues to the next action. Always set this to prevent infinite loops.

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>"
    }
}
  • reference_id (UUID): The call ID whose hangup reason should be relayed. Obtained from GET /calls or a call-related variable (e.g., ${voipbin.call.id}).

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 (Object): Source address for the message. See Address. Must be a number you own, obtained from GET /numbers.

  • destinations (Array of Object): Array of destination addresses. See Address.

  • text (String): Message text content. Supports ${variable} substitution.

Play

Plays the linked file.

Parameters

{
    "type": "play",
    "option": {
        "stream_urls": [
            "<string>",
            ...
        ]
    }
}
  • stream_urls (Array of String): Array of audio file URLs to play sequentially. Supported formats include WAV, MP3. URLs must be publicly accessible.

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 (UUID): Target queue ID to join. Obtained from GET /queues or the response of POST /queues.

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 (enum string): Audio encoding format. Values: wav, mp3, ogg.

  • end_of_silence (Integer): Maximum duration of silence in seconds before recording stops automatically. Set to 0 for no limit.

  • end_of_key (enum string): DTMF key that stops the recording. Values: none, any, *, #.

  • duration (Integer): Maximum recording duration in seconds. Set to 0 for no limit.

  • beep_start (Boolean): If true, play a beep tone 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 (Integer): Sleep duration in milliseconds. Example: 10000 for 10 seconds.

Stream Echo

Echoing the RTP stream including the digits receive.

Parameters

{
    "type": "stream_echo",
    "option": {
        "duration": <number>
    }
}
  • duration (Integer): Echo duration in milliseconds.

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 (String): Text to convert to speech. Supports plain text and SSML (https://cloud.google.com/text-to-speech/docs/ssml). Supports ${variable} substitution.

  • language (String): Language in BCP47 format. Examples: en-US, ko-KR, ja-JP. The value may be a two-letter language code (e.g., en) or language code with country/region (e.g., en-US).

  • provider (enum string): TTS provider. Optional. Values: gcp (Google Cloud TTS), aws (AWS Polly). Default: gcp. If the selected provider fails, the system automatically falls back to the alternative provider with the default voice for the language.

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

  • digits_handle (enum string): How to handle DTMF input received during playback. See Digits handle. Optional.

Digits handle

Type

Description

next

If any DTMF digit is received during TTS playback, stop playback immediately and move to the next action. Useful for “press any key to skip” patterns.

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>",
        "provider": "<string>",
        "direction": "<string>"
    }
}
  • language (String): Language in BCP47 format (e.g., en-US).

  • provider (String, optional): STT provider to use: gcp or aws. If omitted, VoIPBIN selects the best available provider automatically.

  • direction (String, optional): Audio direction to transcribe: in, out, or both. Defaults to both.

Example

{
    "type": "transcribe_recording",
    "option": {
        "language": "en-US",
        "provider": "gcp",
        "direction": "both"
    }
}

Transcribe start

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

Parameters

{
    "type": "transcribe_start",
    "option": {
        "language": "<string>",
        "provider": "<string>",
        "direction": "<string>"
    }
}
  • language (String): Language in BCP47 format. Examples: en-US, ko-KR. The value may be a two-letter language code (e.g., en) or language code with country/region (e.g., en-US).

  • provider (String, optional): STT provider to use: gcp or aws. If omitted, VoIPBIN selects the best available provider automatically.

  • direction (String, optional): Audio direction to transcribe: in, out, or both. Defaults to both.

Example

{
    "type": "transcribe_start",
    "option": {
        "language": "en-US",
        "provider": "gcp",
        "direction": "both"
    }
}

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 (String): Variable name to set. Use dot notation for namespacing (e.g., customer.language). This variable can then be referenced in subsequent actions using ${key} syntax.

  • value (String): Variable value to set. Supports ${variable} substitution from existing variables.

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 (Boolean): If true, the flow waits for the webhook response before continuing. If false, the request is sent asynchronously and the flow continues immediately. Use true when you need response data for branching.

  • uri (String): Destination URL. Must be a publicly accessible HTTPS endpoint.

  • method (enum string): HTTP method. Values: POST, GET, PUT, DELETE.

  • data_type (String): Content-Type header value. Example: application/json.

  • data (String): Request body as a string. Supports ${variable} substitution. For JSON payloads, escape inner quotes (e.g., "{\"key\": \"${variable}\"}").

Note

AI Implementation Hint

When using sync: true, the webhook response can set flow variables. The response body is parsed and variables are set from the response fields. When using sync: false, no response data is available – use this for logging and fire-and-forget notifications.

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

Before working with flows, you need:

  • An authentication token. Obtain one via POST /auth/login or use an access key from GET /accesskeys.

  • (For update/delete) A flow ID (UUID). Obtain from GET /flows or the response of POST /flows.

Note

AI Implementation Hint

When creating a flow via POST /flows, action id fields are optional. The server auto-generates UUIDs for actions that lack explicit IDs. Only set action IDs when you need to reference them from goto, branch, or condition_* actions using target_id or target_ids. Flow changes (update/delete) do not affect calls already in progress – they only apply to future executions.

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. Flow changes will only affect new calls.

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

Note

AI Implementation Hint

The DELETE request uses the DELETE HTTP method, not GET. A successful deletion returns HTTP 204 No Content. The flow is soft-deleted (tm_delete is set) and will no longer appear in GET /flows list results, but calls already using this flow are not affected.

Tutorial scenario

Before running these scenarios, you need:

  • An authentication token. Obtain one via POST /auth/login or use an access key from GET /accesskeys.

  • A source phone number in E.164 format (e.g., +15559876543). This must be a number you own. Obtain your numbers via GET /numbers.

  • A destination phone number in E.164 format (e.g., +15551112222).

  • (Optional) An existing flow to attach to a number. Create one via POST /flows.

Note

AI Implementation Hint

These scenarios use POST /calls with inline actions arrays. You can also pre-register a flow via POST /flows and then reference it by flow_id when creating a call. The inline approach is simpler for one-off calls; the flow approach is better when reusing the same logic across multiple calls or numbers. All phone numbers must be in E.164 format (e.g., +15559876543).

Simple voicemail

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

Note

AI Implementation Hint

This scenario uses condition_call_status (deprecated). For new implementations, use condition_variable with variable: "voipbin.call.status" and value_string: "progressing" instead. The next_id field set to 00000000-0000-0000-0000-000000000000 means “continue to the next action in the array” – it is the same as omitting next_id.

               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.

Note

AI Implementation Hint

This section describes internal architecture and is primarily useful for understanding how the system works, not for building flows. Key takeaways for API consumers: (1) Actions return one of four result types (next, wait, block, done) which determines whether the flow continues immediately or pauses. (2) Variables are stored as a JSON column in the activeflow database record and resolved via ${...} pattern substitution at execution time. (3) Concurrent events for the same activeflow are handled via database-level locking – the first event wins, later events are discarded as stale.

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.

Before implementing these patterns, you need:

  • An authentication token. Obtain one via POST /auth/login or use an access key from GET /accesskeys.

  • Familiarity with basic flow concepts (actions, branching, variables). See Flow Overview and Basic Tutorial.

  • (For queue patterns) Queues with agents configured. Create queues via POST /queues and assign agents.

  • (For AI patterns) An AI agent configured. Obtain the ai_id from your AI agent setup.

Note

AI Implementation Hint

These advanced patterns rely heavily on fetch_flow for modularity. Each sub-flow is a standalone flow created via POST /flows, and the main flow references them by flow_id. This means you need to create the sub-flows first, obtain their IDs from the responses, and then use those IDs in the main flow’s fetch_flow actions. The on_complete_flow_id field is set on the flow definition itself (not on individual actions).

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

Note

AI Implementation Hint

The condition_datetime action checks against UTC time, not local time. To implement business hours for a specific timezone, calculate the UTC offset and adjust the hour values accordingly. For example, 9 AM EST = 14:00 UTC. Two condition_datetime actions are needed to define a range (one for opening, one for closing).

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.

Before debugging, you need:

  • An authentication token. Obtain one via POST /auth/login or use an access key from GET /accesskeys.

  • The call ID (UUID) or activeflow ID (UUID) of the session you want to debug. Obtain from GET /calls or GET /activeflows.

  • (Optional) A webhook endpoint (e.g., https://webhook.site) to receive real-time flow events for monitoring.

Note

AI Implementation Hint

The most common debugging path is: (1) Find the call via GET /calls using the phone number or time range. (2) Get the activeflow via GET /activeflows?reference_id={call-id}. (3) Inspect variables via GET /activeflows/{id}/variables to see what values were set. (4) Check current_action_id and execute_count to understand where execution stopped and why.

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

Note

AI Implementation Hint

Branch matching is exact string comparison and case-sensitive. The most common cause of branch failures is that digits_receive with a key terminator (e.g., #) includes the terminator in the voipbin.call.digits variable. For example, if the user presses 1#, the variable value is 1#, which does not match a target_ids key of "1". Either remove the key parameter or account for the terminator in your target keys.

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.

Note

AI Implementation Hint

When generating flows programmatically, follow three key rules: (1) Always set default_target_id on every branch action to handle unexpected input. (2) Always set loop_count on every goto action to prevent infinite loops. (3) Only set explicit id fields on actions that are referenced as targets by goto, branch, or condition_* actions.

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

An activeflow is a running instance of a flow, representing the real-time execution state of a flow attached to a call or message session.

API Reference: Activeflow endpoints

Overview

Note

AI Context

  • Complexity: High – Activeflows are runtime instances of flows. You never create them directly; they are created automatically when a flow is triggered (e.g., by an incoming call or POST /calls).

  • Cost: No direct cost. Activeflows are a monitoring/control interface. However, the underlying trigger (call, message) may incur charges.

  • Async: Yes. Activeflows execute asynchronously. Use GET /activeflows/{id} to poll the current state, or subscribe via WebSocket for real-time updates.

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

Note

AI Implementation Hint

You cannot create an activeflow directly. Activeflows are created automatically when a flow is triggered (e.g., by an incoming call or by creating an outbound call with POST /calls). Use GET /activeflows to list running instances, and POST /activeflows/{id}/stop to terminate one. The reference_type field tells you what triggered the activeflow (call, message, api, etc.).

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 (UUID): The activeflow’s unique identifier. Returned when listing via GET /activeflows or GET /activeflows/{id}.

  • customer_id (UUID): The customer who owns this activeflow. Obtained from GET /customers or your authentication context.

  • flow_id (UUID): The flow template this activeflow was created from. Obtained from GET /flows.

  • status (enum string): The activeflow’s current status. See detail here.

  • reference_type (enum string): The resource type that triggered this activeflow. See detail here.

  • reference_id (UUID): The ID of the resource that triggered this activeflow (e.g., a call ID if reference_type is call). Obtained from the corresponding resource endpoint (e.g., GET /calls/{id}).

  • current_action (Object): The action currently being executed. See detail here.

  • forward_action_id (UUID): The ID of the next action to execute. Set to 00000000-0000-0000-0000-000000000000 if sequential (next in array).

  • tm_create (String, ISO 8601): Timestamp when the activeflow was created.

  • tm_update (String, ISO 8601): Timestamp of the last state change.

  • tm_delete (String, ISO 8601): Timestamp when the activeflow was deleted. Set to 9999-01-01 00:00:00.000000 if not deleted.

Note

AI Implementation Hint

Activeflows are read-only from an API perspective – you cannot create them via API. They are created automatically when a flow is triggered. You can only list them (GET /activeflows), inspect them (GET /activeflows/{id}), or stop them (POST /activeflows/{id}/stop). Timestamps set to 9999-01-01 00:00:00.000000 indicate the event has not yet occurred.

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.

Status

Description

""

Initial state. The activeflow has been created but execution has not yet started.

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

Before working with activeflows, you need:

  • An authentication token. Obtain one via POST /auth/login or use an access key from GET /accesskeys.

  • An existing activeflow ID (UUID). Activeflows are created automatically when a flow is triggered (e.g., by an incoming call or POST /calls). List them via GET /activeflows.

Note

AI Implementation Hint

You cannot create activeflows directly via the API. They are created automatically when a flow is triggered. To have an activeflow to inspect, first create a call (POST /calls) with flow actions, then list activeflows with GET /activeflows. The status field will be running during execution and ended after completion.

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"
}