How to Implement Customer Lookup with Architect GetExternalContactAction

How to Implement Customer Lookup with Architect GetExternalContactAction

What You Will Build

  • A pure Python script that invokes a Genesys Cloud CX Architect flow containing a GetExternalContactAction to retrieve customer data based on an inbound phone number.
  • This tutorial uses the Genesys Cloud CX Python SDK (genesyscloud) and the underlying REST API for flow execution.
  • The programming language covered is Python 3.9+.

Prerequisites

  • OAuth Client Type: API Key or Client Credentials Grant.
  • Required Scopes: flow:externalcontact:execute, flow:definition:read.
  • SDK Version: genesyscloud >= 150.0.0 (ensure you are using the latest stable release).
  • Language/Runtime: Python 3.9 or higher.
  • External Dependencies: genesyscloud, python-dotenv (for secure credential management).

Authentication Setup

Genesys Cloud CX uses OAuth 2.0 for authentication. For server-to-server integrations, the Client Credentials Grant is the standard approach. You must store your client_id and client_secret securely. Never hardcode these values.

Create a .env file in your project root:

GENESYS_CLOUD_REGION=us-east-1
GENESYS_CLOUD_CLIENT_ID=your_client_id_here
GENESYS_CLOUD_CLIENT_SECRET=your_client_secret_here

Install the required packages:

pip install genesyscloud python-dotenv

The following code initializes the Genesys Cloud Platform Client. The SDK handles token acquisition and refresh automatically once initialized.

import os
from dotenv import load_dotenv
from genesyscloud import PlatformClient

# Load environment variables
load_dotenv()

def get_platform_client() -> PlatformClient:
    """
    Initializes and returns a configured Genesys Cloud Platform Client.
    """
    client = PlatformClient()
    
    # Set the region (e.g., us-east-1, eu-west-1, au-southeast-1)
    region = os.getenv("GENESYS_CLOUD_REGION", "us-east-1")
    client.set_base_url(f"https://{region}.mygenesys.com/api/v2")
    
    # Configure OAuth using Client Credentials
    client.set_oauth_client_credentials(
        os.getenv("GENESYS_CLOUD_CLIENT_ID"),
        os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
    )
    
    return client

client = get_platform_client()

Implementation

The core logic involves two distinct phases:

  1. Validating the Flow: Ensuring the Architect Flow exists and is published.
  2. Executing the Flow: Sending the phone number as an input parameter to the flow, which triggers the GetExternalContactAction.

Step 1: Define the Architect Flow Structure

Before writing the execution code, you must understand what the Architect Flow looks like. The GetExternalContactAction is a specific action type in Genesys Cloud that calls an external HTTP endpoint or uses a pre-configured external contact source.

