AGI CNAM Lookup Script

Integrations Asterisk 18+ -- Last reviewed 2026-08-22 agi cnam php integrations callerid Found this useful? Upvote it. ×

AGI CNAM Lookup Script

When inbound calls arrive from a SIPSession Initiation Protocol, the standard signaling protocol used to set up, manage, and tear down VoIP calls between Asterisk and phones or carriers. trunkA connection between Asterisk and another PBX or an ITSP/carrier, used to send and receive external calls., the caller IDThe calling party number (and optionally name) presented on an outbound call, set from the endpoint or manipulated in the dialplan. number is usually present but the caller name is often blank. An AGIAsterisk Gateway Interface. Lets external scripts (PHP, Python, and others) control a call by communicating with Asterisk over stdin/stdout or TCP. script can query an external CNAM database via HTTP, retrieve the caller's name, and set it on the channelA single call leg passing through Asterisk. Channels represent connections to endpoints and are what dialplan applications act on. before the call is answered.

Requirements

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 characters 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

  1. 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.
  2. 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.
  3. 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.
  4. set_callerid(): Sets both the caller name and number in the format "Name" <Number>. This updates CALLERID(name) and CALLERID(num) on the channel for the duration of the call.
  5. 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

User Notes

Know a tip or gotcha for this topic? Share it below and help others.

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.

Moderated before publishing. Email never shown.
Related Snippets