TheVoĉoTheVoĉo
ConfigurationAdvanced

SIP Headers

SIP (Session Initiation Protocol) headers contain metadata about VoIP calls. Manipulating these headers enables advanced features like custom caller ID assertion, call tracking, provider compatibility, and integration with external systems. Control which headers your PBX sends to providers and how it processes headers from providers.

Understanding SIP Headers

What are SIP Headers?

SIP headers are key-value pairs in SIP messages that carry information about calls:

Basic SIP Message Structure:

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK-1234
From: "John Smith" <sip:[email protected]>;tag=abc123
To: <sip:[email protected]>
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: <sip:[email protected]:5060>
Max-Forwards: 70
User-Agent: TheVoĉo-PBX/1.0
Allow: INVITE, ACK, CANCEL, BYE, OPTIONS, REFER
Content-Type: application/sdp
Content-Length: 300

[SDP Body]

Key Header Types:

Required Headers (RFC 3261):

  • From: Originator of request
  • To: Intended recipient
  • Call-ID: Unique call identifier
  • CSeq: Command sequence number
  • Via: Path taken by request
  • Contact: Direct URI for reaching sender

Caller ID Headers:

  • P-Asserted-Identity: Trusted caller ID from provider
  • Remote-Party-ID: Legacy caller ID header
  • Privacy: Privacy preferences (hide caller ID)

Custom Headers:

  • X-Custom-*: User-defined headers for tracking, routing, etc.

Inbound Header Processing

P-Asserted-Identity (PAI) Header

What is PAI? RFC 3325 header for trusted caller ID. Providers use PAI to assert the authenticated identity of the caller.

Format:

P-Asserted-Identity: "John Smith" <sip:[email protected]>
P-Asserted-Identity: <tel:+15551234567>

Why Use PAI?

  • Trusted: Only network operators can set (not end users)
  • Accurate: Contains verified caller ID
  • Privacy: Separate from From header (can show different to callee)
  • STIR/SHAKEN: Used for call authentication

Configuration:

Read PAI for Caller ID:

Setting: Use P-Asserted-Identity for inbound caller ID
Priority: PAI > Remote-Party-ID > From header
Behavior: If PAI present, use it; else fallback to other headers

Extract Number from PAI:

PAI Header: "John Smith" <sip:[email protected]>
Extract: +15551234567
Use As: Inbound caller ID
Display: "John Smith" +15551234567

Multiple PAI Headers:

SIP allows multiple PAI headers (rare):
P-Asserted-Identity: <tel:+15551234567>
P-Asserted-Identity: <sip:[email protected]>

Configuration: Use first PAI (phone number)
Or: Parse both, prefer tel: URI

PAI with Privacy:

Headers:
  P-Asserted-Identity: <tel:+15551234567>
  Privacy: id

Behavior:
  Provider: Asserts real caller ID in PAI
  Privacy: User requested caller ID hidden
  Result: PBX sees real ID, displays "Anonymous" to users (if honoring privacy)

Troubleshooting PAI:

  • Enable SIP debug, capture actual PAI value
  • Check if provider sends PAI (not all do)
  • Verify PAI parsing extracts number correctly
  • Test with various PAI formats

Modern Standard

P-Asserted-Identity is the modern standard for carrier-provided caller ID. Always prefer PAI over Remote-Party-ID when available.

Remote-Party-ID (RPID) Header

What is RPID? Legacy header for caller ID information. Pre-dates PAI but still widely used.

Format:

Remote-Party-ID: "John Smith" <sip:[email protected]>;party=calling;privacy=off;screen=yes

Parameters:

  • party: calling (caller), called (callee)
  • privacy: off, full, name, uri
  • screen: yes (screened), no (unscreened)

Configuration:

Read RPID for Caller ID:

Setting: Use Remote-Party-ID for caller ID
Priority: PAI > RPID > From
Behavior: Check PAI first, then RPID, then From

Parse RPID Parameters:

Header: Remote-Party-ID: "John" <tel:+15551234567>;party=calling;privacy=off

Extract:
  Name: John
  Number: +15551234567
  Privacy: Off (show caller ID)
  Result: Display both name and number

Privacy Handling:

privacy=off: Show caller ID
privacy=full: Hide name and number
privacy=name: Show number, hide name
privacy=uri: Show name, hide number

Screen Parameter:

screen=yes: Provider verified caller ID (trusted)
screen=no: User-provided, not verified (less trusted)

Configuration:
  Trust screen=yes more than screen=no
  May apply different routing rules based on screening

RPID vs PAI:

Prefer PAI:
  - Modern standard
  - Better defined
  - STIR/SHAKEN compatible

Use RPID:
  - Legacy providers
  - Backward compatibility
  - When PAI not available

Legacy Support

