BSL Direct TCP
BSL Direct TCP is the native low-latency order-entry path for market makers and professional quote engines. It is a persistent TCP/TLS session to the Senticore gateway on Hetzner or a dedicated direct host. It is not an HTTPS endpoint and does not run through Cloudflare.
The wire is a recoverable session (protocol v2): server acknowledgements are sequenced, both sides heartbeat, and a dropped connection can be resumed without losing acks. Use it when HTTP request/response overhead, Cloudflare edge variance, or per-request connection setup is visible in your quoting loop.
Discover the endpoint
Start with the connectivity bundle:
GET /api/v1/bsl/connectivity
Use the returned bslTcp object:
{
"bslTcp": {
"enabled": true,
"transport": "tcp_tls",
"host": "bsl.sentico-labs.xyz",
"port": 9001,
"tlsSni": "bsl.sentico-labs.xyz",
"protocol": "senticore-bsl-tcp-v2",
"handshakeBytes": 48,
"messageHeaderBytes": 8,
"compactActionFrameBytes": 192,
"sessionVersion": 2
}
}
bsl.sentico-labs.xyz is a DNS-only record pointing directly at the Senticore
gateway. Do not substitute https://api.sentico-labs.xyz for this field; HTTPS
cannot carry the native TCP frames.
Session flow
- Open a TCP connection to
bslTcp.host:bslTcp.port. - Start TLS with SNI
bslTcp.tlsSni. - Set
TCP_NODELAY. - Send a 48-byte
HandshakeHellooffering session version2. Bytes36..40carry your requested heartbeat cadence (ms, little-endian;0= let the gateway choose). - Read the 48-byte
HandshakeAck. It carries the negotiated session version (bytes8..10), a 16-byte CSPRNG session token (bytes20..36, used for resume), and the granted heartbeat cadence (bytes36..40). A client that offers only the retired v1 receives aHandshakeReject. - Send framed messages with an 8-byte little-endian message header:
u32_le kind
u32_le payload_len
payload bytes
The first production message is usually an AuthSidecar followed by a compact
action frame. The compact single-order frame size is 192 bytes.
Message kinds
| Kind | Value | Direction | Use |
|---|---|---|---|
CompactActionFrame | 1 | Client → gateway | One 192-byte action frame. |
CoreAck | 2 | Gateway → client | Action/batch acknowledgement (sequenced). |
GatewayReject | 3 | Gateway → client | Fast ingress rejection (sequenced). |
AuthSidecar | 4 | Client → gateway | Session/account authentication sidecar. |
CompactFrameGroup | 10 | Client → gateway | Batch/group of compact action frames. |
CoreAckBatch | 11 | Gateway → client | Batch acknowledgement (sequenced). |
ClientHeartbeat | 12 | Client → gateway | Liveness (8-byte u64 send timestamp). |
ServerHeartbeat | 13 | Gateway → client | Liveness on the granted cadence. |
ResendRequest | 14 | Client → gateway | Replay sequenced messages from a sequence. |
SessionResume | 15 | Client → gateway | Resume a prior session after reconnect. |
SessionResumeResult | 16 | Gateway → client | Resume outcome + continue sequence. |
SequencedData | 17 | Gateway → client | Envelope wrapping a per-session sequenced message. |
EndOfSession | 18 | Gateway → client | Graceful end-of-session marker. |
Sequenced responses, gap-fill, and recovery
Every server→client acknowledgement is delivered inside a SequencedData
envelope. The envelope payload is:
u64_le session_seq # per-session, monotone, starts at 1
u32_le inner_kind # e.g. CoreAck=2, GatewayReject=3, CoreAckBatch=11
inner payload bytes # Senticore cold codec (JSON in beta)
- Track
session_seq. If it skips (got > expected), you have a gap: send aResendRequestwithfrom_session_seq = expected. The gateway replays the retained tail verbatim. - Heartbeat on the granted cadence. If the peer goes silent for more than three intervals, treat the session as dead and reconnect.
- After reconnecting and completing a fresh handshake, send
SessionResumewith the previous session token and the highestsession_seqyou processed. The gateway replies withSessionResumeResult(code = 0= accepted) and replays everything after that sequence. If the sequence has aged out of the retransmit window (code = 2), re-snapshot your open orders via REST/FIX order status instead of gap-filling.
The SDKs implement this state machine for you (see below).
Backpressure
The gateway uses bounded internal queues into the sequencing core. When a market
shard or IPC lane cannot accept more work, the correct behavior is a fast
GatewayReject rather than silently aging quotes in a hidden queue.
Important reject families:
| Code | Meaning |
|---|---|
SHARD_BUSY / BackpressureFull | Target market shard or queue is saturated. |
RateLimitExceeded | Session/account/api-key rate limit hit. |
IdempotencyReplay | Duplicate idempotency key within the replay window. |
AuthFailed | Session is missing required institutional credential state. |
SessionViolation | Session-level protocol violation (identity/sequence/mapping). |
NonceReuse | Windowed-nonce replay rejected by the engine. |
MarketUnknown | Market routing failed. |
For market makers, a fast reject is usable signal. Treat it as a reason to widen, pause, or reconnect instead of retrying blindly. The session stays open across rejects.
SDK session clients
The Rust, Python, and TypeScript SDKs ship a transport-free BslTcpSession
state machine that drives the handshake, sequence tracking, gap detection,
heartbeat cadence, and resume for you — you own only the socket.
TypeScript:
cd sdks/typescript
SENTICORE_BSL_TCP_HOST=bsl.sentico-labs.xyz \
SENTICORE_BSL_TCP_PORT=9001 \
SENTICORE_BSL_TCP_TLS_SNI=bsl.sentico-labs.xyz \
npm run build && node dist/examples/bsl-tcp-handshake.js
Python:
cd sdks/python
python -m pip install -e .
SENTICORE_BSL_TCP_HOST=bsl.sentico-labs.xyz \
SENTICORE_BSL_TCP_PORT=9001 \
SENTICORE_BSL_TCP_TLS_SNI=bsl.sentico-labs.xyz \
python examples/bsl_tcp_handshake.py
TLS posture
The gateway terminates TLS with a public CA certificate for
bsl.sentico-labs.xyz; verify the certificate chain against your system trust
store and SNI bslTcp.tlsSni. For dedicated clients, mutual TLS (a provisioned
client CA) and IP allowlisting are available. Always keep certificate
verification on in production.
HTTP compatibility
Compact HTTP order entry remains available:
POST /api/order-entry/binary
POST /api/v1/bsl/orders/compact
Use HTTP for onboarding, admin tools, backfill-friendly bots, and compatibility. Use Direct TCP for latency-sensitive market making.