You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在IVR中保持会话?基于Twilio Webhook与PHP的技术求助

Hey there! Great progress on your IVR app so far—collecting Customer ID/PIN and sharing balances is a solid foundation. To let users skip re-authenticating for subsequent actions (PIN change, transfers) until the call ends, here's a practical approach using Twilio Webhooks and PHP, focused on session persistence tied to the Twilio Call SID:


Core Concepts to Make This Work

Since Twilio sends stateless HTTP requests for each IVR interaction, we need a way to track the user's authenticated state across those requests. Here's how to do it:

  • Use the Call SID (Twilio sends this in every Webhook request as CallSid) as a unique identifier for the call session.
  • Store authenticated user data (Customer ID, verified status) in a server-side store like Redis or your database—don't rely on PHP sessions, since Twilio's requests don't carry cookies.
  • Build a simple state machine to track where the user is in the IVR flow (e.g., "authenticated, choosing action", "in PIN change flow") so you can route each request correctly.

Step-by-Step Implementation

First, make sure you have the Twilio PHP SDK installed via Composer:

composer require twilio/sdk

1. Initialize Session Storage & Twilio Client

We'll use Redis for fast, temporary session storage (replace with your database if needed):

<?php
require_once 'vendor/autoload.php';
use Twilio\TwiML\VoiceResponse;

// Get critical Twilio request parameters
$callSid = $_POST['CallSid'] ?? '';
$userInput = $_POST['Digits'] ?? '';

// Connect to Redis (adjust host/port as needed)
$redis = new Redis();
$redis->connect('localhost', 6379);
$sessionKey = "ivr_call:$callSid";

// Fetch existing session data (if any)
$sessionData = json_decode($redis->get($sessionKey), true) ?? [];
$isAuthenticated = isset($sessionData['customer_id']) && $sessionData['is_verified'] === true;

// Helper functions (replace with your actual business logic)
function verifyCustomerPin(string $customerId, string $pin): bool {
    // Query your DB to check if PIN matches the customer ID
    return true; // Replace with real validation
}

function getCustomerBalance(string $customerId): string {
    // Fetch balance from your DB
    return "1234.56"; // Replace with real balance
}

function updateCustomerPin(string $customerId, string $newPin): bool {
    // Update PIN in your DB
    return true; // Replace with real update logic
}
?>

2. Handle Unauthenticated Users (ID/PIN Collection)

If the user hasn't logged in yet, guide them through entering their credentials:

<?php
if (!$isAuthenticated) {
    $response = new VoiceResponse();
    
    // Step 1: Collect Customer ID
    if (empty($userInput)) {
        $gather = $response->gather([
            'numDigits' => 8,
            'action' => 'ivr.php',
            'method' => 'POST'
        ]);
        $gather->say('Please enter your customer ID, followed by the pound sign.');
        echo $response;
        exit;
    }
    
    // Step 2: Collect PIN after getting Customer ID
    if (!isset($sessionData['customer_id'])) {
        $sessionData['customer_id'] = $userInput;
        $redis->set($sessionKey, json_encode($sessionData));
        
        $gather = $response->gather([
            'numDigits' => 4,
            'action' => 'ivr.php',
            'method' => 'POST'
        ]);
        $gather->say('Please enter your PIN, followed by the pound sign.');
        echo $response;
        exit;
    }
    
    // Step 3: Validate PIN and mark as authenticated
    $pinIsValid = verifyCustomerPin($sessionData['customer_id'], $userInput);
    if ($pinIsValid) {
        $sessionData['is_verified'] = true;
        $redis->set($sessionKey, json_encode($sessionData));
        
        // Announce balance and present action menu
        $balance = getCustomerBalance($sessionData['customer_id']);
        $response->say("Your account balance is {$balance} dollars.");
        $gather = $response->gather([
            'numDigits' => 1,
            'action' => 'ivr.php',
            'method' => 'POST'
        ]);
        $gather->say('Please select an option: Press 1 to change your PIN, press 2 to make a transfer, press 3 to end the call.');
        echo $response;
        exit;
    } else {
        // Invalid PIN, retry
        $gather = $response->gather([
            'numDigits' => 4,
            'action' => 'ivr.php',
            'method' => 'POST'
        ]);
        $gather->say('Invalid PIN. Please try again.');
        echo $response;
        exit;
    }
}
?>

3. Handle Authenticated Users (Action Menu & Flows)

Once the user is authenticated, let them navigate between actions without re-logging in:

<?php
// User is authenticated: handle their menu choice
$response = new VoiceResponse();

// Handle action selection
if (!empty($userInput)) {
    switch ($userInput) {
        case '1':
            // Start PIN change flow
            $gather = $response->gather([
                'numDigits' => 4,
                'action' => 'ivr.php?action=update_pin',
                'method' => 'POST'
            ]);
            $gather->say('Please enter your new PIN, followed by the pound sign.');
            echo $response;
            exit;
        case '2':
            // Start transfer flow (example first step: collect recipient ID)
            $gather = $response->gather([
                'numDigits' => 8,
                'action' => 'ivr.php?action=transfer_recipient',
                'method' => 'POST'
            ]);
            $gather->say('Please enter the recipient\'s customer ID, followed by the pound sign.');
            echo $response;
            exit;
        case '3':
            // End call and clean up session
            $response->say('Thank you for using our service. Goodbye.');
            $response->hangup();
            $redis->del($sessionKey);
            echo $response;
            exit;
        default:
            // Invalid input, re-prompt menu
            $gather = $response->gather([
                'numDigits' => 1,
                'action' => 'ivr.php',
                'method' => 'POST'
            ]);
            $gather->say('Invalid selection. Please try again: Press 1 to change your PIN, press 2 to make a transfer, press 3 to end the call.');
            echo $response;
            exit;
    }
}

// If no input yet, re-show the menu
$gather = $response->gather([
    'numDigits' => 1,
    'action' => 'ivr.php',
    'method' => 'POST'
]);
$gather->say('Please select an option: Press 1 to change your PIN, press 2 to make a transfer, press 3 to end the call.');
echo $response;
?>

4. Handle Specific Actions (e.g., PIN Update)

Add handlers for specific flows like PIN updates:

<?php
// Handle PIN update completion
if (isset($_GET['action']) && $_GET['action'] === 'update_pin') {
    $newPin = $userInput;
    $updateSuccess = updateCustomerPin($sessionData['customer_id'], $newPin);
    
    $response = new VoiceResponse();
    if ($updateSuccess) {
        $response->say('Your PIN has been updated successfully.');
    } else {
        $response->say('There was an error updating your PIN. Please try again later.');
    }
    
    // Return to main menu
    $gather = $response->gather([
        'numDigits' => 1,
        'action' => 'ivr.php',
        'method' => 'POST'
    ]);
    $gather->say('Please select an option: Press 1 to change your PIN, press 2 to make a transfer, press 3 to end the call.');
    echo $response;
    exit;
}

// Add more action handlers (like transfer steps) here
?>

Key Notes for Production

  • Session Expiry: Set a TTL on your Redis keys (e.g., $redis->expire($sessionKey, 1800) for 30 minutes) to clean up stale sessions.
  • Error Handling: Add validation for invalid inputs (e.g., non-digit entries) and edge cases like empty Customer IDs.
  • Security: Never store plaintext PINs—always hash them in your database before storing.
  • Logging: Log Call SIDs and user actions for debugging and compliance.

内容的提问来源于stack exchange,提问作者HayWhy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:23:30