FreePBX 17 Diversion Header - VoIP.ms Wiki

Check out our YouTube channel to watch our simple tutorials that will help you set up most of our features.

FreePBX 17 Diversion Header

From VoIP.ms Wiki

Revision as of 18:44, 21 August 2026 by FherNando (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Disclaimer: This guide is provided as a reference only. Actual customer configurations may vary depending on their FreePBX version, Asterisk build, trunk settings, dialplan structure, and network environment. Always review and adapt any configuration changes to match the specific customer setup before applying them.


This guide configures FreePBX 17 with PJSIP to automatically add a SIP Diversion header when an inbound DID is forwarded back out through a SIP trunk.

The objective is:

External Caller
      │
      ▼
DID 5557896321
      │
      ▼
   FreePBX
      │
      │ Call Forwarding
      ▼
External Destination

On the outbound leg, FreePBX should generate:

Diversion: <sip:5557896321@PBX_IP_OR_FQDN>;reason=unconditional

The DID is determined dynamically, so the configuration can work with multiple forwarded DIDs.

Prerequisites

This guide assumes:

  • FreePBX 17
  • Asterisk with PJSIP
  • A working SIP trunk
  • Incoming calls are already working
  • An Inbound Route exists for the DID
  • A Misc Destination forwards the call to an external number
  • An Outbound Route sends the forwarded call through the appropriate trunk

The basic FreePBX routing should already work:

SIP Provider
     │
     ▼
Inbound Route
     │
     ▼
Misc Destination
     │
     ▼
Outbound Route
     │
     ▼
SIP Trunk
     │
     ▼
External Destination

The Diversion header is an additional step applied to the outbound leg.

Custom Dialplan

FreePBX does not provide a standard field on a Misc Destination or Inbound Route for inserting an arbitrary Diversion SIP header.

Asterisk's PJSIP_HEADER() function can add headers to an outbound PJSIP channel. Importantly, Asterisk recommends doing this in a pre-dial handler when the header needs to be applied to the outgoing channel.

FreePBX provides a suitable outbound-trunk hook:

macro-dialout-trunk-predial-hook

This hook executes during outbound trunk processing, before the call is sent to the provider.

We therefore use:

/etc/asterisk/extensions_custom.conf

rather than modifying FreePBX-generated dialplan files.

Edit extensions_custom.conf

Open:

nano /etc/asterisk/extensions_custom.conf

Add:

[macro-dialout-trunk-predial-hook]
exten => s,1,NoOp(Diversion check - FROM_DID=${FROM_DID})
exten => s,n,GotoIf($["${FROM_DID}"=""]?done)
exten => s,n,GoSub(func-set-sipheader,s,1(Diversion,<sip:${FROM_DID}@PBX_IP_OR_FQDN>\;reason=unconditional))
exten => s,n(done),Return()

Replace:

PBX_IP_OR_FQDN

with the appropriate PBX address or domain if necessary for your environment.

What the dialplan does

The first line defines the FreePBX hook:

[macro-dialout-trunk-predial-hook]

FreePBX calls this context while preparing an outbound trunk call.

The next line is primarily for debugging:

exten => s,1,NoOp(Diversion check - FROM_DID=${FROM_DID})

It lets you see the value of ${FROM_DID} in the Asterisk console.

For a forwarded incoming call, you should see something similar to:

Diversion check - FROM_DID=5557896321

The next line determines whether this was originally an inbound DID:

exten => s,n,GotoIf($["${FROM_DID}"=""]?done)

If FROM_DID is empty, execution jumps to done and no Diversion header is added.

This is important for ordinary outbound calls:

Extension 1001
     │
     ▼
External number

FROM_DID=
→ No Diversion header

For a forwarded inbound call:

External Caller
     │
     ▼
5557896321
     │
     ▼
FreePBX
     │
     ▼
External number

FROM_DID=5557896321
→ Add Diversion header

Add the Diversion header

This is the line that performs the actual work:

exten => s,n,GoSub(func-set-sipheader,s,1(Diversion,<sip:${FROM_DID}@PBX_IP_OR_FQDN>\;reason=unconditional))


${FROM_DID} is evaluated dynamically.

Therefore:

FROM_DID=5557896321

produces:

Diversion: <sip:5557896321@PBX_IP_OR_FQDN>;reason=unconditional

Another DID, for example:

FROM_DID=5551234567

would automatically produce:

Diversion: <sip:5551234567@PBX_IP_OR_FQDN>;reason=unconditional

There is therefore no need to create a separate dialplan entry for every DID, provided ${FROM_DID} is preserved on those forwarded calls.

Why \; is required

Notice this:

\;reason=unconditional

rather than:

;reason=unconditional

The backslash is important.

In Asterisk configuration syntax, ; starts a comment. Without escaping it, Asterisk can interpret:

;reason=unconditional

as a comment instead of part of the SIP header.

The backslash is only for parsing the configuration. It does not appear on the wire.

Asterisk sends:

Diversion: <sip:5557896321@PBX_IP_OR_FQDN>;reason=unconditional

not:

Diversion: <sip:5557896321@PBX_IP_OR_FQDN>\;reason=unconditional

Reload FreePBX

After saving the file:

fwconsole reload

You do not need to restart the server.

Final configuration

The complete configuration is therefore:

[macro-dialout-trunk-predial-hook]

; Log the inbound DID for troubleshooting
exten => s,1,NoOp(Diversion check - FROM_DID=${FROM_DID})

; Do nothing when the call did not originate from an inbound DID
exten => s,n,GotoIf($["${FROM_DID}"=""]?done)

; Add Diversion header using the original incoming DID
exten => s,n,GoSub(func-set-sipheader,s,1(Diversion,<sip:${FROM_DID}@PBX_IP_OR_FQDN>\;reason=unconditional))

; Return control to the FreePBX-generated outbound dialplan
exten => s,n(done),Return()

The resulting behavior is:

NORMAL OUTBOUND CALL

1001 ──────► FreePBX ──────► SIP Provider
                              No Diversion


FORWARDED CALL

Caller
  │
  ▼
DID 5557896321
  │
  ▼
FreePBX ───────────────────► SIP Provider
                              │
                              │ Diversion:
                              │ <sip:5557896321@PBX_IP_OR_FQDN>;
                              │ reason=unconditional
                              ▼
                         Final Destination

The important design point is that FreePBX continues to control the Inbound Route, Misc Destination, Outbound Route, and trunk through the GUI. The custom dialplan does only one thing: inject the Diversion header into the outbound PJSIP leg when ${FROM_DID} indicates that the call originated from an inbound DID.

Personal tools
Namespaces
Variants
Actions
VoIP.ms Wiki
Guides 🇨🇦
Guías 🇲🇽