Include SIP Trunk headers into CDR

Hi everyone. I’m attempting to save two headers that are sent from Twilio’s SIP trunk to our CDR.


Incoming Route
[from-pstn-custom] exten => _.,1,Set(CDR(twilio_call_sid)=${SIP_HEADER(X-Twilio-CallSid)}) exten => h,1,Set(CDR(twilio_recording_sid)=${SIP_HEADER(X-Twilio-RecordingSid)})

Outgoing Route
[from-internal-custom] exten => _.,1,Set(CDR(twilio_call_sid)=${SIP_HEADER(X-Twilio-CallSid)}) exten => h,1,Set(CDR(twilio_recording_sid)=${SIP_HEADER(X-Twilio-RecordingSid)})

The columns do exist in the database. The only route that kind of works is the incoming route. It will only save the ‘X-Twilio-CallSid’ header which is probably because it is sent with the initial request. I’m not able to save the ‘X-Twilio-RecordingSid’ header anywhere.

I’m so confused and I’ve spent way too much time trying to figure this out so I had to ask!

I’m running Asterisk 13.6.0 & FreePBX 13.0.67.

Please help! Thanks!

Bump. I need to be able to log the headers sent between calls. Is CDR the right choice? This is driving me NUTS!

Modifying the FreePBX database is not recommended from the outset, so it’s doesn’t surprise me that you haven’t gotten a lot of support on this.

There are other databases for this information, including the real-time database in Asterisk and your own SIP_Headers tables in a MySQL database (Asterisk being the obvious choice).

I’m usually pretty good at figuring the “Why” and frankly, this request has me stumped. Why do you think you need to save the SIP headers? With a simple dial-plan change, you can get them into the /full log using a NoOP() and not have to save them for posterity. Explain why you want this stuff and maybe someone can come up with a simple, effective way to help you out.

Your dialplan is messed up…

Incoming Route

exten => _.,1,Set(CDR(twilio_call_sid)=${SIP_HEADER(X-Twilio-CallSid)})
exten => _.,n,Set(CDR(twilio_recording_sid)=${SIP_HEADER(X-Twilio-RecordingSid)})

Outgoing Route

exten => s,1,Set(CDR(twilio_call_sid)=${SIP_HEADER(X-Twilio-CallSid)})
exten => s,n,Set(CDR(twilio_recording_sid)=${SIP_HEADER(X-Twilio-RecordingSid)})

I’m trying to figure out where I can save the headers sent with the final BYE 200 OK response between my freepbx box and Twilio’s SIP trunking service. So whenever a call hangs up on any Twilio trunked call (in and out), it logs all the headers in CDR for later use.

An example is I allow Twilio to store and manage call recordings. X-Twilio-RecordingSid allows me to construct a url for an mp3 audio stream of that recording. I can use that URL on our custom admin pages. I’ve also considered adding headers to SIP requests with our corporate firewall for logging.

Tell me something I don’t know…

My goal was to “hook” into the hangup response for all phone calls in and out of our freepbx. I figured it was *-custom and I was just missing it.

Both a little *-custom and perhaps:-

you will see that the userfield and perhaps the peeraccount might work for you , but with a little thought you can “alter” the asteriskcdr table cdr to add what you want ion your custom dialplan and so insert as appropriate.

It is unlikely that FreePBX would remove that “altered” state on an “update” cos it would be hard to do on a working system. But you should add such fields to you [aliases] in /etc/asterisk/cdr_mysql.conf so you can for example

edit: Never mind all covered already.

Use a hangup handler:

exten =>  _.,1,Set(CHANNEL(hangup_handler_push)=allison-hangup,s,1);