Remote-Party-ID is legacy but still common. Support both PAI and RPID for maximum provider compatibility.

Diversion Header

What is Diversion? RFC 5806 header indicating call has been diverted/forwarded. Shows original destination before forwarding.

Format:

Diversion: <sip:[email protected]>;reason=unconditional;counter=1;privacy=off

Use Cases:

Call Forwarding:

Original destination: +15551111111
Forwarded to: +15552222222

Headers:
  To: +15552222222
  Diversion: <tel:+15551111111>;reason=unconditional

PBX knows: Call was originally for +15551111111

Voicemail Redirect:

Reason values:
  - unconditional: Always forward
  - user-busy: Forwarded because busy
  - no-answer: Forwarded because no answer
  - unavailable: Forwarded because unavailable
  - deflection: Call deflected by user

Use: Display appropriate message to caller

Multiple Diversions:

Call forwarding chain:
  A → B → C

Diversion headers (multiple):
  Diversion: <tel:+1555-A>;reason=unconditional;counter=1
  Diversion: <tel:+1555-B>;reason=user-busy;counter=2

Shows full forwarding path

Configuration:

Read Diversion Information:

Setting: Parse Diversion header
Extract: Original destination, reason, counter
Use: Display to user, routing decisions, logging

Example Display:

Diversion detected:
  Original number: +15551111111
  Reason: No answer
  Current destination: You

Display: "Call forwarded from +15551111111 (no answer)"

Routing Based on Diversion:

If Diversion present and reason=no-answer:
  Route to: Urgent queue (may be time-sensitive)
Else:
  Route to: Standard queue

Counter Parameter:

counter=1: First forward
counter=2: Second forward
counter=5: Fifth forward

Use: Prevent forward loops
Configuration: Max counter=3 (reject if >3)

Call History

Diversion headers provide valuable call history. Use for better routing decisions and improved caller experience.

Reading Custom Headers from Provider

What are Custom Headers? Provider-specific headers (usually X-*) with custom information for tracking, routing, or integration.

Common Custom Headers:

X-Account-Code:

Header: X-Account-Code: CUSTOMER-12345
Use: Billing, cost allocation
Processing: Extract account code, associate with call

X-Original-Called-Number:

Header: X-Original-Called-Number: +15551111111
Use: Alternative to Diversion header
Processing: Extract original destination

X-Carrier-Info:

Header: X-Carrier-Info: carrier=Verizon;quality=HD
Use: Carrier identification, call quality info
Processing: Parse for reporting

X-Call-Type:

Header: X-Call-Type: emergency
Use: Special call handling
Processing: Route to priority queue

X-Customer-ID:

Header: X-Customer-ID: 67890
Use: Link call to customer account
Processing: CRM lookup, screen pop

Configuration:

Read Specific Custom Header:

Setting: Custom Header Processing
Header Name: X-Account-Code
Action: Extract value
Store In: Call variable ${XHEADER_ACCOUNT}
Use In: Routing, CDR, reporting

Multiple Custom Headers:

Read Headers:
  X-Account-Code → ${ACCOUNT_CODE}
  X-Customer-ID → ${CUSTOMER_ID}
  X-Call-Priority → ${PRIORITY}

Use in routing:
  If ${PRIORITY} = "high":
    Route to: VIP queue
  Else:
    Route to: Standard queue

Parse Complex Header Values:

Header: X-Metadata: account=12345;region=west;type=sales
Parse:
  account: 12345
  region: west
  type: sales

Use: Multiple routing criteria from single header

Header-Based Authentication:

Header: X-API-Key: abc123xyz789
Validation: Check against known API keys
If valid: Allow call
If invalid: Reject call
Use: Secure API-initiated calls

Integration Example (CRM):

Inbound call with:
  X-Customer-ID: 67890

Processing:
  1. Extract customer ID
  2. Webhook to CRM: GET /customer/67890
  3. CRM returns: Name, account status, history
  4. Display to agent
  5. Route based on customer tier

Result: Context-aware call handling

Security

Don't trust custom headers from untrusted sources. Validate and sanitize all header values before use.


Outbound Header Manipulation

Set P-Asserted-Identity on Outbound

Why Set PAI?

  • Assert authenticated caller ID to provider
  • Enable STIR/SHAKEN call authentication
  • Trusted caller ID display
  • Provider-required header

Configuration:

Basic PAI Setup:

Setting: Send P-Asserted-Identity
Format: <tel:${CALLERID(num)}>
Result: P-Asserted-Identity: <tel:+15551234567>

PAI with Display Name:

Setting: Include display name
Format: "${CALLERID(name)}" <tel:${CALLERID(num)}>
Result: P-Asserted-Identity: "John Smith" <tel:+15551234567>

Multiple PAI Headers:

