Adding Stir/Shaken Identity Header to Outbound Calls Using Tiltx
Preamble
If you have a requirement to add a Stir/Shaken attestation to calls leaving a FreePBX/PBXact system and you have an account with Tiltx, you can use their callshaper API to add an S/S identity header to outbound calls. There are a few third party services that will assist with generating S/S attestations for SIP calls, the Tiltx callshaper API does not rely on an SBC or proxy between the PBX and the provider.
This information is current as of 2022-05-20. Subsequent developments in FreePBX, Asterisk or in Tiltx APIs may render it obsolete. Consult reference for additional info https://help.smartcarrier.io/portal/en/kb/articles/tiltx-call-shaper-module
Prerequisites
FreePBX/PBXact version 15/16 and Asterisk version 18/19. This dialplan requires support for the Asterisk dialplan function 'JSON_DECODE'Â
Account with Tiltx configured for Stir/Shaken and and API key from Tiltx
PBX Config
Add the following code to the PBX in the file /etc/asterisk/extensions_custom.conf
[macro-dialout-trunk-predial-hook]
; history  2022-05-20 first commit
;Â Â Â Â Â Â Â Â Â Â 2022-07-08 Update for forwarded calls and check for valid API return value
exten => s,1,Noop(Entering user defined context macro-dialout-trunk-predial-hook in extensions_custom.conf)
Â
; setup curlopts and curl API call with call params
exten => s,n,Set(CURLOPT(httptimeout)=10)Â Â Â ; give up if we don't get a reply from API in 10s
exten => s,n,Set(CURLOPT(httpheader)=x-api-key: Tiltx-API-KEY)Â Â Â Â Â Â Â Â ; substitute your actual Tiltx API key
exten => s,n,Set(CURLOPT(httpheader)=Content-Type: application/json)
exten => s,n,Set(response=${CURL(https://api.shaper.tiltx.com/Calls/shaper?ToNumber=${OUTNUM}&FromNumber=${CALLERID(num)})})
Â
; check if we get a header back from Tiltx and skip to end if not
exten => s,n,GotoIf($["${JSON_DECODE(response,Identity)}"=""]?finish)
exten => s,n,Set(IdentityHeader=${JSON_DECODE(response,Identity)})Â Â Â Â Â Â Â Â Â Â Â ; JSON_DECODE requires recent Asterisk versions 16/18/19
exten => s,n,GoSub(func-set-sipheader,s,1(Identity,${IdentityHeader}))
Â
exten => s,n(finish),MacroExit()
Â
; end macro-dialout-trunk-predial-hook |
Substitute your Actual API key where indicated, save the file, and reload the dialplan.
Example outbound call
From the Asterisk Console, make an outbound call. If the dialplan is working correctly, there will be a section that looks like this:
-- Executing [s@macro-dialout-trunk-predial-hook:1] NoOp("PJSIP/7002-00000032", "Entering user defined context macro-dialout-trunk-predial-hook in extensions_custom.conf") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:2] Set("PJSIP/7002-00000032", "CURLOPT(httptimeout)=10") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:3] Set("PJSIP/7002-00000032", "CURLOPT(httpheader)=x-api-key: QQaUA3bSXa1ncE8vol0sV6bHIyEXSdfb2staWyQp") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:4] Set("PJSIP/7002-00000032", "CURLOPT(httpheader)=Content-Type: application/json") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:5] Set("PJSIP/7002-00000032", "response={"RequestGuid":"c19636d3-1c96-4efe-8112-45b8737fbeda","AccountGuid":"c88a4b90-86c5-4c35-8f53-7c860d3866bb","ToNumber":"<<redacted>>","FromNumber":"<<redacted>>","IPAddress":"<<redacted>>","Country":"US","IsDNC":"false","IsDIDManager":"false","IsDisconnected":"false","CallerIDToUse":null,"Identity":"long_Identity_string_shortened_for_clarity","CAID":"c19636d3-1c96-4efe-8112-45b8737fbeda","AttestationLevel":"B","SHAKEN_Server":"ca.shaken.tiltx.internal","IsInternallyFlagged":"false","RoutingNumber":"17159721948","LERGInformation":{"RequestGuid":"f188ce8b-a79b-4027-a16d-f3525c586767","NPANXX":1715972,"Block":"1","USState":"WI","AssignedTo":"BANDWIDTH.COM CLEC, LLC - WI","AssignedTo_OCN":"007F","Type":"CLEC","Ilec":"WISCONSIN BELL INC","Ilec_OCN":"9327","Lata":"350","RequestedAt":"2022-06-17T19:15:54.6658375Z","ElapsedMilliseconds":0},"DIDLERG":{"RequestGuid":"13ab720a-8258-440e-a3fe-cd7f8fe4b4c3","NPANXX":1920886,"Block":"8","USState":"WI","AssignedTo":"TDS METROCOM, INC. - WI","AssignedTo_OCN":"7804","Type":"CLEC","Ilec":"WISCONSIN BELL INC","Ilec_OCN":"9327","Lata":"350","RequestedAt":"2022-06-17T19:15:54.6776668Z","ElapsedMilliseconds":0},"DNCInformation":null,"TILTXID":"c19636d3-1c96-4efe-8112-45b8737fbeda","ServiceData":null,"RequestedAt":"2022-06-17T19:15:54.2442607Z","CompletedAt":"2022-06-17T19:15:54.8671704Z","ProcessingTime":"622.9097","ReturnCode":200,"ReturnStatus":"Attestation B assigned - Number not Found"}") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:6] Set("PJSIP/7002-00000032", "IdentityHeader=long_Identity_string_shortened_for_clarity") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:7] Gosub("PJSIP/7002-00000032", "func-set-sipheader,s,1(Identity,long_Identity_string_shortened_for_clarity)") in new stack
-- Executing [s@func-set-sipheader:1] NoOp("PJSIP/7002-00000032", "Sip Add Header function called. Adding Identity = long_Identity_string_shortened_for_clarity") in new stack
-- Executing [s@func-set-sipheader:2] Set("PJSIP/7002-00000032", "HASH(__SIPHEADERS,Identity)=long_Identity_string_shortened_for_clarity") in new stack
-- Executing [s@func-set-sipheader:3] Return("PJSIP/7002-00000032", "") in new stack
-- Executing [s@macro-dialout-trunk-predial-hook:8] MacroExit("PJSIP/7002- |