Skip to main content

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

  1. Open a TCP connection to bslTcp.host:bslTcp.port.
  2. Start TLS with SNI bslTcp.tlsSni.
  3. Set TCP_NODELAY.
  4. Send a 48-byte HandshakeHello offering session version 2. Bytes 36..40 carry your requested heartbeat cadence (ms, little-endian; 0 = let the gateway choose).
  5. Read the 48-byte HandshakeAck. It carries the negotiated session version (bytes 8..10), a 16-byte CSPRNG session token (bytes 20..36, used for resume), and the granted heartbeat cadence (bytes 36..40). A client that offers only the retired v1 receives a HandshakeReject.
  6. 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

KindValueDirectionUse
CompactActionFrame1Client → gatewayOne 192-byte action frame.
CoreAck2Gateway → clientAction/batch acknowledgement (sequenced).
GatewayReject3Gateway → clientFast ingress rejection (sequenced).
AuthSidecar4Client → gatewaySession/account authentication sidecar.
CompactFrameGroup10Client → gatewayBatch/group of compact action frames.
CoreAckBatch11Gateway → clientBatch acknowledgement (sequenced).
ClientHeartbeat12Client → gatewayLiveness (8-byte u64 send timestamp).
ServerHeartbeat13Gateway → clientLiveness on the granted cadence.
ResendRequest14Client → gatewayReplay sequenced messages from a sequence.
SessionResume15Client → gatewayResume a prior session after reconnect.
SessionResumeResult16Gateway → clientResume outcome + continue sequence.
SequencedData17Gateway → clientEnvelope wrapping a per-session sequenced message.
EndOfSession18Gateway → clientGraceful 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 a ResendRequest with from_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 SessionResume with the previous session token and the highest session_seq you processed. The gateway replies with SessionResumeResult (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:

CodeMeaning
SHARD_BUSY / BackpressureFullTarget market shard or queue is saturated.
RateLimitExceededSession/account/api-key rate limit hit.
IdempotencyReplayDuplicate idempotency key within the replay window.
AuthFailedSession is missing required institutional credential state.
SessionViolationSession-level protocol violation (identity/sequence/mapping).
NonceReuseWindowed-nonce replay rejected by the engine.
MarketUnknownMarket 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.