Some providers accept multiple PAI:
PAI 1: <tel:+15551234567> (phone number)
PAI 2: <sip:[email protected]> (SIP URI)

Configuration: Send both if provider supports

Extension-Specific PAI:

Extension 2001: PAI = +15551111111
Extension 2002: PAI = +15552222222
Extension 2003: PAI = +15553333333

Configuration: Map extension to specific DID for PAI

Trunk-Specific PAI:

Trunk A: PAI = +15551234567 (main number)
Trunk B: PAI = +15559876543 (secondary number)

Configuration: Different PAI per trunk

Conditional PAI:

If destination is US:
  PAI: +15551234567
If destination is international:
  PAI: +15559999999 (international callback number)

STIR/SHAKEN Attestation:

PAI with attestation level:
P-Asserted-Identity: <tel:+15551234567>;stir-attest=A

Levels:
  A: Full attestation (best)
  B: Partial attestation
  C: Gateway attestation (minimal)

Configuration: Work with provider for attestation

Privacy with PAI:

Send both:
P-Asserted-Identity: <tel:+15551234567>
Privacy: id

Result:
  - Provider knows real caller ID (PAI)
  - End user sees "Anonymous" or "Private"
  - Use: Executive calls, sensitive situations

Provider Requirements

Check if your provider requires PAI, accepts it, or ignores it. Some providers mandate PAI for caller ID authentication.

Set Remote-Party-ID on Outbound

Why Set RPID?

  • Legacy provider compatibility
  • Backup if PAI not supported
  • Additional privacy controls

Configuration:

Basic RPID Setup:

Setting: Send Remote-Party-ID
Format: <tel:${CALLERID(num)}>;party=calling;privacy=off;screen=yes
Result: Remote-Party-ID: <tel:+15551234567>;party=calling;privacy=off;screen=yes

RPID with Display Name:

Format: "${CALLERID(name)}" <tel:${CALLERID(num)}>;party=calling;privacy=off;screen=yes
Result: Remote-Party-ID: "John Smith" <tel:+15551234567>;party=calling;privacy=off;screen=yes

Privacy Parameter:

privacy=off: Show full caller ID
privacy=full: Hide all (anonymous)
privacy=name: Hide name, show number
privacy=uri: Hide number, show name

Configuration: Based on user preference or call type

Screen Parameter:

screen=yes: PBX verified caller ID (assert trust)
screen=no: User-provided (lower trust)

Configuration: Set screen=yes for authenticated users

Party Parameter:

party=calling: This is the caller
party=called: This is the called party (rare in RPID)

Always use: party=calling for outbound

Conditional RPID Privacy:

Normal calls:
  privacy=off (show caller ID)

Executive extensions:
  privacy=full (anonymous)

After-hours:
  privacy=name (show number only, hide name)

RPID for Call Forwarding:

Call forwarded from +15551111111 to +15552222222:

RPID in forwarded call:
  Remote-Party-ID: <tel:+15551111111>;party=calling;privacy=off

Shows: Original caller, not forwarder

Compatibility Mode:

Send both PAI and RPID:
  P-Asserted-Identity: <tel:+15551234567>
  Remote-Party-ID: <tel:+15551234567>;party=calling;privacy=off;screen=yes

Provider uses: Whichever it supports
Result: Maximum compatibility

Dual Headers

Sending both PAI and RPID ensures compatibility with all providers. Modern providers use PAI, legacy use RPID.

Add Custom Headers to Outbound Calls

Use Cases:

Call Tracking:

Header: X-Campaign-ID: GOOGLE-SUMMER-2024
Use: Track calls by marketing campaign
Report: ROI per campaign

Account Code:

Header: X-Account-Code: DEPT-SALES
Use: Cost allocation per department
Billing: Charge back to department

Call Priority:

Header: X-Priority: high
Use: Signal priority to provider
Provider: May route to better trunks

Customer Reference:

Header: X-Customer-ID: ${CUSTO MER_ID}
Use: Link call to CRM record
Integration: Provider sends to your webhook with customer context

API Key Authentication:

Header: X-API-Key: ${API_SECRET}
Use: Authenticate API-initiated calls
Provider: Validates key before connecting

Configuration:

Static Custom Header:

Setting: Add Custom Header
Name: X-Account-Code
Value: MAIN-OFFICE
Apply: All outbound calls

Dynamic Custom Header:

Setting: Add Custom Header
Name: X-Extension-Number
Value: ${CALLERID(num)}
Apply: All outbound calls
Result: X-Extension-Number: 2001

Conditional Custom Header:

If destination matches +1555*:
  Add header: X-Call-Type: local
Else:
  Add header: X-Call-Type: long-distance

Multiple Custom Headers:

