Formatting Phone Numbers in Genesys Cloud Architect: From E.164 to National Format

Formatting Phone Numbers in Genesys Cloud Architect: From E.164 to National Format

What You Will Build

  • A working Architect flow expression that converts an E.164 formatted phone number (e.g., +14155552671) into the standard US national format (415) 555-2671.
  • This solution uses the Genesys Cloud Architect Expression language (expr) to manipulate strings and regular expressions without external API calls.
  • The logic is implemented directly within the Architect interface using a Script Action or a Set Variable action, requiring no external SDK or runtime dependencies.

Prerequisites

  • Genesys Cloud Platform Access: You must have a user account with permissions to edit Architect flows (typically architect:flow:edit or architect:flow:read).
  • Architect Knowledge: Familiarity with creating Scripts, Flows, or IVRs in Genesys Cloud Architect.
  • Data Source: A valid phone number variable in E.164 format (e.g., system.attributes.phone_number or a custom variable like $.input_phone). Note that Genesys Cloud typically stores phone numbers in E.164 format by default.
  • No External Dependencies: This solution runs entirely within the Genesys Cloud edge network using the built-in expression engine. No Python, JavaScript, or external HTTP calls are required.

Authentication Setup

This tutorial does not require OAuth authentication for the end-user experience. The logic executes server-side within the Genesys Cloud Architect engine. However, if you are using the Genesys Cloud REST API to deploy this flow via CI/CD, you will need:

  • OAuth Client Type: Client Credentials or JWT.
  • Required Scopes: architect:flow:edit to save the flow.
  • SDK: PureCloudPlatformClientV2 (Python/Java/C#) or @genesyscloud/node-sdk (Node.js).

For this tutorial, we will focus on the Expression Logic itself, which you will paste into the Architect UI.

Implementation

Step 1: Understanding the Input Data

Genesys Cloud stores phone numbers in E.164 format. This format includes the country code prefix. For US and Canadian numbers, this is +1 followed by 10 digits.
Example Input: +14155552671

Our goal is to extract the Area Code (first 3 digits after the country code), the Prefix (next 3 digits), and the Line Number (last 4 digits) and format them as (XXX) XXX-XXXX.

If the input might come from different countries, we must handle the variable length of the country code. However, for a specific US/Canada use case, the logic is deterministic. For a global solution, we would need a more complex regex or a lookup table. This tutorial covers the US/Canada specific transformation, which is the most common requirement.

Step 2: Constructing the Regular Expression

The Genesys Cloud expression engine supports standard regular expressions via the ~ operator for matching and capture groups.

To parse +14155552671:

  1. We need to ignore the +1 prefix.
  2. We need to capture the next 3 digits (Area Code).
  3. We need to capture the next 3 digits (Prefix).
  4. We need to capture the last 4 digits (Line Number).

The regex pattern is:
^\+1(\d{3})(\d{3})(\d{4})$

  • ^: Start of string.
  • \+1: Matches the literal +1.
  • (\d{3}): Capture Group 1: 3 digits.
  • (\d{3}): Capture Group 2: 3 digits.
  • (\d{4}): Capture Group 3: 4 digits.
  • $: End of string.

Step 3: Implementing the Logic in Architect

In Genesys Cloud Architect, you cannot use a simple replace function with backreferences like (\1) \2-\3. You must use the expr function with a conditional check or a more robust string manipulation approach.

The most reliable method in Architect is to use the regex function (available in newer versions) or a combination of left, right, and mid functions if the length is fixed. However, the regex function with capture groups is the cleanest.

Note: As of recent updates, Genesys Cloud Architect supports the regex function which returns a map of captured groups.

Option A: Using the regex Function (Recommended)

  1. Open your Flow or Script.
  2. Add a Script Action or a Set Variable action.
  3. Define the Output Variable: Create a variable named formatted_phone.
  4. Enter the Expression:
// This expression checks if the phone number matches the US/Canada E.164 pattern.
// If it matches, it formats it. If not, it returns the original number or an empty string.

if (
  regex("+1(\\d{3})(\\d{3})(\\d{4})", $.input_phone) != null,
  "(" + regex("+1(\\d{3})(\\d{3})(\\d{4})", $.input_phone).group1 + ") " + 
  regex("+1(\\d{3})(\\d{3})(\\d{4})", $.input_phone).group2 + "-" + 
  regex("+1(\\d{3})(\\d{3})(\\d{4})", $.input_phone).group3,
  $.input_phone
)

Breakdown of the Expression:

  • regex(pattern, string): Attempts to match the pattern against the string. Returns a map with keys group0 (full match), group1, group2, etc., or null if no match.
  • \\d{3}: In the Architect expression editor, backslashes must be escaped. So \d becomes \\d.
  • $.input_phone: The variable containing the raw E.164 number.
  • group1, group2, group3: Accessing the captured groups from the regex result.
  • The if statement ensures we do not crash if the input is not a valid US/Canada number.

Option B: Using String Manipulation (Legacy/Fallback)

If you are on an older version of Architect that does not support the regex function with capture groups, you can use fixed-position string slicing. This assumes the input is always exactly 12 characters long (+1 + 10 digits).

// Only works if $.input_phone is exactly 12 characters long (e.g., +14155552671)
if (
  length($.input_phone) == 12,
  "(" + mid($.input_phone, 3, 3) + ") " + mid($.input_phone, 6, 3) + "-" + right($.input_phone, 4),
  $.input_phone
)
  • length($.input_phone): Checks if the string is 12 characters.
  • mid($.input_phone, 3, 3): Extracts 3 characters starting at index 3 (0-indexed). Index 0 is +, 1 is 1, 2 is the first digit of the area code. Wait, +1415...
    • Index 0: +
    • Index 1: 1
    • Index 2: 4 (Area Code Start)
    • Index 3: 1
    • Index 4: 5
    • So, mid($.input_phone, 2, 3) gets the Area Code.
    • mid($.input_phone, 5, 3) gets the Prefix.
    • right($.input_phone, 4) gets the Line Number.

Corrected Legacy Expression:

if (
  length($.input_phone) == 12,
  "(" + mid($.input_phone, 2, 3) + ") " + mid($.input_phone, 5, 3) + "-" + right($.input_phone, 4),
  $.input_phone
)

Step 4: Handling Edge Cases

Real-world data is messy. Phone numbers might:

  1. Have spaces or hyphens already: +1 415-555-2671
  2. Be missing the country code: 4155552671
  3. Be international: +442079460000

To make the expression robust, we should first sanitize the input.

Sanitization Expression:
Remove all non-digit characters, except the leading +.

// Step 1: Sanitize the input
let sanitized_phone = replace_all(regex("[^\\d+]", $.input_phone, "global"), "")

// Step 2: Format based on sanitized input
if (
  regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", sanitized_phone) != null,
  "(" + regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", sanitized_phone).group1 + ") " + 
  regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", sanitized_phone).group2 + "-" + 
  regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", sanitized_phone).group3,
  sanitized_phone
)

