Need to add SIP header to outbound calls on PJSIP trunk

So the carrier Skyetel is adding a tenant functionality that I would like to make use of on one PBX (not actually multi-tenant).

I want to use this function to make use of the built in cost tools in Skyetel’s portal to get departmental usage stats.

To enable outbound calls to be linked correctly they want a SIP header added.


A search here led me to a few older posts that led me to this external post

The working bit of that post is Set(HASH(__SIPHEADERS,X-DID)=${CDR(did)})) to update the DID.

  1. Would it be the same process to ADD a header? Set(HASH(__SIPHEADERS,X-Tenant)
  2. Would I also need to hook into the trunk predial macro?

PJSIP does not use variables like that, it has an explicit PJSIP_HEADER dialplan function[1] that is expected to be executed in the pre-dial handler.



ok, that helps. I thought I had seen more recent posts, but search skill fialed me today.

That answers question 1. I can easily do Set(PJSIP_HEADER(add,X-Tenant)

Now where to get this into the dialplan…

There are channel agnostic, native FreePBX subroutines for this. Use a dialplan hook to call like this:

exten => s,1,NoOp(Entering user defined context [macro-dialout-trunk-predial-hook] in extensions_custom.conf)
exten => s,n,GoSub(func-set-sipheader,s,1(X-Tenant,
exten => s,n,MacroExit()

Thank you sir.

1 Like

ok, this works perfectly, but applies the header to all calls.

I can easily tweak that to check the outbound route name.

But what if Skyetel is down and the route fails over to my Twilio trunk, or, etc?

Obviously they don’t care about that header and I would expect the calls to terminate anyway. But it just feels dirty to shoehorn that header in there always.

It would be nice to have something that is only applied on the trunk.

Edit: I say that mostly for others, because for my example, I am using this functionality for departments. I will have to apply this header based on the outbound route used, as there is only 1 trunk setup and I want 4 different departments tracked with this tenant functionality…

1 Like

This post shows how to get the trunk name: Hooking for fun and income

1 Like

Here is my final solution. I welcome improvements.


  1. The trunk name is Skyetel
  2. NoOp Traces in Dialplan set to 1 in Advanced Settings
  3. All outbounds routes start with known values to match against.
; Much thanks to Lorne Gaetz with Sangoma for answering questions.
exten => s,1,NoOp(Entering user defined context [macro-dialout-trunk-predial-hook] in extensions_custom.conf)
; Get trunk name. If it is Skyetel determine a tenant, if not, exit.
exten => s,n,ExecIF($["${OUT_${DIAL_TRUNK}_SUFFIX}"!=""]?Set(trunk_name=${OUT_${DIAL_TRUNK}_SUFFIX}):Set(trunk_name=${OUT_${DIAL_TRUNK}}))
exten => s,n,GotoIf($["${trunk_name}"=="@Skyetel"]?determine_tenant:exit_macro)
; Based on outbound route name, add a SIP header X-Tenant=X
exten => s,n(determine_tenant),NoOp(We are heading for the Skyetel Trunk, determine the X-Tenant based on outbound route)
; Set x_tenant = to tenant.stl by default.
exten => s,n,Set(x_tenant=tenant.stl)
; Change it if the call is on a Cape, Jeff City, or Quincy outbound route.
exten => s,n,ExecIf($["${OUTBOUND_ROUTE_NAME:0:4}"=="Cape"]?Set(x_tenant=tenant.cape))
exten => s,n,ExecIf($["${OUTBOUND_ROUTE_NAME:0:9}"=="Jeff City"]?Set(x_tenant=tenant.jeffcity))
exten => s,n,ExecIf($["${OUTBOUND_ROUTE_NAME:0:6}"=="Quincy"]?Set(x_tenant=tenant.quincy))
exten => s,n,NoOp(Based on the outbound route name of ${OUTBOUND_ROUTE_NAME}, the X-Tenant is being set to ${x_tenant}.)
exten => s,n,GoSub(func-set-sipheader,s,1(X-Tenant,${x_tenant}))
exten => s,n(exit_macro),MacroExit()

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.