FIX Session Layer Explained
The session layer makes a FIX connection reliable: every message is numbered, nothing is lost or processed twice, and a connection that dies is detected. It is the same in every FIX version, and from FIX 5.0 it is a separate protocol called FIXT.1.1.
Sessions, initiators and acceptors
- A session is identified by BeginString (8), SenderCompID (49) and TargetCompID (56). It outlives any single TCP connection: a session can be logged on and off many times a day and keeps its sequence numbers across reconnects.
- The initiator opens the TCP connection and sends the first Logon, usually the client. The acceptor listens, usually the broker or venue.
- Seven session (administrative) messages run the session; everything else is an application message.
| 35 | Message | Purpose |
|---|---|---|
| A | Logon | Starts the session and agrees the heartbeat interval. |
| 0 | Heartbeat | Shows the connection is alive; answers a TestRequest. |
| 1 | TestRequest | Asks the other side for a Heartbeat. |
| 2 | ResendRequest | Asks for missed messages by sequence number. |
| 4 | SequenceReset | Skips sequence numbers (GapFill) or forces a new number (Reset). |
| 3 | Reject | Refuses a message that breaks the FIX rules. |
| 5 | Logout | Ends the session, with an optional reason. |
Logon
The initiator sends Logon (35=A) with EncryptMethod (98) (0) and HeartBtInt (108). The acceptor checks the CompIDs, the sequence number and any credentials, then answers with its own Logon. Only then may application messages flow.
A FIX 4.4 logon with a 30-second heartbeat interval.
1. Initiator: Logon
8=FIX.4.4|9=70|35=A|49=BUYSIDE|56=SELLSIDE|34=1|52=20261020-07:00:00.000|98=0|108=30|10=075|
2. Acceptor: Logon response
8=FIX.4.4|9=70|35=A|49=SELLSIDE|56=BUYSIDE|34=1|52=20261020-07:00:00.006|98=0|108=30|10=081|
SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.
Open this example in the parserIf the Logon is refused, the acceptor sends a Logout with a reason in Text (58), or simply closes the connection. See Logon rejected.
Heartbeats and TestRequest
- Each side sends a Heartbeat (35=0) whenever it has sent nothing for HeartBtInt (108) seconds. Any other message resets the timer.
- If a side hears nothing for a little longer than the interval, it sends a Test Request (35=1) with a TestReqID (112). The answer must be a Heartbeat carrying the same TestReqID.
- If that answer does not come, the connection is considered dead and is dropped. The session itself is not reset: on reconnect, sequence numbers carry on.
A TestRequest and the Heartbeat that answers it.
1. Acceptor: TestRequest
8=FIX.4.4|9=74|35=1|49=SELLSIDE|56=BUYSIDE|34=2|52=20261020-07:01:06.000|112=TEST-070106|10=155|
2. Initiator: Heartbeat echoing TestReqID
8=FIX.4.4|9=74|35=0|49=BUYSIDE|56=SELLSIDE|34=2|52=20261020-07:01:06.003|112=TEST-070106|10=157|
SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.
Open this example in the parserSequence numbers
- Every message carries MsgSeqNum (34), counted separately in each direction and starting at 1. Each side stores the next number it will send and the next it expects.
- A number higher than expected means messages are missing: the receiver asks for them with a ResendRequest.
- A number lower than expected, without 43=Y, means the sender lost its state. The receiver logs out with "MsgSeqNum too low".
- Both counters go back to 1 at the agreed reset time, or when a Logon carries 141=Y. From FIX 4.4, NextExpectedMsgSeqNum (789) on the Logon lets each side state what it expects next.
Resend and gap fill
The receiver sends Resend Request (35=2) with BeginSeqNo (7) (first missing number) and EndSeqNo (16) (0 for "to the end"). The sender replays application messages with their original numbers, 43=Y and OrigSendingTime (122), and covers session messages with a Sequence Reset (35=4) in GapFill mode (123=Y).
The initiator reconnects and sees the acceptor's Logon at 9 while it expected 5. Message 5 was an Execution Report; 6 to 8 were heartbeats and 9 is the Logon itself.
1. Acceptor: Logon with MsgSeqNum 9
8=FIX.4.4|9=70|35=A|49=SELLSIDE|56=BUYSIDE|34=9|52=20261020-08:00:00.006|98=0|108=30|10=090|
2. Initiator: ResendRequest from 5
8=FIX.4.4|9=67|35=2|49=BUYSIDE|56=SELLSIDE|34=4|52=20261020-08:00:00.010|7=5|16=0|10=173|
3. Acceptor: message 5 replayed
8=FIX.4.4|9=174|35=8|49=SELLSIDE|56=BUYSIDE|34=5|52=20261020-08:00:00.015|43=Y|122=20261020-07:20:11.402|37=OID-9005|11=ORD-2005|17=EXEC-9005-2|150=4|39=4|55=MSFT|54=1|38=300|151=0|14=0|6=0|10=204|
4. Acceptor: GapFill over 6 to 9
8=FIX.4.4|9=101|35=4|49=SELLSIDE|56=BUYSIDE|34=6|52=20261020-08:00:00.016|43=Y|122=20261020-08:00:00.016|123=Y|36=10|10=126|
Heartbeats and the Logon (9) are not replayed: the GapFill covers them and moves the expected number to 10, the next message the acceptor will send.
SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.
Open this example in the parserSession Reject
A message that breaks the FIX rules (missing required field, bad format, wrong CompID) gets a Reject (35=3) with RefSeqNum (45), RefTagID (371), RefMsgType (372) and SessionRejectReason (373). The rejected message still used its sequence number. Valid messages that the application cannot act on get a Business Message Reject (35=j) instead.
Logout
Either side ends the session by sending Logout (35=5). The other side answers with its own Logout and the initiator closes the connection. A Logout sent because of an error carries the reason in Text (58).
A normal end of day.
1. Initiator: Logout
8=FIX.4.4|9=60|35=5|49=BUYSIDE|56=SELLSIDE|34=412|52=20261020-17:00:00.000|10=140|
2. Acceptor: Logout response
8=FIX.4.4|9=61|35=5|49=SELLSIDE|56=BUYSIDE|34=1880|52=20261020-17:00:00.004|10=203|
SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.
Open this example in the parserQuestions
- Are sequence numbers reset when the TCP connection drops?
- No. A session keeps its sequence numbers across reconnects. They are reset only at the agreed schedule or by a Logon with ResetSeqNumFlag (141=Y).
- Are heartbeats replayed during a resend?
- No. Session messages such as Heartbeat, TestRequest and Logon are covered by a SequenceReset-GapFill instead of being sent again.
- Who sends the first Logon?
- The initiator, the side that opened the TCP connection. The acceptor answers with its own Logon.