Note: Architect expressions do not support let variables in a single line. You must chain them or use intermediate variables.

Chained Expression (Single Line):

if (
  regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", replace_all(regex("[^\\d+]", $.input_phone, "global"), "")) != null,
  "(" + regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", replace_all(regex("[^\\d+]", $.input_phone, "global"), "")).group1 + ") " + 
  regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", replace_all(regex("[^\\d+]", $.input_phone, "global"), "")).group2 + "-" + 
  regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", replace_all(regex("[^\\d+]", $.input_phone, "global"), "")).group3,
  replace_all(regex("[^\\d+]", $.input_phone, "global"), "")
)

This is verbose but functional. For readability and maintainability, it is highly recommended to use Intermediate Variables in your Script.

  1. Action 1: Set Variable sanitized_phone
    Expression: replace_all(regex("[^\\d+]", $.input_phone, "global"), "")
  2. Action 2: Set Variable formatted_phone
    Expression:
    if (
      regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone) != null,
      "(" + regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone).group1 + ") " + 
      regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone).group2 + "-" + 
      regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone).group3,
      $.sanitized_phone
    )
    

Complete Working Example

Below is a complete Script definition that can be imported or manually recreated in Architect.

Script Name: Format US Phone Number

Parameters:

  • input_phone (String): The raw phone number in E.164 or dirty format.

Variables:

  • sanitized_phone (String)
  • formatted_phone (String)

Actions:

  1. Set Variable: sanitized_phone

    replace_all(regex("[^\\d+]", $.input_phone, "global"), "")
    
  2. Set Variable: formatted_phone

    if (
      regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone) != null,
      "(" + regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone).group1 + ") " + 
      regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone).group2 + "-" + 
      regex("^\\+1(\\d{3})(\\d{3})(\\d{4})$", $.sanitized_phone).group3,
      $.sanitized_phone
    )
    
  3. Return Value: $.formatted_phone

Usage in a Flow

  1. Drag the Script action into your flow.
  2. Select Format US Phone Number.
  3. Map input_phone to system.attributes.phone_number or your custom variable.
  4. After the script runs, use $.formatted_phone in your TTS (Text-to-Speech) or SMS message.

Common Errors & Debugging

Error: null result from regex

  • Cause: The input phone number does not match the expected pattern. This often happens if the country code is missing or the number is international.
  • Fix: Check the sanitized_phone variable value in the Architect Debugger. Ensure it starts with +1 and has 10 digits following it. If you need to handle international numbers, you must create separate regex patterns for each country code.

Error: regex function not found

  • Cause: You are using an older version of the Architect expression engine that does not support the regex function with capture groups.
  • Fix: Use the Legacy String Manipulation method (Option B in Step 3) using mid and right functions, ensuring the input length is fixed.

Error: Invalid Character in Expression

  • Cause: Forgetting to escape backslashes in the regex pattern. In JSON and Architect expressions, \d must be written as \\d.
  • Fix: Replace all single backslashes \ with double backslashes \\ in the regex pattern.

Error: Spaces in Output

  • Cause: The regex capture groups might include unexpected whitespace if the sanitization step fails.
  • Fix: Ensure the sanitization step replace_all(regex("[^\\d+]", $.input_phone, "global"), "") is executed before the formatting step.

Official References