VoIP.info Guide

Asterisk PJSIP outbound headers: channel ownership, inheritance and proof

Put a required SIP header on the channel that will send it, distinguish direct from inherited headers and verify the emitted request.

Reviewed 2026-10-13Current Asterisk PJSIP header, inheritable-header, header-list, header-parameter, response-header and pre-dial-handler documentation reviewed October 8, 2026; PJSIP_INHERITABLE_HEADER is documented from 20.19.0, 22.9.0 and 23.3.0, and no PBX, dialplan, channel, header, provider, endpoint, request, response, registration, authentication exchange, availability, compatibility or call was inspected or testedAdvancedDocumentation based · not lab tested

Start with the request and the header owner

Record the exact provider or peer requirement, SIP method, direction, header name, value syntax, destination and whether the value is constant or call-specific. Preserve a sanitized working request when one exists. A field required on an outbound INVITE is not automatically required on REGISTER, OPTIONS, an in-dialog request or the response to an inbound call.

Map the caller channel, every Local-channel pair and the final outbound PJSIP channel. A dialplan variable visible on the caller is not proof that a SIP header exists on the callee, and a header read from the inbound request is not automatically copied to a new outbound request.

Use PJSIP_HEADER on the outbound channel

Asterisk documents PJSIP_HEADER() as reading headers from an inbound PJSIP channel and adding, updating or removing headers on an outbound PJSIP channel. In an ordinary dialplan context it operates on the caller, which may be the wrong channel. The documented pattern uses the lowercase b pre-dial option so the function runs on each newly created callee before the request is sent.

The lowercase b handler is different from uppercase B: B runs on the caller before callee channels are created, while b runs on each callee after creation and before dialing. Every pre-dial handler is a Gosub and must end with Return(). Keep it short and do not move the channel into another application from the handler.

Asterisk dialplan — add one outbound header on each callee
[outbound-header]
exten => add,1,Set(PJSIP_HEADER(add,X-Example-Route)=${ARG1})
 same => n,Return()

[from-example]
exten => _X.,1,Dial(PJSIP/${EXTEN}@example-trunk,30,b(outbound-header^add^1(route-a)))

Choose inheritance only on supported versions

PJSIP_INHERITABLE_HEADER() is a newer path for writing a header on a PJSIP or non-PJSIP calling channel so an outbound PJSIP child inherits it. The current documentation lists it from Asterisk 20.19.0, 22.9.0 and 23.3.0. Confirm the installed branch and maintenance release before using it; its presence in current documentation does not add it to older 18, 20 or 22 builds.

Inherited headers and headers added with PJSIP_HEADER() are separate stores. A header added by one function can only be updated or removed by that same function. Inherited headers can be adjusted in a callee pre-dial handler, but mixing both paths for the same name can create duplicates and confusing rollback.

Keep request, parameter and response APIs distinct

PJSIP_HEADERS() enumerates header names from an inbound INVITE; it does not list the future outbound request or return values. PJSIP_HEADER_PARAM() gets or sets URI or header parameters and currently supports only the From header. A custom header value and a From URI parameter are therefore different edits.

PJSIP_RESPONSE_HEADER() reads headers from the 200 response on an outbound PJSIP channel and belongs in the documented pre-connect path. It is evidence about a response, not a way to add the request header. Preserve method, direction, channel and message phase whenever recording a function result.

Treat forwarding as policy, not blind copying

Do not copy every X- header or a trusted-network identity header from an inbound request to an outbound trunk. Define an allow-list, validate the source and value, remove hop-specific or customer-private data, and generate authoritative identity only at the component that owns it. Header names can be repeated, and add always creates another instance; use update only when the named instance already exists.

Caller identity, privacy, emergency location, STIR/SHAKEN, diversion and billing headers can have legal, trust and routing consequences. Follow the provider's current specification and local policy. A syntactically emitted header does not prove the peer accepted or acted on it.

Verify the wire request and rollback

Use a short authorized protocol capture and correlate the outbound request by timestamp, Call-ID, destination and dialplan branch. Confirm the exact header count, spelling, value, channel and method, then preserve the peer's response and the call outcome separately. Test a path that should carry the header and an unrelated path that should not.

On FreePBX-managed systems, use supported custom dialplan or module extension points and retain Apply Config ownership; do not edit generated dialplan. Remove temporary logging, protect captured identities and tokens, and restore the previous dialplan if another route gains, loses or duplicates a header. No PBX, channel, header, peer or call was tested for this guide.

Do not replace party-state controls with static headers

Connected-line and redirecting information can change at answer, forwarding or transfer. The party-identity guide maps those updates to PJSIP trust, send, Diversion and History-Info controls rather than treating a pre-Dial custom header as the whole identity model.

Select the Gosub handler that owns the outbound channel

Use the Gosub channel-ownership guide before setting a PJSIP header. B() on the caller, b() on each callee and U() after answer run at different lifecycle points and do not prove the same channel owns the header.

Parse header URI data on the channel that owns it

The PJSIP_PARSE_URI workflow keeps the complete header, its channel and message direction beside every extracted user, host or parameter. Parsing does not prove outbound-header placement or peer acceptance.

Read response headers after answer, not in the request handler

The dedicated PJSIP response-header guide distinguishes uppercase U() after answer from lowercase b() before dialing and preserves the selected response field instance.

Use the parameter function when the From container is already correct

The PJSIP_HEADER_PARAM guide distinguishes a narrow From URI or header parameter from adding or replacing an entire outbound header.

Keep inheritable headers separate from ordinary outbound headers

The inheritable-header guide explains why values added by PJSIP_INHERITABLE_HEADER() and PJSIP_HEADER() require their matching update and remove functions.

Do not use an inbound inventory as outbound proof

PJSIP_HEADERS() lists names from the INVITE available to the current inbound channel. The dedicated inventory guide keeps that evidence separate from callee pre-dial writes and wire verification.

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.