Skip to content
LogoLogo

Protocols & transports

Every margin service is reachable over two wire protocols on the same URL:

ProtocolContent-TypeBest for
gRPC (binary, HTTP/2)application/grpcNative clients (Rust, Go, Python, …) — the hot path.
gRPC-Web (binary)application/grpc-web+protoBrowsers and other HTTP/1.1 clients.

The server is tonic with tonic_web, so gRPC-Web is translated in process — there is no separate proxy. CORS allows any origin, method, and header, and exposes response headers, so browser apps can call the public host directly. There is no JSON / Connect-protocol endpoint; the OpenAPI file describes the gRPC-Web URLs for tooling, not a REST API.

The Flint SDKs use:

SDKDefault transport
Rust (flint-margin-user-client, flint-margin-maker-client)gRPC over HTTPS (HTTP/2)
TypeScript (@superis-labs/flint-margin-user-client, @superis-labs/flint-margin-maker-client)gRPC-Web binary over HTTPS

The one bidirectional RPC, the maker SessionService.Session heartbeat, needs HTTP/2 gRPC; gRPC-Web can't carry it. Everything else works on either transport.

Request headers

HeaderSent byMeaning
authorization: Bearer <session_token>You / SDK AuthFlowRequired on every maker service except AuthService and NodeService. Ignored by the public user services.
x-api-key: <key>YouAlternative credential for MakerService and EscalationService, for organizations with perps access.
x-flint-sdkSDKSDK identity: rust/<version> or ts-web/<version>.
x-flint-proto-hashSDKFingerprint of the proto tree the SDK was generated from.
x-flint-proto-revSDKflint-protos git revision the SDK was generated from.
grpc-timeoutYou / SDKClient deadline, standard gRPC encoding (e.g. 5000m = 5 s).

The x-flint-* identity headers are diagnostics: the server logs them alongside each request so support can tell which SDK build made a call. They do not gate compatibility today. Hand-rolled clients may omit them.

Response headers

Every response — including rate-limit rejections — carries the server's identity in its headers (and, for gRPC, its trailers):

HeaderMeaning
x-flint-server-versionServer release version.
x-flint-server-commitServer git commit.
x-flint-server-proto-hashProto fingerprint the server was built from.
x-flint-server-proto-revProto revision the server was built from.

Comparing x-flint-server-proto-hash with the SDK's own PROTO_HASH constant is the quickest way to confirm a client and server agree on the schema. In TypeScript, responseMetadata(err) and serverMetadataFromHeaders(headers) read these for you.

Deadlines and timeouts

  • Server side. The server bounds how long it spends producing a response and returns DEADLINE_EXCEEDED when that limit (15 s by default) is hit.
  • Rust. Channels built by the SDK — including the ones endpoint discovery dials — use a 5 s connect timeout and a 10 s per-request timeout, with HTTP/2 keep-alive pings every 30 s (also while idle) and TCP keep-alive every 60 s. Override per call with tonic::Request::set_timeout.
  • TypeScript. No timeout by default. Pass timeoutMs on a call (sent as grpc-timeout) or signal for cancellation; the createXxxClient factories in the user SDK also take a client-wide timeoutMs, which applies to that client's streams as well.

Don't put a short deadline on a server stream: the deadline covers the whole call, so it would cut a healthy subscription.

Streaming

Every Subscribe* RPC is a long-lived server stream and is the recommended path for anything event-driven:

  • MarketDataService.SubscribeOrderBook / SubscribeCandles
  • FundingService.SubscribeFundingRates
  • AccountService.SubscribeAccount / SubscribeAccounts / SubscribeFills / SubscribeActivity
  • MarketService.SubscribeMarkets
  • RiskService.SubscribeAccountsAtRisk
  • MakerService.SubscribeMarketSnapshots / SubscribeFills / SubscribeQuotes
  • TxService.SubscribeTxStatus / SubscribeBlockhash / SubscribeSlots / SubscribeLeaders
  • SpreadProtectService.SubscribeSpreadProtect
  • SessionService.Session (bidirectional heartbeat)

Things to know:

  • Snapshot first. Most streams open with a full snapshot (flagged snapshot = true where the message has the field), then send updates. On reconnect you get a fresh snapshot — replace local state rather than merging.
  • Order book sequencing. SubscribeOrderBook messages carry sequence and previous_sequence. If previous_sequence doesn't match the last sequence you applied, drop the book and resubscribe.
  • Slow consumers are cut off. If you fall behind the server's buffer, the stream ends with DATA_LOSS (account activity, fills, candles) or RESOURCE_EXHAUSTED (accounts at risk). Reconnect and reconcile against the matching unary RPC — GetActivity, GetFills, GetCandles, or ListAccountsAtRisk.
  • Live-only streams. SubscribeActivity and SubscribeFills do not replay history. Backfill with the unary RPC after a gap.
  • Reconnect with backoff. The TypeScript SDKs export streamWithBackoff, which re-opens a stream on a 500 ms → 30 s exponential schedule. The Rust maker client's subscribe_* methods return a ResilientStream that does the same, re-authenticating as needed. With a bare generated client, loop over the stream and reopen on error.

Each open stream holds one of your 100 concurrent stream slots until it closes — see Rate limits.

gRPC examples

The SDKs are the supported clients. For quick checks from a shell, grpcurl works against the bundled protos. These commands use the running local fixture. For another network, use the operator's host:port values and omit -plaintext when the gateway uses TLS. Use a margin bearer session from that same gateway.

# Public — perp market catalog.
grpcurl -plaintext \
  -proto margin-user.proto \
  -d '{}' \
  127.0.0.1:15061 \
  flint.margin.user.v1.PerpMarketService/ListPerpMarkets
 
# Public — one trader account.
grpcurl -plaintext \
  -proto margin-user.proto \
  -d '{"trader_id":{"id":"42"}}' \
  127.0.0.1:15061 \
  flint.margin.user.v1.AccountService/GetAccount
 
# Authenticated — pass the session token as metadata.
grpcurl -plaintext \
  -proto margin-maker.proto \
  -H "authorization: Bearer ${FLINT_MARGIN_TOKEN}" \
  -d '{}' \
  127.0.0.1:15062 \
  flint.margin.maker.v1.MakerService/GetQuotingState
 
# Public — this node's identity, program id, and health.
grpcurl -plaintext \
  -proto margin-maker.proto \
  -d '{}' \
  127.0.0.1:15062 \
  flint.margin.maker.v1.NodeService/GetNodeInfo

grpcurl takes JSON for convenience; uint64 fields such as trader_id.id are strings in proto JSON. The request still goes over the wire as protobuf.