For this tutorial, assume you have created a Flow with the following characteristics:

  • Name: Customer Lookup by Phone
  • Input Parameter: phoneNumber (String)
  • Action: GetExternalContactAction
    • Source: External HTTP Endpoint (e.g., https://your-crm.com/api/lookup)
    • Method: GET
    • URL Pattern: https://your-crm.com/api/lookup?phone={input.phoneNumber}
  • Output Parameter: customerData (JSON object returned from the HTTP call)

You need the Flow ID to execute this. You can retrieve it by listing flows or by copying it from the Architect UI (URL: https://{region}.mypurecloud.com/admin/architect/flow/{flow-id}).

Step 2: Execute the Flow with Input Parameters

To execute a flow via the API, you use the POST /api/v2/architect/flows/{flowId}/executions endpoint. The SDK provides a method create_flow_execution (or similar depending on the exact SDK version wrapper).

The critical part is constructing the ExecutionRequest body. This object must contain:

  • input: A dictionary mapping your flow’s input parameters.
  • context: Optional, but recommended for tracking (e.g., conversation ID).
from genesyscloud import ArchitectApi
from genesyscloud.models import FlowExecutionRequest, FlowExecutionInput

def lookup_customer_by_phone(flow_id: str, phone_number: str) -> dict:
    """
    Executes a Genesys Cloud Architect Flow to look up customer data.
    
    Args:
        flow_id (str): The ID of the Architect Flow.
        phone_number (str): The E.164 formatted phone number (e.g., +15551234567).
        
    Returns:
        dict: The output data from the flow execution.
    """
    architect_api = ArchitectApi(client)
    
    # Construct the input object
    # The key 'phoneNumber' must match the Input Parameter name defined in Architect
    input_data = FlowExecutionInput(
        values={
            "phoneNumber": phone_number
        }
    )
    
    # Construct the execution request
    request_body = FlowExecutionRequest(
        input=input_data,
        # Optional: Add context for debugging or correlation
        context={
            "source": "python-sdk-tutorial",
            "timestamp": "2023-10-27T10:00:00Z"
        }
    )
    
    try:
        # Execute the flow
        # Note: This is a synchronous call. It waits for the flow to complete.
        # For long-running flows, consider using async execution patterns.
        response = architect_api.post_architect_flow_execution(
            flow_id=flow_id,
            body=request_body
        )
        
        return response
        
    except Exception as e:
        print(f"Error executing flow: {e}")
        raise

# Example Usage
FLOW_ID = "your-flow-id-here"
PHONE_NUMBER = "+15551234567"

result = lookup_customer_by_phone(FLOW_ID, PHONE_NUMBER)
print(f"Flow Output: {result.output}")

Step 3: Processing the Response

The FlowExecution response object contains the output field, which is a dictionary of key-value pairs defined in your Architect Flow’s output parameters.

If your GetExternalContactAction successfully retrieved data from your external CRM and mapped it to an output parameter named customerProfile, you will access it like this:

if result and result.output:
    customer_profile = result.output.get("customerProfile")
    if customer_profile:
        print(f"Customer Name: {customer_profile.get('name')}")
        print(f"Customer ID: {customer_profile.get('id')}")
        print(f"VIP Status: {customer_profile.get('is_vip')}")
    else:
        print("No customer profile found in flow output.")
else:
    print("Flow execution did not return output.")

Complete Working Example

This is a complete, runnable Python script. Replace the placeholder values with your actual credentials and Flow ID.

import os
import sys
from dotenv import load_dotenv
from genesyscloud import PlatformClient, ArchitectApi
from genesyscloud.models import FlowExecutionRequest, FlowExecutionInput

# Load environment variables from .env file
load_dotenv()

def get_platform_client() -> PlatformClient:
    """
    Initializes and returns a configured Genesys Cloud Platform Client.
    """
    client = PlatformClient()
    
    # Set the region (e.g., us-east-1, eu-west-1, au-southeast-1)
    region = os.getenv("GENESYS_CLOUD_REGION", "us-east-1")
    client.set_base_url(f"https://{region}.mygenesys.com/api/v2")
    
    # Configure OAuth using Client Credentials
    client_id = os.getenv("GENESYS_CLOUD_CLIENT_ID")
    client_secret = os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
    
    if not client_id or not client_secret:
        raise ValueError("GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET must be set in environment variables.")
        
    client.set_oauth_client_credentials(client_id, client_secret)
    
    return client

def lookup_customer_by_phone(flow_id: str, phone_number: str) -> dict:
    """
    Executes a Genesys Cloud Architect Flow to look up customer data.
    
    Args:
        flow_id (str): The ID of the Architect Flow containing GetExternalContactAction.
        phone_number (str): The E.164 formatted phone number.
        
    Returns:
        dict: The output data from the flow execution.
    """
    client = get_platform_client()
    architect_api = ArchitectApi(client)
    
    # Validate input
    if not phone_number.startswith("+"):
        print("Warning: Phone number should be in E.164 format (starting with +).")
    
    # Construct the input object
    # The key 'phoneNumber' MUST match the Input Parameter name defined in Architect
    input_data = FlowExecutionInput(
        values={
            "phoneNumber": phone_number
        }
    )
    
    # Construct the execution request
    request_body = FlowExecutionRequest(
        input=input_data,
        context={
            "source": "python-sdk-tutorial",
            "request_id": "req-001"
        }
    )
    
    try:
        print(f"Executing Flow ID: {flow_id} with input: {phone_number}")
        
        # Execute the flow synchronously
        response = architect_api.post_architect_flow_execution(
            flow_id=flow_id,
            body=request_body
        )
        
        return response
        
    except Exception as e:
        # The SDK raises specific exceptions for HTTP errors
        print(f"Error executing flow: {e}")
        raise

def main():
    # Configuration
    FLOW_ID = os.getenv("GENESYS_CLOUD_FLOW_ID", "your-flow-id-here")
    PHONE_NUMBER = os.getenv("TEST_PHONE_NUMBER", "+15551234567")
    
    if FLOW_ID == "your-flow-id-here":
        print("Error: Please set GENESYS_CLOUD_FLOW_ID in your .env file.")
        sys.exit(1)
        
    try:
        result = lookup_customer_by_phone(FLOW_ID, PHONE_NUMBER)
        
        # Process the output
        if result and result.output:
            print("\n--- Flow Execution Successful ---")
            print(f"Output Keys: {list(result.output.keys())}")
            
            # Example: Extracting specific data
            # Adjust 'customerData' to match your Architect Output Parameter name
            customer_data = result.output.get("customerData")
            
            if customer_data:
                if isinstance(customer_data, dict):
                    print(f"Customer Name: {customer_data.get('name', 'N/A')}")
                    print(f"Customer Email: {customer_data.get('email', 'N/A')}")
                    print(f"Customer Tier: {customer_data.get('tier', 'N/A')}")
                else:
                    print(f"Customer Data (Raw): {customer_data}")
            else:
                print("No customer data found in output. Check Architect Flow mapping.")
                
        else:
            print("Flow execution completed but returned no output.")
            
    except Exception as e:
        print(f"Fatal error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Common Errors & Debugging

Error: 400 Bad Request - Invalid Flow Input

Cause: The input parameter name in your code does not match the Input Parameter name defined in the Architect Flow.

Fix:

  1. Open the Architect Flow in the Genesys Cloud UI.
  2. Go to the Inputs tab.
  3. Verify the exact name of the input parameter (e.g., phoneNumber vs phone_number vs inputPhone).
  4. Update the FlowExecutionInput.values dictionary key in your Python code to match exactly.

Error: 403 Forbidden - Insufficient Scopes

Cause: The OAuth client used does not have the flow:externalcontact:execute scope.

Fix:

  1. Go to Admin > Security > OAuth 2.0 Clients.
  2. Edit your client.
  3. Under Scopes, ensure flow:externalcontact:execute and flow:definition:read are checked.
  4. Save the client. Note that existing tokens may need to be refreshed.

Error: 504 Gateway Timeout - Flow Execution Timeout

Cause: The GetExternalContactAction is calling an external HTTP endpoint that is slow to respond, causing the flow execution to exceed the default timeout (usually 30 seconds for synchronous executions).

Fix:

  1. Optimize External Endpoint: Ensure your CRM/API endpoint responds within 5-10 seconds.
  2. Use Async Execution: If the lookup is slow, consider using the asynchronous execution API (POST /api/v2/architect/flows/{flowId}/executions with async: true if supported by your flow design, though standard GetExternalContactAction is typically synchronous within the flow).
  3. Add Logging: Add a “Log” action in Architect before and after the GetExternalContactAction to pinpoint where the delay occurs.

Error: Flow Output is Empty

Cause: The GetExternalContactAction succeeded, but the output mapping in Architect is incorrect.

Fix:

  1. In Architect, select the GetExternalContactAction.
  2. Check the Output tab.
  3. Ensure the response body from the HTTP call is correctly parsed and mapped to the Flow Output Parameters.
  4. If the HTTP response is JSON, ensure you are using the correct JSON path (e.g., $.data.customer) rather than just the raw body.

Official References