Design principles

Keep it simple: Build linear flows with clear decision points. Avoid complex branching. Use agents for intelligence: Agent nodes handle complex conversations. Give them specific tools and clear system prompts. Route early: Filter and route conversations at the beginning. Use Send Text + Decide pattern. Functions for data: Use custom functions to fetch, process, and store data. Keep business logic out of agents.

Common patterns

Basic routing flow Route users to specialized agents based on their first message:
  • Support agent: Help with issues, access user data
  • Sales agent: Product recommendations, order processing
  • Billing agent: Payment issues, subscription management
Data collection flow Use functions to fetch user profile, order history, subscription status, and personalize the greeting. Multi-step workflow Pattern: Collect user input → Process/validate → Agent interaction → Save results.

Agent design

Create focused agents for specific tasks:
support_agent = AgentNode(
    id="support_agent",
    system_prompt="You are a technical support specialist. Help users with account issues, bugs, and technical problems. Always search for existing tickets first.",
    webhooks=[
        FlowAgentWebhook(
            name="search_tickets",
            url="https://api.company.com/support/tickets/search",
            description="Search for user's existing support tickets"
        ),
        FlowAgentWebhook(
            name="create_ticket", 
            url="https://api.company.com/support/tickets",
            http_method="POST",
            description="Create a new support ticket"
        )
    ]
)
Design agents around the tools they need:
  • Customer service: User lookup, order status, refund processing
  • Sales: Product search, inventory check, order creation
  • Onboarding: Account setup, feature tours, tutorial scheduling

Function-first patterns

Start flows with functions to enrich data and make smart routing decisions. User verification pattern Check if user exists in your system, then route accordingly:
flow = (Flow(name="User Verification")
    .add_node(StartNode(id="start"))
    .add_node(FunctionNode(
        id="check_user",
        function_id="verify_user_by_phone",  # Use ID from kapso functions list
        save_response_to="user_status"
    ))
    .add_node(DecideNode(
        id="route_by_status",
        conditions=[
            Condition(label="registered", description="User exists in database"),
            Condition(label="new", description="New user, not in database")
        ],
        provider_model_name="claude-sonnet-4-20250514"
    ))
    .add_node(AgentNode(
        id="existing_user_agent",
        system_prompt="Welcome back! You're talking to {{user_status.name}}. Help with their account.",
        provider_model_name="claude-sonnet-4-20250514"
    ))
    .add_node(AgentNode(
        id="onboarding_agent", 
        system_prompt="Welcome! Help new users get started with account setup.",
        provider_model_name="claude-sonnet-4-20250514"
    ))
    
    .add_edge("start", "check_user")
    .add_edge("check_user", "route_by_status")
    .add_edge("route_by_status", "existing_user_agent", "registered")
    .add_edge("route_by_status", "onboarding_agent", "new")
)
Data enrichment pattern Load user context first, then personalize everything:
flow = (Flow(name="Personalized Support")
    .add_node(StartNode(id="start"))
    .add_node(FunctionNode(
        id="load_context",
        function_id="get_user_profile",  # Get ID with: kapso functions list
        save_response_to="profile"
    ))
    .add_node(SendTextNode(
        id="personalized_greeting",
        whatsapp_config_id="config",
        message=AIField(prompt="Create personalized greeting for {{profile.name}} with order history: {{profile.recent_orders}}"),
        provider_model_name="claude-sonnet-4-20250514"
    ))
    .add_node(WaitForResponseNode(id="wait"))
    .add_node(AgentNode(
        id="agent",
        system_prompt="Help {{profile.name}}. Recent orders: {{profile.recent_orders}}. Subscription: {{profile.plan}}",
        provider_model_name="claude-sonnet-4-20250514"
    ))
    
    .add_edge("start", "load_context")
    .add_edge("load_context", "personalized_greeting")
    .add_edge("personalized_greeting", "wait")
    .add_edge("wait", "agent", "response")
)
Input validation pattern Validate user input before processing:
flow = (Flow(name="Order Processing")
    .add_node(StartNode(id="start"))
    .add_node(SendTextNode(id="ask_order", message="What's your order number?"))
    .add_node(WaitForResponseNode(id="wait"))
    .add_node(FunctionNode(
        id="validate_order",
        function_id="check_order_exists",  # Your deployed function ID
        save_response_to="order_info"
    ))
    .add_node(DecideNode(
        id="check_validity",
        conditions=[
            Condition(label="valid", description="Order exists and is valid"),
            Condition(label="invalid", description="Order not found or invalid")
        ],
        provider_model_name="claude-sonnet-4-20250514"
    ))
    .add_node(AgentNode(
        id="process_order",
        system_prompt="Help with order {{order_info.number}}. Status: {{order_info.status}}",
        provider_model_name="claude-sonnet-4-20250514"
    ))
    .add_node(SendTextNode(
        id="order_not_found",
        message="Order not found. Please check the number and try again."
    ))
    
    .add_edge("start", "ask_order")
    .add_edge("ask_order", "wait")
    .add_edge("wait", "validate_order", "response")
    .add_edge("validate_order", "check_validity")
    .add_edge("check_validity", "process_order", "valid")
    .add_edge("check_validity", "order_not_found", "invalid")
)

Function usage

Functions handle data operations at different stages: Pre-flow setup: Fetch user context before conversation starts
get_user_context = FunctionNode(
    id="get_user_context",
    function_id="user_profile_loader",  # From: kapso functions list
    save_response_to="user_profile"
)
Mid-flow processing: Process user input or agent responses
validate_order = FunctionNode(
    id="validate_order", 
    function_id="order_validator",  # From: kapso functions list
    save_response_to="order_validation"
)
Post-flow actions: Save conversation results
save_lead = FunctionNode(
    id="save_lead",
    function_id="crm_lead_creator"  # From: kapso functions list
)