Header 1: X-Account-Code: SALES
Header 2: X-Department: Sales
Header 3: X-Extension: 2001
Header 4: X-Campaign: SUMMER2024

All added to outbound INVITE

Per-Extension Custom Headers:

Extension 2001:
  X-Department: Sales
  X-Manager: John Smith

Extension 3001:
  X-Department: Support
  X-Manager: Jane Doe

Result: Context per extension

Integration Example:

Outbound call with:
  X-Customer-ID: 67890
  X-Campaign-ID: GOOGLE-ADS-123
  X-Account-Code: SALES

Provider forwards to your webhook:
  POST /call-initiated
  Headers:
    X-Customer-ID: 67890
    X-Campaign-ID: GOOGLE-ADS-123
    X-Account-Code: SALES

Your system:
  - Logs call against campaign
  - Associates with customer
  - Updates CRM

Header Limitations:

  • Max header length: 256 characters (typical)
  • Max custom headers: 10-20 (provider-dependent)
  • Character restrictions: ASCII only, no special chars
  • Some providers strip X-* headers

Provider Support

Not all providers support or forward custom headers. Test with your specific provider before relying on custom headers.

Remove/Sanitize Outbound Headers

Why Remove Headers?

Privacy:

Remove: User-Agent (reveals PBX software/version)
Remove: Server (reveals system info)
Remove: Organization (company internal info)
Reason: Don't leak system details

Security:

Remove: X-Internal-Extension (exposes internal numbering)
Remove: X-Private-* (internal custom headers)
Reason: Prevent information disclosure

Compatibility:

Remove: Proprietary headers provider doesn't support
Remove: Headers that confuse provider
Reason: Some providers reject calls with unknown headers

Configuration:

Remove Specific Headers:

Remove: User-Agent
Remove: Server
Remove: Organization
Remove: X-Internal-*

Result: Cleaner, more private SIP messages

Whitelist Approach:

Keep only:
  - Required headers (From, To, Via, etc.)
  - P-Asserted-Identity
  - Remote-Party-ID
  - Custom headers you intentionally add

Remove: Everything else

Result: Minimal, secure header set

Remove By Pattern:

Remove: X-Internal-*
Matches: X-Internal-Extension, X-Internal-ID, X-Internal-Anything
Result: All internal headers stripped

Conditional Removal:

If destination is external (not internal PBX):
  Remove: X-Internal-*
  Remove: Organization
If destination is internal:
  Keep all headers (useful for internal routing)

Sanitize Header Values:

User-Agent: TheVoĉo-PBX/1.0 (internal-hostname.local)
Sanitized: TheVoĉo-PBX/1.0

Action: Remove internal hostname
Reason: Don't expose internal names

Remove Anonymous Headers:

If caller wants to be anonymous:
  Remove: P-Asserted-Identity
  Add: Privacy: id
  From header: "Anonymous" <sip:[email protected]>

Result: Full caller ID hiding

Header Rewriting:

Original: Contact: <sip:[email protected]:5060>
Rewritten: Contact: <sip:[email protected]:5060>

Reason: Replace internal IP with public IP (NAT)

Audit Outbound Headers:

Before removal:
  - Capture sample outbound INVITE
  - Review all headers
  - Identify unnecessary/sensitive headers
  - Configure removal

After removal:
  - Capture again
  - Verify only intended headers present

Best Practices:

  1. Remove User-Agent and Server (info leakage)
  2. Remove internal-only custom headers
  3. Sanitize Contact and Via (replace internal IPs)
  4. Keep required headers (RFC 3261)
  5. Keep provider-required headers (PAI, RPID)

Don't Over-Remove

Removing required headers breaks calls. Test thoroughly. Only remove genuinely unnecessary or sensitive headers.


Advanced Use Cases

Using Headers for Call Tracking

Scenario: Marketing Attribution

Setup:

Website shows dynamic numbers based on visitor source:
  Google Ads: +1-555-001-GOOGLE
  Facebook: +1-555-002-FACEBOOK
  Organic: +1-555-003-ORGANIC
  Direct: +1-555-004-DIRECT

Inbound Header Processing:

DID +1-555-001-GOOGLE receives call:
  Add header: X-Campaign-Source: Google-Ads
  Add header: X-Campaign-ID: GOOGLE-SUMMER-2024
  Add header: X-Medium: PPC

DID +1-555-002-FACEBOOK receives call:
  Add header: X-Campaign-Source: Facebook-Ads
  Add header: X-Campaign-ID: FACEBOOK-Q4-2024
  Add header: X-Medium: Social

Route all to: Sales queue

Call Answered:

Agent answers, PBX sends webhook:
  POST /call-answered
  Headers:
    X-Campaign-Source: Google-Ads
    X-Campaign-ID: GOOGLE-SUMMER-2024
    X-Caller-Number: +15559876543
    X-Extension: 2001

