We typically like forcing Caller ID to get set by whatever is configured for the extension but have some downstream systems where we wish to pass customer overriding Caller ID through. On those systems we set the desired Caller ID as a custom SIP / IAX header (X-CallerID) on the down stream system and then use that when placing the outgoing call on the upstream host.
NB: We prefer configuring trunks as standard extensions as it makes configuring failover routing flexible. We for example have our Microsoft Teams tenant connected to our Asterisk box and subsequently configure follow me on the main extension to ring both the standard VoIP handset as well as Teams when dialled.
On the downstream system (FreePBX 16 with Asterisk 18 but has worked like this since Asterisk 1.6):
Each extension has a DID from various ranges where the last 4 digits of the DID is the extension number. We also have Microsoft Teams integrated as well but that passes the Caller ID as the full DID, for example:
3055 → 0115553055
0108 → 0116660108
exten => s,1,ExecIf($[${REGEX("^30[0-9][0-9]$" ${CALLERID(num)})}]?Set(CALLERID(num)=011555${CALLERID(num)}))
exten => s,n,ExecIf($[${REGEX("^0[12][0-9][0-9]$" ${CALLERID(num)})}]?Set(CALLERID(num)=011666${CALLERID(num)}))
exten => s,n,GotoIf($[${REGEX("^[\+]271155530[0-9][0-9]$" ${CALLERIDNUMINTERNAL})}]?teams)
exten => s,n,GotoIf($[${REGEX("^[\+]27116660[12][0-9][0-9]$" ${CALLERIDNUMINTERNAL})}]?teams)
exten => s,n,Goto(tech)
exten => s,n(teams),Set(AMPUSERCID=${CALLERIDNUMINTERNAL:8})
exten => s,n,Set(AMPUSERCIDNAME=${CALLERIDNAMEINTERNAL})
exten => s,n(tech),Set(TECH=${CUT(custom,/,1)})
exten => s,n,GotoIf($["${TECH}" = "SIP"]?sip)
exten => s,n,GotoIf($["${TECH}" = "PJSIP"]?pjsip)
exten => s,n,GotoIf($["${TECH}" = "IAX2"]?iax2)
exten => s,n,Goto(finish)
exten => s,n(sip),SIPAddHeader(X-CallerID:${CALLERID(name)} <${CALLERID(num)}>)
exten => s,n,Goto(finish)
exten => s,n(pjsip),Set(HASH(__SIPHEADERS,X-CallerID)=${CALLERID(name)} <${CALLERID(num)}>)
exten => s,n,Goto(finish)
exten => s,n(iax2),Set(IAXVAR(X-CallerID)=${CALLERID(name)} <${CALLERID(num)}>)
exten => s,n(finish),MacroExit
The upstream system then checks for these headers and sets the Caller ID as required:
exten => s,1,Set(TECH=${CUT(CHANNEL,/,1)})
exten => s,n,GotoIf($["${TECH}" = "SIP"]?sip)
exten => s,n,GotoIf($["${TECH}" = "PJSIP"]?pjsip)
exten => s,n,GotoIf($["${TECH}" = "IAX2"]?iax2)
exten => s,n,Goto(next)
exten => s,n(sip),ExecIf($[ ${LEN(${SIP_HEADER(X-CallerID)})} > 0 ]?Set(CALLERID(all)=${SIP_HEADER(X-CallerID)}))
exten => s,n,SIPRemoveHeader(X-CallerID:)
exten => s,n,Goto(next)
exten => s,n(pjsip),ExecIf($[ ${LEN(${PJSIP_HEADER(read,X-CallerID)})} > 0 ]?Set(CALLERID(all)=${PJSIP_HEADER(read,X-CallerID)}))
exten => s,n,Set(PJSIP_HEADER(remove,X-CallerID)=)
exten => s,n,Goto(next)
exten => s,n(iax2),ExecIf($[ ${LEN(${IAXVAR(X-CallerID)})} > 0 ]?Set(CALLERID(all)=${IAXVAR(X-CallerID)}))
exten => s,n,Set(IAXVAR(X-CallerID)=)
exten => s,n(next),ExecIf($[${REGEX("<0" ${CALLERID(all)})}]?Set(CALLERID(all)=${STRREPLACE(CALLERID(all),<0,<+27)}))
Use it or lose it, hope it helps…