exten => s,1,Set(CHANNEL(hangup_handler_push)=allison-hangup,s,1

exten => s,1,Set(CDR(twilio_call_sid)=${SIP_HEADER(X-Twilio-CallSid)})
exten => s,n,Set(CDR(twilio_recording_sid)=${SIP_HEADER(X-Twilio-RecordingSid)})

Thank you so much for the response.


No matter what I did, I could not Noop the X-Twilio-CallSid header for outgoing calls. I decided to try and Noop the User-Agent and found that it was set as the SIP phone!?

So, what I found was that that immediately after the hangup handler runs, the final request takes place between Twilio and Freepbx.

[2016-04-12 17:29:15] VERBOSE[13585][C-0000031f] pbx.c: Executing [[email protected]:36] Return("SIP/9001-00000bad", "") in new stack [2016-04-12 17:29:15] VERBOSE[13585][C-0000031f] app_stack.c: Spawn extension (restrictedroute-c4ca4238a0b923820dcc509a6f75849b, h, 1) exited non-zero on 'SIP/9001-00000bad' [2016-04-12 17:29:15] VERBOSE[13585][C-0000031f] app_stack.c: SIP/9001-00000bad Internal Gosub(outbound-hangup-data,s,1) complete GOSUB_RETVAL=

Immediately after that runs, I receive this final request from Twilio’s server:

[2016-04-12 17:29:15] VERBOSE[1734] chan_sip.c: <--- SIP read from UDP: ---> SIP/2.0 200 OK CSeq: 104 BYE Call-ID: [email protected]:xx From: "Name" <sip:[email protected]:xx>;tag=as38eed54f To: <sip:[email protected]>;tag=01671807_6772d868_b63dada7-da54-4837-84a2-92dbbf0d7358 Via: SIP/2.0/UDP xx.xx.xx.195:xx;received=xx.xx.xx.195;branch=z9hG4bK77a5a0c7;rport=XXXX Server: Twilio X-Twilio-RecordingSid: REc6a1cacc4991b************** X-Twilio-RecordingDuration: 5 X-Twilio-CallSid: CA83b4f9053cf9e54409********* Content-Length: 0

As you can see, those are the values I need to save. How can I save those!? Also, can I save values into CDR after the channel has closed?


I’m in the exact same boat, trying to get the CallSid from the X-Header on an outbound Twilio SIP trunk call in Asterisk. Did you ever get a solution? Twilio support said I should ask “Asterisk”. Heh.

I too, need a solution for this if anyone can help out.


It seems to me that we’ve worked out that Twilio doesn’t provide DID information on their “single user” connections. If there’s some other need you have, a SIP trace would be the first place to check, and once you’ve identified the part you want, we should be able to advise you.

Here is the information from the TCPDUMP.

Call-ID: [email protected]
From: sip:[email protected];user=phone;tag=as0d28a7c7
To: sip:[email protected];isup-oli=62;tag=31902782_6772d868_d1e1a574-ec31-4d25-b3db-17fa426f143e
Via: SIP/2.0/UDP;received=;branch=z9hG4bK1b18c01e;rport=5070
Server: Twilio
X-Twilio-RecordingSid: RE392895aee90507bbf9c0f30xxx202037
X-Twilio-RecordingDuration: 22
X-Twilio-CallSid: CA8dc1ddb6f75749942cb2xxx1884e340e

Trying to catch the X-Twillio-CallSid and X-Twillio-RecordingSID

Once you’ve “caught” them, what are you planning on doing with them?

There is an accountcode field that you can “divert” for this using a custom incoming context. You may (although I really recommend against it) add a couple of fields to the asteriskcdrdb/cdr table. You could also add a new “twilio” table that extends the CDR functionality by connecting the records by (for example) start date and time. Both of these likewise require custom context code.

I don’t think there’s anything from the GUI that’s going to help you, though. This is all “custom code” territory. If you have a budget, check with the Sangoma guys and see what they think,

We have added the fields the the CDR table already. Using the dial plan:

exten => _.,1,Set(CDR(twilio_call_sid)=${SIP_HEADER(X-Twilio-CallSid)})

I can store the X-Twilio-CallSID on INCOMING calls, but I can not get this to work with outbound calls at all.

Here is some additional information. We have a hangup handler set to execute on the conclusion of the calls. It is the same hand up handler for inbound and outbound calls. The handler is set to send debug information containing the X-Twilio-SID and X-Twilio-Recording-ID

There are three cases:

  1. We make an outbound call. The debug information does not show either value
  2. An inbound call and the called (internal) party hangs up. Debug shows the SID only.
  3. An inbound call and the calling party (from the PSTN) hangs up. Debug shows both SID and Recording-ID values