Session Message Types
Session Message Types
Client and server use the following session messages:
- Logon (35=A): Opens and authenticates a session.
- Logout (35=5): Closes a session.
- Heartbeat (35=0): Keeps the session alive and answers a TestRequest.
- TestRequest (35=1): Requests a Heartbeat.
- ResendRequest (35=2): Requests missed messages by sequence number.
- Reject (35=3): Session-level reject of a message that failed session validation.
- SequenceReset (35=4): Gap-fills the sequence number.
Fill Recovery Message Types
Fill Recovery Message Types
Order entry and drop copy only. Use these application messages to recover missed fills:
- LastExecIDRequest (35=F1): Client request for the latest
ExecID. - LastExecID (35=F2): System response to F1.
- EventResendRequest (35=F3): Client request to replay fills in an
ExecIDrange. - EventResendComplete (35=F4): System response to a successful F3 request.
- EventResendReject (35=F5): System response to an unsuccessful F3 request.
Gateway comparison
Logon (35=A)
The Logon message opens a session. The gateway authenticates the API key in SenderCompID (49), the passphrase, and an HMAC signature, then confirms with a Logon that carries the heartbeat interval in use. If authentication fails, the gateway rejects the Logon and ends the session.
The API key is carried in the header field SenderCompID (49), not in a Logon body field. To reset sequence numbers, send
ResetSeqNumFlag (141) = Y on Logon.
Logon signature
Compute the signature as follows:- Build the payload by concatenating, without delimiters:
SendingTime + SenderCompID + TargetCompID + Passphrase.SendingTimeis the Logon’s SendingTime (52) formatted as a UTC timestamp with millisecond precision:YYYYMMDD-HH:MM:SS.sss. If you send SendingTime (52) with finer precision, sign the value truncated to milliseconds.SenderCompIDis the exact value of tag 49: your API key. Market data only: include the.<tag>suffix when you send a tagged SenderCompID.TargetCompIDis Order entry:CPMOE; Market data:CPMMD; Drop copy:CBPMDC.Passphraseis the value of Password (554).
- Encode the payload as UTF-8.
- Decode your API secret with standard Base64.
- Compute HMAC-SHA256 over the payload bytes, keyed with the decoded secret.
- Encode the 32-byte result with standard padded Base64 (exactly 44 characters) and send it in
Text (58).
SendingTime (52) on the Logon must be within 30 seconds of the gateway’s clock, in either direction. A Logon outside this window is rejected.
- The API key exists, and the passphrase and signature are valid for it.
- The API key’s user is active and has the gateway’s permission: Order entry:
TRADE; Market data:MARKET_DATA; Drop copy:DROP_COPY. - The API key’s firm or FCM scope resolves. For a firm-level key, both the firm and its FCM must be active. For an FCM-level key, the FCM must be active.
- Market data only: the API key has not reached its maximum number of concurrent sessions.
Sessions per API key
Order entry and drop copy: one session per API key. A new Logon with the same API key replaces the existing session, which receives Logout (35=5) withText (58) = replaced by newer connection. Tagged SenderCompIDs such as apiKey.01 are not supported. On order entry, a replaced session does not trigger cancel on disconnect.
Multiple sessions per API key
Market data only. You can open several concurrent sessions with one API key by appending a session tag to the key in SenderCompID (49):- Format:
<apiKey>.<tag>, where the API key is the full 16-character key, the delimiter is., and the tag is a two-digit index from01to99. Example:AB12CD34EF56GH78.01. - Each distinct
<apiKey>.<tag>is an independent session with its own sequence numbers. - Logging on again with the same
<apiKey>.<tag>takes over that session. The replaced session receives Logout (35=5) withText (58) = replaced by newer connection. - A non-canonical tag is rejected at Logon, for example
1,00,01.2, or an empty tag. - A bare API key without a tag is also accepted and counts as one session.
- All sessions of one key share that key’s
MARKET_DATApermission. - Each API key has a configured maximum number of concurrent sessions. A Logon that would exceed it is rejected.
Sign the full SenderCompID you send in tag 49, including the
.<tag> suffix. A signature computed over the bare API key fails when the SenderCompID is tagged.Logout (35=5)
Closes a session. Either side can send it.Heartbeat (35=0)
Keeps the session alive. Answers a TestRequest with the sameTestReqID (112).
The gateway sends a Heartbeat when it has sent nothing for most of the heartbeat interval. If the gateway receives nothing from you for one interval, it sends a TestRequest. If it receives nothing for two intervals, it ends the session.
TestRequest (35=1)
Requests a Heartbeat carrying the sameTestReqID (112). Either side can send it.
ResendRequest (35=2)
Requests messagesBeginSeqNo (7) to EndSeqNo (16).
The gateways answer a ResendRequest differently.
Order entry and drop copy gap fill
Order entry and drop copy only. The gateway answers with one SequenceReset (35=4) gap fill and does not retransmit any messages:
An invalid ResendRequest is ignored. No SequenceReset or reject is sent.
A ResendRequest never returns execution reports or settlement reports on order entry or drop copy. To recover missed fills, use LastExecIDRequest (35=F1) and EventResendRequest (35=F3). Other order entry reports (new, cancel, reject, mass cancel, settlement) cannot be recovered after a disconnect.
Market data retransmission
Market data only. The gateway resends the requested range from its record of messages sent on your session:- Application messages are retransmitted with their original
MsgSeqNum (34),PossDupFlag (43) = Y,OrigSendingTime (122)set to the originalSendingTime (52), and a newSendingTime (52). - Session messages in the range are replaced by a SequenceReset (35=4) with
GapFillFlag (123) = YandPossDupFlag (43) = Y. - An
EndSeqNo (16)of0, or beyond the last message sent, means through the last message sent. - A
BeginSeqNo (7)at or beyond the gateway’s next outbound sequence number is rejected with Reject (35=3),SessionRejectReason (373) = 5,Text (58) = invalid resend requests. - An
EndSeqNo (16)less thanBeginSeqNo (7)is rejected with Reject (35=3),SessionRejectReason (373) = 5,Text (58) = endSeqNo is less than beginSeqNo. - Messages that are no longer retained are not resent.
Reject (35=3)
Session-level reject of a message that failed session validation. Either side can send it.SendingTime accuracy
An application message whose SendingTime (52) differs from the gateway’s clock by more than the limit is rejected with Reject (35=3) andSessionRejectReason (373) = 10 (SendingTime accuracy problem). The limit is Order entry: 60 seconds; Market data: 60 seconds; Drop copy: 5 seconds. Session messages are not checked.
SequenceReset (35=4)
Resets or gap-fills the sequence number toNewSeqNo (36). Either side can send it.
Fill recovery
Order entry and drop copy only. After a reconnect, use LastExecIDRequest (35=F1) to check whether you missed fills, then EventResendRequest (35=F3) to replay them. Market data has no fill recovery.ExecID (17) values increase over time. Compare them numerically. Values are not consecutive.
LastExecIDRequest (35=F1)
Requests the latestExecID: Order entry: of your newest fill; Drop copy: sent for your scope. The request has no age limit. The response is always LastExecID (35=F2).
LastExecID (35=F2)
Sent in response to LastExecIDRequest.- Order entry: if this
ExecIDis greater than the lastExecIDyou processed, you missed fills. TheExecIDcan be older than the replay window of EventResendRequest (35=F3). A fill reported here is not necessarily replayable. - Drop copy: when no recent report is available, the gateway returns the
ExecIDof the newest stored fill for your scope, however old. The value marks a position in theExecIDsequence. It can be theExecIDof a report that is not a fill, or of the other side of a fill. Use it as a lower bound forBeginExecId (22003), not as proof that a fill can be resent.
EventResendRequest (35=F3)
Requests replay of fills (150=F) in an ExecID range: Order entry: fills of your API key; Drop copy: fills for your scope. Replayed fills are sent as ExecutionReports in ascending ExecID order, followed by EventResendComplete (35=F4) or EventResendReject (35=F5).
Only fills are replayed: ExecutionReports with
150=F. New, pending new, canceled, expired, and rejected reports, cancel-on-disconnect reports, OrderCancelReject, OrderMassCancelReport, and MarketSettlementReport are not replayed. The replay window is Order entry: 30 minutes; Drop copy: 24 hours. Fills older than the window are not replayed. A BeginExecId before the oldest fill in the window is rejected with 22006=1; it is not moved forward to that fill, and no later fills are sent.- Replayed fills carry
PossResend (97) = Y.PossDupFlag (43)is not set. Use97, notTransactTime, to tell replayed reports from live ones. - Replayed fills have new
MsgSeqNum (34)andSendingTime (52)values and keep their originalExecID (17)andTransactTime (60).- Order entry: the report body is unchanged, including the
Symbol (55)at the time of the trade. - Drop copy: order fields are unchanged. Parties (453) reflect firm, FCM, and user details at the time of the resend.
- Order entry: the report body is unchanged, including the
- One replay runs at a time: Order entry: per API key; Drop copy: per scope, across all sessions in that scope.
- If a replay fails after fills were sent, EventResendReject (35=F5) replaces EventResendComplete (35=F4). When a replayed fill cannot be delivered, the gateway stops and sends
22006=5. Do not advance past the last fill you received; request the range again. - Order entry: fills inside the window can still be unavailable for replay. Do not use Event Resend as a system of record. Request a replay promptly after you reconnect, starting from your last processed
ExecID. - Order entry: if your API key no longer has
TRADEpermission or its scope no longer resolves, the request is rejected with BusinessMessageReject (35=j). Drop copy: the gateway ends a session whose authorization no longer holds; see Drop Copy.
EventResendComplete (35=F4)
Sent after all replayed fills of a successful request.EventResendReject (35=F5)
Sent when an EventResendRequest cannot be completed. Except for some22006=5 cases, no fills are sent before an EventResendReject.
Cancel on disconnect
Order entry only. Cancel on disconnect is set per session withCancelOrdersOnDisconnect (8013) on Logon (35=A). The scope is fixed for the life of the session.
- Orders are canceled only when the client disconnects. When a new Logon with the same API key replaces the session, no orders are canceled.
- Each canceled order is reported as Canceled with
378=1andText (58) = CLIENT_DISCONNECT. These reports are delivered only to a session that is connected when the cancel happens, and are not replayed by EventResendRequest. - Send the scope you want on every Logon.