CRM Integration:

CRM receives webhook:
  - Looks up customer by phone
  - Associates call with campaign
  - Updates campaign metrics
  - Creates opportunity
  - Screen pops agent with full context

Callback with Context:

Agent calls customer back:
  Outbound call includes:
    X-Campaign-ID: GOOGLE-SUMMER-2024
    X-Customer-ID: 67890
    X-Callback: true

Provider forwards to your analytics:
  - Log callback against original campaign
  - Track time-to-callback
  - Measure callback effectiveness

Reporting:

Campaign Performance:
  
Google Ads (X-Campaign-Source: Google-Ads):
  - Inbound Calls: 500
  - Answered: 450
  - Callbacks: 200
  - Conversions: 75
  - Revenue: $375,000
  - ROI: 450%

Facebook Ads (X-Campaign-Source: Facebook-Ads):
  - Inbound Calls: 300
  - Answered: 270
  - Callbacks: 120
  - Conversions: 40
  - Revenue: $200,000
  - ROI: 280%

Result: Data-driven marketing decisions

Full Attribution

SIP headers enable full call attribution from initial ad click through call, callback, and conversion. Closes the marketing loop.

Automatic CRM Screen Pop

Scenario: Sales Team with CRM

Inbound Call Processing:

1. Call arrives from +15559876543
2. PBX extracts caller ID
3. PBX sends webhook to CRM:
   POST /screen-pop
   Headers:
     X-Caller-Number: +15559876543
     X-Called-Number: +15551234567
     X-Extension: 2001 (if already routed)
     X-Trunk-ID: Main-Trunk

CRM Lookup:

CRM searches for +15559876543:
  
Found: John Smith
  - Company: Acme Corp
  - Title: VP of Sales
  - Last Contact: 2024-11-15
  - Opportunity: $50,000 pending
  - Status: Hot lead
  - Notes: Requested demo, follow up on pricing

Agent Display:

Screen pop before answer:
  ╔════════════════════════════════╗
  ║  Incoming Call                 ║
  ║                                ║
  ║  John Smith                    ║
  ║  VP of Sales, Acme Corp        ║
  ║                                ║
  ║  Last Contact: Nov 15          ║
  ║  Opportunity: $50,000          ║
  ║  Status: Hot Lead              ║
  ║                                ║
  ║  Notes:                        ║
  ║  Requested demo, follow up     ║
  ║  on pricing                    ║
  ║                                ║
  ║  [Answer]  [Send to Voicemail] ║
  ╚════════════════════════════════╝

Enhanced with Custom Headers:

If provider sends custom headers:
  X-Customer-ID: 67890
  X-Account-Tier: Premium
  X-Last-Order-Date: 2024-11-01

Screen pop includes:
  - Customer since: 2020
  - Lifetime value: $500,000
  - Last order: Nov 1, 2024 ($10,000)
  - Tier: Premium (VIP treatment)

Call Recording Note:

When call answered:
  PBX sends: 
    X-CRM-Record-ID: 67890
    X-Call-Purpose: Sales-Follow-Up

When call ends:
  PBX sends webhook with recording URL:
    POST /call-ended
    Headers:
      X-CRM-Record-ID: 67890
      X-Recording-URL: https://pbx/recordings/12345.mp3
      X-Duration: 480 (8 minutes)

CRM:
  - Attaches recording to customer record
  - Logs call duration
  - Updates last contact date

Outbound Screen Pop:

Agent clicks "Call" in CRM:
  CRM initiates call via API:
    POST /click-to-call
    Headers:
      X-Customer-ID: 67890
      X-Extension: 2001
      X-Destination: +15559876543

PBX:
  - Calls extension 2001
  - When answered, calls customer
  - Includes X-Customer-ID in outbound headers
  - Enables tracking in all systems

Context is King

Screen pop with full customer context dramatically improves agent performance. Faster, more personalized service.

Multi-Tenant PBX Header Management

Scenario: Multi-Company Hosted PBX

Tenant Identification:

Company A: Calls on DIDs +1-555-1000 to +1-555-1099
Company B: Calls on DIDs +1-555-2000 to +1-555-2099
Company C: Calls on DIDs +1-555-3000 to +1-555-3099

Inbound Header Processing:

Call arrives on +1-555-1050:
  Add header: X-Tenant-ID: COMPANY-A
  Add header: X-Tenant-Name: Acme Corp
  Route to: Company A's extensions

Call arrives on +1-555-2050:
  Add header: X-Tenant-ID: COMPANY-B
  Add header: X-Tenant-Name: Best Co
  Route to: Company B's extensions

Tenant-Specific Outbound:

Company A outbound:
  P-Asserted-Identity: <tel:+15551000> (Company A main number)
  User-Agent: TheVoĉo-PBX/1.0 (AcmeCorp)
  X-Tenant-ID: COMPANY-A

Company B outbound:
  P-Asserted-Identity: <tel:+15552000> (Company B main number)
  User-Agent: TheVoĉo-PBX/1.0 (BestCo)
  X-Tenant-ID: COMPANY-B

Result: Proper caller ID per tenant

Tenant Isolation:

Security headers:
  X-Tenant-ID: COMPANY-A
  X-Allowed-Destinations: internal,local,mobile
  X-Block-International: true

Routing logic:
  If X-Tenant-ID = COMPANY-A:
    If destination is international:
      Block call (per tenant config)
    Else:
      Allow call

Result: Per-tenant call restrictions

CDR with Tenant Info:

Call Detail Record:
  Caller: +15559876543
  Called: +15551234567
  Tenant: COMPANY-A (from X-Tenant-ID header)
  Duration: 480 seconds
  Cost: $0.50

Billing:
  Company A charged: $0.50 for this call
  Company B: Separate billing

Tenant-Specific Features:

Company A config:
  Call Recording: All calls
  Hold Music: Company A custom music
  Voicemail: Company A voicemail system
  Headers: X-Tenant-ID, X-Account-Code

Company B config:
  Call Recording: Compliance calls only
  Hold Music: Default music
  Voicemail: Company B voicemail system
  Headers: X-Tenant-ID, X-Department

Enforced via: Header-based routing rules

Inter-Tenant Calls (if allowed):

Company A extension calls Company B extension:
  Headers:
    X-Source-Tenant: COMPANY-A
    X-Dest-Tenant: COMPANY-B
    X-Inter-Tenant-Call: true

Billing:
  Both tenants charged (or free internal)
Logs:
  Tracked separately for audit

Tenant Security

Use headers to enforce tenant isolation. Critical for multi-tenant security - prevent cross-tenant access.

Advanced Routing Based on Headers

Scenario 1: Priority Routing

Configuration:

If X-Priority header present:
  X-Priority: high → VIP queue (immediate)
  X-Priority: medium → Standard queue
  X-Priority: low → Bulk queue (longer wait)

If no X-Priority:
  Default → Standard queue

Application:

VIP customer calls:
  Provider sends: X-Priority: high
  Routing: Immediately to VIP queue
  Wait time: < 30 seconds
  Agent: Senior agent

Regular customer calls:
  No X-Priority header
  Routing: Standard queue
  Wait time: ~2 minutes
  Agent: Any available agent

Scenario 2: Time-Zone Routing

Headers:

Provider sends: X-Caller-Timezone: America/Los_Angeles
  Or: X-Caller-Region: PST

Routing Logic:

If X-Caller-Timezone = America/Los_Angeles (PST):
  Route to: West Coast office
  If unavailable: East Coast office (different hours)

If X-Caller-Timezone = America/New_York (EST):
  Route to: East Coast office
  If unavailable: West Coast office

Result: Local office answers, or appropriate backup

Scenario 3: Language Routing

Headers:

X-Preferred-Language: es (Spanish)
X-Preferred-Language: en (English)
X-Preferred-Language: fr (French)

Routing:

If X-Preferred-Language = es:
  Route to: Spanish-speaking queue
  IVR: Spanish prompts
  Agents: Bilingual or Spanish-only

If X-Preferred-Language = fr:
  Route to: French-speaking queue
  IVR: French prompts

Default (no header or en):
  Route to: English queue

Scenario 4: Account Type Routing

Headers:

X-Account-Type: enterprise
X-Account-Type: small-business
X-Account-Type: trial

Routing:

If X-Account-Type = enterprise:
  Route to: Enterprise support (24/7)
  SLA: < 1 minute response
  Agent: Senior certified

If X-Account-Type = small-business:
  Route to: Business support (business hours)
  SLA: < 5 minutes
  Agent: Standard support

If X-Account-Type = trial:
  Route to: Sales (convert to paid)
  IVR: Upsell messaging
  Agent: Sales rep

Scenario 5: Product-Specific Routing

Headers:

X-Product-ID: PRODUCT-A
X-Product-ID: PRODUCT-B
X-Product-ID: PRODUCT-C

Routing:

If X-Product-ID = PRODUCT-A:
  Route to: Product A specialists
  Queue: Product A support

If X-Product-ID = PRODUCT-B:
  Route to: Product B specialists
  Queue: Product B support

Multiple products:
  X-Product-ID: PRODUCT-A,PRODUCT-B
  Route to: General support (knows both)

Scenario 6: Call Back Queue

Headers:

X-Call-Type: callback
X-Original-Call-Time: 2024-11-21T14:30:00Z
X-Callback-Reason: no-answer

