AGI CNAM Lookup Script
AGI CNAM Lookup Script
When inbound calls arrive from a SIP trunk, the caller ID number is usually present but the caller name is often blank. An AGI script can query an external CNAM database via HTTP, retrieve the caller's name, and set it on the channel before the call is answered.
Requirements
- PHP CLI installed (
php-cliorphp-cgi) - phpagi library installed in
/var/lib/asterisk/agi-bin/ - PHP
curlextension enabled - A CNAM lookup service account (e.g., OpenCNAM, CallerID.com, or a private provider)
res_agi.somodule loaded in Asterisk
The AGI Script (cnam-lookup.agi)
Place this in /var/lib/asterisk/agi-bin/ and make it executable (chmod +x).
#!/usr/bin/php -q
<?php
require_once('/var/lib/asterisk/agi-bin/phpagi-2.20/phpagi.php');
$agi = new AGI();
// CNAM provider credentials
$cnam_server = 'https://api.example.com/cnam';
$cnam_userid = 'your_user_id';
$cnam_secret = 'your_secret';
$cid_num = trim($agi->request['agi_callerid']);
$cid_name = trim($agi->request['agi_calleridname']);
// If we already have a name, nothing to do
if ($cid_name !== '' && $cid_name !== $cid_num) {
exit;
}
// --- Number normalization ---
// Strip leading +1 (12 digits like +12125551234)
if (strlen($cid_num) == 12 && substr($cid_num, 0, 2) === '+1') {
$cid_num = substr($cid_num, 2);
}
// Strip leading 1 (11-char string like 12125551234)
if (strlen($cid_num) == 11 && substr($cid_num, 0, 1) === '1') {
$cid_num = substr($cid_num, 1);
}
// Strip leading + (11-char string like +2125551234)
if (strlen($cid_num) == 11 && substr($cid_num, 0, 1) === '+') {
$cid_num = substr($cid_num, 1);
}
// --- Handle special cases ---
if (strcasecmp($cid_num, 'anonymous') === 0) {
$agi->set_callerid('"Anonymous" <Anonymous>');
exit;
}
if (strcasecmp($cid_num, 'restricted') === 0) {
exit; // Leave as-is
}
if (!is_numeric($cid_num)) {
$agi->set_callerid('"Unavailable" <>');
exit;
}
// Not a valid NANPA 10-digit number
if (strlen($cid_num) != 10 || $cid_num < 2010000000 || $cid_num > 9899999999) {
$agi->set_callerid('"Out of Area" <' . $cid_num . '>');
exit;
}
// --- CNAM HTTP lookup ---
$url = "$cnam_server?userid=$cnam_userid&secret=$cnam_secret&number=$cid_num";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$cid_name = trim(curl_exec($ch));
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// If lookup failed, let the call through without a name
if ($cid_name === '' || $http_code !== 200) {
exit;
}
$agi->set_callerid('"' . $cid_name . '" <' . $cid_num . '>');
?>
Dialplan Integration
[from-trunk]
; Run CNAM lookup before routing the call
exten => _X.,1,AGI(cnam-lookup.agi)
same => n,Goto(internal,${EXTEN},1)
How it works
- AGI (Asterisk Gateway Interface): AGI lets Asterisk hand control of a channel to an external script. The script communicates with Asterisk over stdin/stdout using a simple text protocol. The phpagi library wraps this protocol in PHP objects.
- Number normalization: Inbound caller IDs arrive in inconsistent formats:
+12125551234,12125551234,2125551234. The script strips prefixes to produce a consistent 10-digit NANPA number before querying the CNAM provider. - Fail-open design: If the HTTP lookup times out (2-second connect, 4-second total) or returns empty, the script exits without changing the caller ID. The call proceeds with whatever caller ID it had. This prevents a slow CNAM service from blocking inbound calls.
set_callerid(): Sets both the caller name and number in the format"Name" <Number>. This updatesCALLERID(name)andCALLERID(num)on the channel for the duration of the call.- Special caller IDs: Anonymous, restricted, non-numeric, and out-of-range numbers are handled before the HTTP lookup to avoid wasting API calls on numbers that won't return useful results.
Tips
- Set a strict
CURLOPT_TIMEOUT(2-4 seconds). CNAM lookups happen in the call setup path: a slow response delays ringing for the callee. - Consider adding a local cache (AstDB or MySQL) to store lookups and avoid repeated queries for the same number. Check the cache before the HTTP request.
- Make the script executable:
chmod 755 /var/lib/asterisk/agi-bin/cnam-lookup.agiand owned by the Asterisk user. - Test from the CLI:
channel originate Local/2125551234@from-trunk application Playback hello-worldto trigger the AGI and watch the caller ID update. - For high-volume systems, consider
EAGIorFastAGI(TCP-based AGI) to avoid the overhead of spawning a PHP process per call. - Log lookup results with
$agi->verbose("CNAM: $cid_num -> $cid_name"): visible in the Asterisk CLI at verbosity 1+.
User Notes
No notes yet. Be the first to contribute a tip or example.
Contribute a note
Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.