phalanx/twilio

Twilio integration for Phalanx — async SMS, voice, TwiML, and Conversation Relay

Maintainers

Package info

github.com/havy-tech/phalanx-twilio

pkg:composer/phalanx/twilio

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.2.0 2026-03-27 13:10 UTC

This package is auto-updated.

Last update: 2026-03-27 13:53:29 UTC


README

Phalanx

phalanx/twilio

Async Twilio integration for Phalanx -- SMS, voice calls, webhook validation, TwiML building, and Conversation Relay protocol support. Built on ReactPHP for non-blocking I/O.

Table of Contents

Installation

composer require phalanx/twilio

Requires PHP 8.4+, phalanx/core, react/http.

Quick Start

<?php

use Phalanx\Twilio\TwilioServiceBundle;

$app = Application::starting([
    'twilio_account_sid' => getenv('TWILIO_ACCOUNT_SID'),
    'twilio_auth_token' => getenv('TWILIO_AUTH_TOKEN'),
])
    ->providers(new TwilioServiceBundle())
    ->compile();

$scope = $app->createScope();
$twilio = $scope->service(TwilioRest::class);

$twilio->sendSms(
    to: '+15551234567',
    from: '+15559876543',
    body: 'Your order has shipped!',
);

Configuration

TwilioServiceBundle registers TwilioRest and TwilioWebhook as singletons. Pass credentials through the application context:

<?php

use Phalanx\Twilio\TwilioConfig;

$config = new TwilioConfig(
    accountSid: 'ACxxxxxxxx',
    authToken: 'your-auth-token',
    apiBase: 'https://api.twilio.com/2010-04-01', // default
);

SMS

<?php

$result = $twilio->sendSms(
    to: '+15551234567',
    from: '+15559876543',
    body: 'Your verification code is 847291',
);

// $result contains the Twilio API response as an associative array
echo $result['sid']; // Message SID

Voice Calls

<?php

$result = $twilio->createCall(
    to: '+15551234567',
    from: '+15559876543',
    url: 'https://your-app.com/voice/welcome',
    statusCallback: 'https://your-app.com/voice/status', // optional
);

The statusCallback receives events for initiated, ringing, answered, and completed.

TwiML

Build TwiML responses with a fluent API:

<?php

use Phalanx\Twilio\TwiML;

$response = TwiML::response()
    ->say('Welcome to Acme Support.', voice: 'Polly.Amy')
    ->pause(1)
    ->say('Please hold while we connect you.')
    ->build();

// Returns: <?xml version="1.0" encoding="UTF-8"?><Response><Say voice="Polly.Amy">Welcome...</Say>...</Response>

Conversation Relay

Connect a Twilio voice call to a real-time AI agent over WebSocket:

<?php

$response = TwiML::response()
    ->conversationRelay(
        url: 'wss://your-app.com/ws/voice-agent',
        welcomeGreeting: 'Hello! How can I help you today?',
        ttsProvider: 'Amazon',
        transcriptionProvider: 'Deepgram',
        voice: 'Polly.Amy',
        language: 'en-US',
    )
    ->build();

Parse incoming Conversation Relay messages:

<?php

use Phalanx\Twilio\ConversationRelay\CrProtocol;
use Phalanx\Twilio\ConversationRelay\CrMessage;

// Inside a WebSocket handler
$msg = CrMessage::fromJson($rawJson);

if ($msg->type === 'prompt') {
    // User spoke -- send to AI agent, stream response back
    $conn->send(CrProtocol::text('Let me check that for you...', last: false));
    $conn->send(CrProtocol::text(' I found the answer.', last: true));
}

// Other protocol messages
CrProtocol::endSession(handoffData: '{"reason":"transfer"}');
CrProtocol::sendDigits('1234#');
CrProtocol::play('https://cdn.example.com/hold-music.mp3');
CrProtocol::language('es-ES', transcriptionLanguage: 'es-ES');

Webhook Validation

Validate incoming Twilio webhooks using HMAC-SHA1 signature verification:

<?php

use Phalanx\Twilio\TwilioWebhook;

$webhook = $scope->service(TwilioWebhook::class);

$isValid = $webhook->validate($request); // PSR-7 ServerRequestInterface

if (!$isValid) {
    return new Response(403, [], 'Invalid signature');
}

When behind a reverse proxy, pass base_url through the application context so the signature computation uses the public URL:

<?php

$app = Application::starting([
    'twilio_account_sid' => getenv('TWILIO_ACCOUNT_SID'),
    'twilio_auth_token' => getenv('TWILIO_AUTH_TOKEN'),
    'base_url' => 'https://your-app.com',
]);

REST Client

TwilioRest exposes get() and post() for any Twilio API endpoint:

<?php

// Fetch call details
$call = $twilio->get("/Accounts/{$sid}/Calls/{$callSid}.json");

// Any POST endpoint
$result = $twilio->post("/Accounts/{$sid}/Messages.json", [
    'To' => '+15551234567',
    'From' => '+15559876543',
    'Body' => 'Custom message',
]);

All HTTP calls are non-blocking via ReactPHP. Errors throw TwilioApiException with the HTTP status code and response body.