Routing:

If X-Call-Type = callback:
  Priority: High (customer waiting for callback)
  Route to: Agent who missed original call (if available)
  Or: Next available agent with context
  Display: "CALLBACK: Promised at 2:30pm"

Intelligent Routing

SIP headers enable sophisticated routing logic beyond simple number-based routing. Improves customer experience and operational efficiency.


Best Practices

SIP Header Recommendations

Follow best practices for secure, compatible, and effective header manipulation.

Security

  1. Validate Input: Never trust inbound headers without validation
  2. Sanitize Values: Strip malicious content (SQL injection, XSS attempts)
  3. Remove Sensitive: Remove internal headers before sending to provider
  4. Limit Exposure: Don't send User-Agent, Server, Organization
  5. Whitelist Approach: Only send explicitly configured headers

Compatibility

  1. Test with Provider: Always test with your specific provider first
  2. RFC Compliance: Follow RFC 3261 for required headers
  3. PAI + RPID: Send both for maximum compatibility
  4. Fallback Headers: Have backup headers if primary rejected
  5. SIP Debug: Capture actual messages to verify headers sent/received

Performance

  1. Minimize Headers: Only add necessary custom headers
  2. Short Values: Keep header values concise (< 100 chars)
  3. Limit Quantity: < 10 custom headers per call
  4. Cache Lookups: Cache CRM/DB lookups referenced in headers
  5. Async Processing: Don't block call setup for header processing

Documentation

  1. Document Headers: Maintain list of all custom headers and purposes
  2. Integration Guide: Document header requirements for integrations
  3. Change Log: Track when headers added/removed/changed
  4. Examples: Provide sample SIP messages with headers
  5. Troubleshooting: Document common header-related issues

Testing

  1. SIP Capture: Capture actual SIP messages with sngrep/Wireshark
  2. Test Suite: Test calls with various header combinations
  3. Edge Cases: Test missing headers, malformed values, very long values
  4. Provider Testing: Test with provider before production
  5. Regression Testing: Re-test after PBX upgrades

Troubleshooting

Custom Headers Not Appearing in Outbound

Problem: Configured custom headers not in outbound INVITE

Diagnostics:

1. Verify Configuration:

Check: Settings > Trunks > [Trunk] > SIP Headers > Outbound
Expected: X-Custom-Header: value
Status: Enabled

2. Capture SIP Messages:

Tool: sngrep or Wireshark
Filter: Outbound INVITE to provider
Search: X-Custom-Header
Result: Present or missing?

3. Check Direction:

Configuration: Direction = Outbound
Test: Making outbound call (not inbound)
Verify: Testing correct direction

4. Check Trunk:

Configuration: Applied to Trunk A
Test: Call goes through Trunk B
Problem: Headers on wrong trunk
Fix: Apply to correct trunk or all trunks

5. Header Name Validation:

Valid: X-Custom-Header
Invalid: Custom Header (space not allowed)
Invalid: Custom@Header (@ not allowed)
Valid characters: Letters, numbers, hyphen

6. SIP Proxy Stripping:

Your PBX: Sends X-Custom-Header
SIP Proxy: Strips unknown headers
Provider: Never receives it

Test: Capture at multiple points
Fix: Configure proxy to allow headers

7. Provider Restrictions:

Some providers: Block X-* headers
Reason: Security policy
Check: Provider documentation
Alternative: Use allowed headers (Contact, From)

Debug Mode

Enable SIP debug logging. Shows exactly which headers are sent in INVITE. Essential for troubleshooting.

Expected Inbound Headers Missing

Problem: Provider should send headers, but PBX doesn't see them

Diagnostics:

1. Capture Inbound INVITE:

Tool: sngrep, Wireshark, or PBX SIP debug
Capture: Inbound INVITE from provider
Search: Expected header (e.g., P-Asserted-Identity)
Result: Is it in the message?

2. Provider Actually Sends It?:

Question: Does provider actually send this header?
Check: Provider documentation
Ask: Provider support
Test: Make call, capture traffic

3. SIP Proxy Stripping:

Provider: Sends header
SIP Proxy: Strips it (firewall, SBC, etc.)
Your PBX: Never receives it

Test: Capture before and after proxy
Fix: Configure proxy to forward headers

4. Header Parsing:

Header present: P-Asserted-Identity: <tel:+15551234567>
PBX config: Looking for "P-Asserted-Id" (typo)
Result: Not recognized

Fix: Correct header name in config

5. Case Sensitivity:

Provider sends: X-Custom-Header
PBX looks for: x-custom-header
System: Case-sensitive header matching
Result: Not found

Fix: Match exact case, or make case-insensitive

6. Multi-Line Headers:

Header spanning multiple lines:
  X-Custom-Header: value1;
    param1=foo;param2=bar

