7.1 The headers in every request
Six headers are the minimum for any request; an INVITE also needs Contact.
“A valid SIP request formulated by a UAC MUST, at a minimum, contain the following header fields: To, From, CSeq, Call-ID, Max-Forwards, and Via; all of these header fields are mandatory in all SIP requests.”Read the section ↗
| Header | Job | Changes on the way? |
|---|---|---|
| Via | The path back for responses; the top branch names the transaction | Each hop adds one; the next hop may add received and rport |
| Max-Forwards | Stops loops | Each proxy subtracts 1 |
| From | The sender, and the sender’s tag | No (a B2BUA writes a new one) |
| To | The target, and the other side’s tag | The UAS adds its tag |
| Call-ID | Groups the messages of one call or one registration | No (a B2BUA writes a new one) |
| CSeq | Orders the requests from one side, and names the method | +1 for each new request from that side |
| Contact (INVITE) | Where to send the next requests in the dialog | Rewritten by SBCs and NAT fixes |
“It consists of an integer that is decremented by one at each hop. If the Max-Forwards value reaches 0 before the request reaches its destination, it will be rejected with a 483(Too Many Hops) error response.”Read the section ↗
The header reference below covers these and about forty more. Search for a header, or pick a group, to see who adds, changes, and removes it.
Header reference
47 headers: what they mean, who touches them
- +Adds
- ~Changes
- −Removes
Every request
Routing
Identity and privacy
Authentication
Capabilities
Body
Session and timers
Events and transfer
Information
Viacompact: v
Every requestin every request
Records the path of the request. Responses follow the Via headers back, and the top branch identifies the transaction.
- Adds
- Every element that sends or forwards a request, at the top
- Changes
- The next hop adds received and rport
- Removes
- Each element removes its own Via from the response
Via: SIP/2.0/UDP 192.0.2.10:5060;branch=z9hG4bK74bf9;rportRFC 3261 §20.42 ↗
Watch the headers travel
Here is one INVITE on its way from Alice’s phone, behind a NAT router, through Proxy A, an SBC, and Proxy B to Bob’s phone. Each column is one hop; each marked cell is a change at that hop. Turn on Show only the headers that change to see what each element does.
Header journey
One INVITE, four hops: what each element changes
- +Added here
- ~Changed here
- −Removed here
| Header | Hop 1Alice → Proxy A | Hop 2Proxy A → SBC | Hop 3SBC → Proxy B | Hop 4Proxy B → Bob |
|---|---|---|---|---|
| sip:bob@biloxi.example | sip:bob@biloxi.example | sip:bob@biloxi.example | ~sip:bob@203.0.113.20:5060 | |
| SIP/2.0/UDP 192.168.1.20:5060;branch=z9hG4bK74bf9;rport | ~SIP/2.0/UDP 198.51.100.10:5060;branch=z9hG4bKpa4790 SIP/2.0/UDP 192.168.1.20:5060;branch=z9hG4bK74bf9;received=192.0.2.10;rport=40112 | ~SIP/2.0/UDP 198.51.100.200:5060;branch=z9hG4bK-sbc-5b2e | ~SIP/2.0/UDP 203.0.113.10:5060;branch=z9hG4bKpb721e SIP/2.0/UDP 198.51.100.200:5060;branch=z9hG4bK-sbc-5b2e | |
| 70 | ~69 | ~68 | ~67 | |
| Alice <sip:alice@atlanta.example>;tag=9fxced76sl | Alice <sip:alice@atlanta.example>;tag=9fxced76sl | ~Alice <sip:alice@atlanta.example>;tag=sbc-3c9d0f | Alice <sip:alice@atlanta.example>;tag=sbc-3c9d0f | |
| Bob <sip:bob@biloxi.example> | Bob <sip:bob@biloxi.example> | Bob <sip:bob@biloxi.example> | Bob <sip:bob@biloxi.example> | |
| 3848276298220188511@192.168.1.20 | 3848276298220188511@192.168.1.20 | ~9e7d6c5b4a21@198.51.100.200 | 9e7d6c5b4a21@198.51.100.200 | |
| 1 INVITE | 1 INVITE | 1 INVITE | 1 INVITE | |
| <sip:alice@192.168.1.20:5060> | <sip:alice@192.168.1.20:5060> | ~<sip:alice@198.51.100.200:5060> | <sip:alice@198.51.100.200:5060> | |
| <tel:+14045550101> | −removed | — | — | |
| timer, 100rel | timer, 100rel | timer, 100rel | timer, 100rel | |
| 1800 | 1800 | 1800 | ~900 | |
| 90 | 90 | 90 | 90 | |
| INVITE, ACK, CANCEL, BYE, OPTIONS, UPDATE, REFER | INVITE, ACK, CANCEL, BYE, OPTIONS, UPDATE, REFER | INVITE, ACK, CANCEL, BYE, OPTIONS, UPDATE, REFER | INVITE, ACK, CANCEL, BYE, OPTIONS, UPDATE, REFER | |
| Linphone/5.2 | Linphone/5.2 | −removed | — | |
| application/sdp | application/sdp | application/sdp | application/sdp | |
| 162 | 162 | ~158 | 158 | |
| alice 2890844526 2890844526 IN IP4 192.168.1.20 | alice 2890844526 2890844526 IN IP4 192.168.1.20 | ~sbc 1700000 1700000 IN IP4 198.51.100.200 | sbc 1700000 1700000 IN IP4 198.51.100.200 | |
| IN IP4 192.168.1.20 | IN IP4 192.168.1.20 | ~IN IP4 198.51.100.200 | IN IP4 198.51.100.200 | |
| — | +<sip:proxy.atlanta.example;lr> | −removed | +<sip:proxy.biloxi.example;lr> | |
| — | +"Alice" <sip:alice@atlanta.example>, <tel:+14045550101> | "Alice" <sip:alice@atlanta.example>, <tel:+14045550101> | "Alice" <sip:alice@atlanta.example>, <tel:+14045550101> |
Via
Records the path of the request. Responses follow the Via headers back, and the top branch identifies the transaction. RFC 3261 §20.42 ↗
- Alice → Proxy Aunchanged
SIP/2.0/UDP 192.168.1.20:5060;branch=z9hG4bK74bf9;rport - Proxy A → SBCchanged
SIP/2.0/UDP 198.51.100.10:5060;branch=z9hG4bKpa4790 SIP/2.0/UDP 192.168.1.20:5060;branch=z9hG4bK74bf9;received=192.0.2.10;rport=40112 - SBC → Proxy Bchanged
SIP/2.0/UDP 198.51.100.200:5060;branch=z9hG4bK-sbc-5b2e - Proxy B → Bobchanged
SIP/2.0/UDP 203.0.113.10:5060;branch=z9hG4bKpb721e SIP/2.0/UDP 198.51.100.200:5060;branch=z9hG4bK-sbc-5b2e
Call flow · the same INVITE, hop by hop
One INVITE, four hops
- SIP
Alice's phone builds the INVITE behind a NAT router. It asks for its phone number as identity.
All steps as text
- Alice → Proxy A: INVITE. Alice's phone builds the INVITE behind a NAT router. It asks for its phone number as identity.
- Proxy A → SBC: INVITE. Proxy A records the NAT address in Alice's Via, asserts Alice's identity, and adds Record-Route.
- SBC → Proxy B: INVITE (outer side). The SBC starts a new INVITE. It hides every inner address and keeps the asserted identity for a trusted peer.
- Proxy B → Bob: INVITE. Proxy B routes to Bob's Contact, adds Record-Route, and lowers the session timer to its own limit.
7.2 Tags
A tag is a random string in From and To. The UAC adds its tag to From in the first request; the UAS adds its tag to To in its response. Together with the Call-ID, the two tags name the dialog.
“It serves as a general mechanism to identify a dialog, which is the combination of the Call-ID along with two tags, one from each participant in the dialog.”Read the section ↗
Why two tags, and not just the Call-ID? Because a forked INVITE can be answered by several phones. Each one adds its own To tag, so the caller can tell the dialogs apart:
“This also explains the need for the two-sided dialog identifier; without a contribution from the recipients, the originator could not disambiguate the multiple dialogs established from a single request.”Read the section ↗
Every request inside the dialog repeats both tags, in the right places. From the caller’s side, From carries the caller’s tag; from the callee’s side — for example in Bob’s BYE — the two swap: From carries Bob’s tag, To carries Alice’s.
7.3 Via parameters
| Parameter | Added by | Means |
|---|---|---|
branch |
The sender of the request | Names the transaction. Starts with z9hG4bK (Module 8). |
received |
The next hop | The source IP address the packet really came from, if it differs from the Via |
rport |
The sender adds it empty; the next hop fills it | The source port the packet came from: send the response there (RFC 3581) |
maddr |
Rarely used | A multicast or override address for responses |
In the journey above, Alice’s phone writes its private address in Via and adds an empty rport. Proxy A fills in what it really saw: received=192.0.2.10;rport=40112 — the public address and port of the NAT router (Module 2).
“If the host portion of the "sent-by" parameter contains a domain name, or if it contains an IP address that differs from the packet source address, the server MUST add a "received" parameter to that Via header field value.”Read the section ↗
“If this Via header field value contains an "rport" parameter with no value, it MUST set the value of the parameter to the source port of the request.”Read the section ↗
7.4 Contact parameters
| Parameter | Used in | Means |
|---|---|---|
expires |
REGISTER and its 200 OK | How long this binding lasts, in seconds |
q |
REGISTER, 3xx | Preference among several Contacts, 0 to 1 |
+sip.instance |
REGISTER | A permanent, unique id of the device (RFC 5626) |
reg-id |
REGISTER | Which of the device’s connections this registration uses (RFC 5626) |
Contact: <sip:alice@192.0.2.10:5060;transport=tcp>;expires=3600;q=1.0
;+sip.instance="<urn:uuid:00000000-0000-1000-8000-000A95A0E128>";reg-id=1
“When a UA registers multiple times, each for a different flow, each concurrent registration gets a unique reg-id value.”Read the section ↗
7.5 URI parameters
URI parameters live inside the angle brackets (Module 4):
| Parameter | Means |
|---|---|
transport=tcp |
Use this transport to reach the URI |
lr |
Loose router: this proxy follows RFC 3261 routing (Module 10) |
user=phone |
The user part is a telephone number |
maddr |
Send to this address instead of the host — avoid; use Route |
ob |
SIP Outbound: keep using the connection this request came on |
7.6 Routing headers
Record-Route is added by a proxy that wants to see the rest of the dialog. The UAs turn the list into a route set, and later requests carry it as Route headers. Each proxy removes its own Route entry. Module 10 explains the details; for now, notice in the journey that Proxy A and Proxy B add Record-Route — and that the SBC removes Proxy A’s entry to hide the inner network.
7.7 Identity and privacy
The From header is written by the caller’s phone, so it proves nothing. A network that has authenticated the caller says so in P-Asserted-Identity (PAI):
“A proxy server which handles a message can, after authenticating the originating user in some way (for example: Digest authentication), insert such a P-Asserted-Identity header field into the message and forward it to other trusted proxies.”Read the section ↗
- The phone may suggest which of its identities to use with P-Preferred-Identity. The first trusted proxy removes it and adds PAI.
- PAI is trusted only inside a trust domain — between elements that have agreed to trust each other, such as a carrier and its customers’ SBCs. A proxy that receives PAI from an untrusted source must replace or remove it:
“If the proxy received the message from an element that it does not trust and there is a P-Asserted-Identity header present which contains a SIP or SIPS URI, the proxy MUST replace that SIP or SIPS URI with a single SIP or SIPS URI or remove this header field.”Read the section ↗
- Privacy asks the network to hide things.
Privacy: idasks the network to remove PAI before the call leaves the trust domain; the caller’s phone also writes an anonymous From.
From: "Anonymous" <sip:anonymous@anonymous.invalid>;tag=1928301774
P-Asserted-Identity: "Alice" <sip:alice@atlanta.example>, <tel:+14045550101>
Privacy: id
“The presence of this privacy type in a Privacy header field indicates that the user would like the Network Asserted Identity to be kept private with respect to SIP entities outside the Trust Domain with which the user authenticated.”Read the section ↗
“The following SIP headers, when generated by a user agent, can directly or indirectly reveal identity information about the originator of a message: From, Contact, Reply-To, Via, Call-Info, User-Agent, Organization, Server, Subject, Call-ID, In-Reply-To and Warning.”Read the section ↗
7.8 Redirect history: Diversion and History-Info
When a call is forwarded, the new target often needs to know who was called first and why the call moved — a voicemail system needs to know whose mailbox to open.
- Diversion (RFC 5806) answers both questions in one entry per forwarding. The RFC is Historic, but many carriers and PBXs still use it.
“Question 1: From whom was the request diverted? Question 2: Why was the request diverted?”Read the section ↗
Diversion: <sip:+14045550102@atlanta.example>;reason=no-answer;counter=1
- History-Info (RFC 7044) is the standard replacement. Each element that forwards the request adds an entry, with an index that shows the order and a parameter that shows how the target changed:
rc(same user, new Contact),mp(another user), ornp(no change).
History-Info: <sip:bob@biloxi.example>;index=1
History-Info: <sip:bob@biloxi.example>;np=1;index=1.1
History-Info: <sip:bob@203.0.113.20>;index=1.1.1;rc=1.1
“This request history information allows the receiving application to obtain information about how and why the SIP request arrived at the application/user.”Read the section ↗
7.9 Session timers
SIP has no built-in keepalive for a call. If a BYE is lost, or a phone crashes, the proxies and the other phone may keep the call open for hours. Session timers (RFC 4028) fix this: one side refreshes the session with a re-INVITE or an UPDATE, and if no refresh comes, both sides end the call.
“If a session refresh request is not received before the interval passes, the session is considered terminated. Both UAs are supposed to send a BYE, and call stateful proxies can remove any state for the call.”Read the section ↗
| Header | Means |
|---|---|
Supported: timer |
“I support session timers.” |
Session-Expires: 1800;refresher=uac |
The session interval in seconds, and who refreshes. A proxy may lower it. |
Min-SE: 90 |
The shortest interval this element accepts. Never below 90 seconds. |
422 Session Interval Too Small |
The interval is shorter than the receiver’s Min-SE. The response carries the Min-SE to retry with. |
“However, 1800 seconds (30 minutes) is RECOMMENDED as the value for the Session-Expires header field.”Read the section ↗
The refresher sends its refresh halfway through the interval:
“It is RECOMMENDED that this refresh be sent once half the session interval has elapsed.”Read the section ↗
In the journey above, Proxy B lowers Session-Expires from 1800 to 900: it wants to know within 15 minutes if a call is dead.
7.10 Other headers you will meet
| Header | Says |
|---|---|
| User-Agent / Server | The software of the UAC / UAS. Often the fastest clue in a trace — and removed by SBCs that hide the topology. |
| Reason | Why a request ends something (Module 6) |
| Warning | Extra detail for a response, such as 304 … "Media type not available" |
| Date | The sender’s clock; registrars send it, and some phones set their clock from it |
| Subject | A short text about the call |
Common mistakes
Changing the From tag or To tag inside a dialog
The tags, with the Call-ID, are the dialog. A request with another tag belongs to no dialog: the other side answers 481, and the call it was meant to change or end stays up.
Broken
Broken: BYE with a changed tag
- SIP
- Error
- ⚠Problem
Alice's phone calls Bob's phone.
All steps as text
- Alice → Bob: INVITE. Alice's phone calls Bob's phone.
- Bob → Alice: 180 Ringing. Bob's phone rings.
- Bob → Alice: 200 OK. Bob answers, at the same moment that Alice decides to hang up.
- Alice → Bob: ACK. Alice's phone confirms the 200 OK. The call is now set up.
- Alice → Bob: BYE. Alice's phone ends the call, but it writes a new To tag into the BYE. Problem: The To tag must be the tag from Bob's 200 OK. With another tag, the BYE matches no dialog.
- Bob → Alice: 481 Call/Transaction Does Not Exist. Bob's phone finds no dialog with these tags. It rejects the BYE, and the call stays up. Problem: Alice's phone thinks the call has ended. Bob's phone still sends media.
Using the same Call-ID for unrelated calls
A phone or script that reuses one Call-ID for every call makes all of them look like one dialog. Registrars, proxies, and analysis tools then merge unrelated calls, reject requests as retransmissions, or answer 481.
Remember: a new Call-ID for every new call. A retry after 401 or 407 keeps the Call-ID; a new call does not.
Trusting From for the caller's identity
Anybody can write anything in From. Billing, emergency services, and call blocking must use an identity that the network verified: P-Asserted-Identity from a trusted peer, or a verified STIR Identity header (Module 28).
Remember: From is a claim. PAI from a trusted peer is an assertion. Accept PAI only from peers you trust.
Not decrementing Max-Forwards
A proxy or a B2BUA that forwards without decrementing Max-Forwards — or resets it to 70 — disables loop protection. A routing loop between two servers then runs until something else breaks, instead of ending with 483 Too Many Hops.
Remember: every proxy subtracts 1. A B2BUA that starts a new request should still carry the received value down, not reset it.
Summary
- Every request has Via, Max-Forwards, From, To, Call-ID, and CSeq; an INVITE also has Contact.
- The From tag and the To tag, with the Call-ID, name a dialog. They never change inside it.
- Via gets
receivedandrportfrom the next hop, so responses find their way back through NAT. - Contact parameters (
expires,q,+sip.instance,reg-id) describe a registration; URI parameters (transport,lr,user=phone,ob) describe how to reach a URI. - P-Asserted-Identity is a verified identity, trusted only inside a trust domain. Privacy: id hides it outside that domain.
- Diversion and History-Info record why a call was forwarded.
- Session-Expires and Min-SE make sure a dead call ends, even when a BYE is lost.