VoIP.info Guide

Asterisk PJSIP_INHERITABLE_HEADER: channel inheritance and outbound SIP evidence

Add one controlled SIP header on a calling channel, follow it to each outbound PJSIP child, and keep inheritance, callee-specific mutation, emitted signaling and peer acceptance separate.

Reviewed 2026-10-15Current Asterisk PJSIP_INHERITABLE_HEADER, PJSIP_HEADER, Dial and pre-dial-handler documentation reviewed October 14, 2026; the inheritable function is documented since Asterisk 20.19.0, 22.9.0 and 23.3.0, is absent from the documented Asterisk 21 function set, and exposes add, update and remove rather than a read action; installed release, loaded module, dialplan owner, channel graph, generated request, intermediary policy and peer acceptance remain deployment specific, and no PBX, module, dialplan, channel, endpoint, header, request, response, packet or call was inspected or testedAdvancedDocumentation based · not lab tested

Gate the dialplan by the installed Asterisk branch

Asterisk documents PJSIP_INHERITABLE_HEADER() from 20.19.0, 22.9.0 and 23.3.0. Those are branch-specific maintenance floors, not one interchangeable major-version label. The documented Asterisk 21 function index does not contain this function. Confirm the installed full version and loaded res_pjsip_header_funcs module before deploying a dialplan that depends on it.

Current online documentation does not prove that an older package, vendor build or unreloaded process exposes the function. Preserve the exact runtime version, package source, module inventory and dialplan reload result with any acceptance record.

Treat the calling channel as the inheritance source

The function adds, updates or removes a header on a PJSIP or non-PJSIP calling channel so an outbound PJSIP channel can inherit it. This is different from writing an ordinary outbound header directly on an already-created callee channel. Record the current channel name and unique ID where the inheritable header is created, then record every child channel expected to receive it.

A shared linked ID, a successful Dial invocation or a header stored on the caller is not proof that a particular outbound request contained the field. Local channels, queues, forwarding, parallel contacts and nested dialing can create additional channel boundaries that need their own observation.

Use add, update and remove as distinct operations

add creates a new inheritable header, including an explicitly empty value. update targets an existing instance and the documentation warns that the call fails when the named header does not already exist. remove can match one exact name, a prefix ending in *, or every inheritable header and returns the count removed. The optional instance number applies to update, not add or remove.

The function does not document a read action. Do not invent one or treat an empty expansion as inspection evidence. Prove the intended value from controlled dialplan input and the sanitized outbound SIP request, and use returned remove counts only as evidence of the selected channel store.

Keep inheritable and ordinary PJSIP headers in separate stores

Asterisk explicitly separates headers created with PJSIP_INHERITABLE_HEADER() from headers created with PJSIP_HEADER(). An inheritable header can be updated or removed only by the inheritable function; an ordinary PJSIP header can be modified or removed only by PJSIP_HEADER(). Matching names do not merge those ownership models.

Inventory both sources before troubleshooting a duplicate or unexpected field. Removing an ordinary header cannot be relied on to clear an inherited copy, and clearing inheritable state does not establish that endpoint, pre-dial or intermediary logic did not add another instance.

Use the callee pre-dial handler for per-leg changes

In normal execution the inheritable function operates on the caller, and the outbound PJSIP child inherits the result. Asterisk documents that a lowercase b() pre-dial handler can update or remove inherited headers on each newly created callee before dialing. Uppercase B() runs on the current caller before callee creation.

For parallel destinations, b() runs independently on every callee channel. Keep the handler short, terminate its Gosub with Return(), and bind any per-leg decision to that callee rather than a mutable global. One fork receiving the right header does not establish the value on another fork.

Separate generated syntax from authorization and outcome

An emitted custom or provider-required header is not authentication, caller-identity verification, routing authorization, billing entitlement or call completion. A proxy, SBC or carrier can remove, normalize or reject the field after Asterisk sends it. Do not put untrusted call input into routing, identity or policy headers without an explicit allowlist and ownership contract.

Validate one authorized request from source channel through child channel, pre-dial mutation, Asterisk output, next-hop copy, peer response and final application outcome. Redact identities, tokens and customer data. No PBX, module, dialplan, channel, endpoint, header, request, response, packet or call was tested for this guide.

Asterisk dialplan — inherit and narrow one outbound header
[from-policy]
exten => _X.,1,Set(PJSIP_INHERITABLE_HEADER(add,X-Policy-Token)=approved-lab-value)
 same => n,Dial(PJSIP/${EXTEN}@lab-endpoint,,b(per-leg^s^1))

[per-leg]
exten => s,1,Set(PJSIP_INHERITABLE_HEADER(update,X-Policy-Token)=approved-leg-value)
 same => n,Return()

Distinguish a channel variable from an inheritable SIP header

Asterisk channel-variable _ and __ prefixes do not by themselves prove a PJSIP_INHERITABLE_HEADER() value or an outbound header on a created PJSIP leg. Use the scope guide to prove the channel path first.

Sources & applicability

Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.

Examples require adaptation to your topology. No live PBX or hardware testing is claimed.