Asterisk IP Telephony Integration on Website
Asterisk is an open-source IP PBX platform, the de-facto standard for corporate telephony. Unlike cloud providers (Mango, Zadarma), Asterisk is deployed on your own server — full control over data, routing, and call costs.
Integration Architecture
Browser (WebRTC/SIP.js) ←→ Asterisk (Kamailio/nginx + WebSocket)
↓
AMI (Asterisk Manager Interface)
↓
Backend API (PHP/Go/Node)
↓
Database + Redis (events)
Asterisk Manager Interface (AMI) — TCP connection to port 5038, through which backend receives real-time events (incoming call, answer, completion) and sends commands (originate, hangup).
Connecting to AMI
// Low-level TCP connection to AMI
$socket = fsockopen(env('ASTERISK_HOST'), 5038, $errno, $errstr, 5);
fwrite($socket, "Action: Login\r\nUsername: api_user\r\nSecret: api_secret\r\n\r\n");
// Receiving events (polling in background process)
while (!feof($socket)) {
$line = fgets($socket);
// Parse events: Event: Newchannel, Event: Hangup, etc.
}
In practice, it's more convenient to use a library: optika-si/phpagi or pami/pami (PAMI — PHP Asterisk Manager Interface).
PAMI — Working with Events
// composer require marcelog/pami
$client = new \PAMI\Client\Impl\ClientImpl([
'host' => env('ASTERISK_HOST'),
'port' => 5038,
'username' => 'api_user',
'secret' => 'api_secret',
'connect_timeout' => 10
]);
$client->open();
// Listen for incoming calls
$client->registerEventListener(function(\PAMI\Message\Event\EventMessage $event) {
if ($event->getName() === 'Newchannel') {
$callerNum = $event->getKey('CallerIDNum');
$channel = $event->getKey('Channel');
// Find customer, notify manager via Redis pub/sub
Redis::publish('incoming_call', json_encode([
'caller' => $callerNum,
'channel' => $channel,
'timestamp' => now()->toIso8601String()
]));
}
if ($event->getName() === 'Hangup') {
$duration = $event->getKey('Duration');
// Save call to database
}
});
while (true) {
$client->process();
usleep(100000); // 100ms
}
This process runs as a supervisor daemon, always maintaining connection with AMI.
Click-to-Call via Originate
// Initiate call: connect agent with customer
$client->send(new \PAMI\Message\Action\OriginateAction(
"SIP/{$agentExtension}", // agent's channel
"exten,{$customerPhone},default", // where to call after agent answers
[
'Timeout' => 30000,
'CallerID' => '"My Store" <80001234567>',
'Variable' => "ORDER_ID={$orderId}",
'Async' => true
]
));
Asterisk first calls the agent, then after answer connects them to the customer — this is more convenient for the agent than dialing the number themselves.
ARI (Asterisk REST Interface)
Modern approach — ARI (Asterisk REST Interface) via WebSocket. Allows building complex call handling scenarios as code:
// Node.js + ari-client
const ari = require('ari-client');
ari.connect('http://asterisk:8088', 'user', 'secret', function(err, client) {
client.on('StasisStart', function(event, channel) {
const callerNum = channel.caller.number;
// Find customer, play personalized greeting
channel.play({media: `sound:welcome-${customerId}`});
});
client.start('my-stasis-app');
});
WebRTC via Asterisk + Nginx
For browser calls Asterisk must work with WebSocket TLS. Configuration:
; /etc/asterisk/http.conf
[general]
enabled=yes
tlsenable=yes
tlsbindaddr=0.0.0.0:8089
tlscertfile=/etc/ssl/asterisk/asterisk.crt
tlsprivatekey=/etc/ssl/asterisk/asterisk.key
; /etc/asterisk/pjsip.conf
[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:8089
Call Recording
Asterisk records calls with MixMonitor. Files are stored in /var/spool/asterisk/monitor/. A script moves them to S3 and updates call_records.recording_url.
Development timeline: 3–5 weeks for full integration: deploying Asterisk, AMI daemon, click-to-call, WebRTC in browser and call history.