Parsing: May not handle multi-line correctly
Result: Value truncated or parsing fails

Fix: Robust parsing logic

7. Encrypted SIP:

Using TLS: Can't capture with Wireshark
Need: PBX-level SIP debug logging
Enable: SIP debug in PBX
Review: Logs show decrypted headers

Provider Coordination

If expecting specific headers from provider, coordinate with their support to verify they're actually sending them.

Headers Present but Values Incorrect

Problem: Headers exist but contain unexpected values

Scenario 1: Variable Not Expanded:

Configuration: X-Extension: ${EXTEN}
Expected: X-Extension: 2001
Actual: X-Extension: ${EXTEN}

Problem: Variable not expanded (literal string)
Fix: Verify variable expansion syntax for your PBX

Scenario 2: Empty Value:

Configuration: X-Account-Code: ${ACCOUNT_CODE}
Expected: X-Account-Code: SALES-001
Actual: X-Account-Code: 

Problem: Variable ${ACCOUNT_CODE} not set
Fix: Set variable before adding header

Scenario 3: Truncated Value:

Configuration: X-Long-Value: [300 character string]
Expected: Full 300 characters
Actual: First 128 characters only

Problem: Header value length limit
Fix: Shorten value or split into multiple headers

Scenario 4: Special Characters Escaped:

Configuration: X-Name: John's Phone
Expected: X-Name: John's Phone
Actual: X-Name: John%27s Phone

Problem: Special characters URL-encoded
Fix: Decode on receiving end, or avoid special chars

Scenario 5: Wrong Variable:

Configuration: X-Caller: ${CALLERID(num)}
Expected: X-Caller: +15551234567
Actual: X-Caller: 2001

Problem: Using wrong variable (extension instead of caller ID)
Fix: Use correct variable for outbound caller ID

Scenario 6: Dynamic Value Not Updated:

Call 1: X-Customer-ID: 67890 (correct)
Call 2: X-Customer-ID: 67890 (should be different customer)

Problem: Variable not updated between calls
Fix: Ensure variable cleared/updated per call

Testing Variable Expansion:

Test call with known values:
  Extension: 2001
  Caller ID: +15551234567
  Account Code: SALES

Configure headers:
  X-Extension: ${EXTEN}
  X-Caller-ID: ${CALLERID(num)}
  X-Account: ${ACCOUNT_CODE}

Verify in capture:
  X-Extension: 2001 ✓
  X-Caller-ID: +15551234567 ✓
  X-Account: SALES ✓

Test Thoroughly

Always test variable expansion with actual calls. Different PBX systems use different syntax for variables.

Provider Rejects Calls Due to Headers

Problem: Calls fail when custom headers added

Scenario 1: Unknown Header Rejection:

Your PBX: Sends X-Custom-Header: value
Provider: "481 Call/Transaction Does Not Exist"
Reason: Provider strict SIP validation, rejects unknown headers

Fix: Remove custom header, or contact provider to whitelist

Scenario 2: Malformed Header:

Header: X-Custom: value with spaces
Provider: "400 Bad Request - Malformed Header"
Reason: Header value has syntax error

Fix: Encode spaces (%20) or remove

Scenario 3: Header Length Limit:

Header: X-Long-Value: [500 character value]
Provider: "513 Message Too Large"
Reason: Total message size exceeds provider limit

Fix: Shorten header values, remove unnecessary headers

Scenario 4: Duplicate Headers:

Your PBX:
  P-Asserted-Identity: <tel:+15551234567>
  P-Asserted-Identity: <sip:[email protected]>

Provider: "400 Bad Request - Duplicate PAI"
Reason: Provider doesn't accept multiple PAI headers

Fix: Send only one PAI header

Scenario 5: Conflicting Headers:

Headers:
  From: <sip:[email protected]>
  P-Asserted-Identity: <tel:+15559999999>

Provider: "403 Forbidden - PAI Mismatch"
Reason: PAI doesn't match From, provider suspicious

Fix: Ensure PAI matches From or allowed caller ID

Scenario 6: Security Check Failure:

Header: X-API-Key: wrong_key
Provider: "401 Unauthorized"
Reason: Provider validates X-API-Key header

Fix: Use correct API key from provider

Debugging Steps:

  1. Capture SIP 4xx/5xx response from provider
  2. Note error code and reason phrase
  3. Identify which header causing issue
  4. Test without that header
  5. Contact provider if unclear

Provider Whitelist Approach:

Contact provider:
  - Request whitelist of allowed custom headers
  - Only send headers on whitelist
  - Avoid rejection

Result: Provider accepts calls

Provider Coordination

Always coordinate custom headers with provider. Many providers have strict SIP validation that rejects unknown or malformed headers.


Next Steps