Skip to content

Protocols & transports

Every RPC is served over four protocols at the same URL. Pick whichever fits your stack.

ProtocolContent-TypeBest for
gRPC (binary)application/grpcNative Rust / Go / Python clients — hot path.
gRPC-Web (binary)application/grpc-webBrowsers using a gRPC-Web library.
Connect (JSON)application/jsoncurl, Postman, debugging.
Connect (binary)application/protoBrowser SDK default; smaller than JSON.

The Superis SDKs default to:

SDKDefault transport
RustgRPC (binary) over HTTPS
GogRPC (binary) over HTTPS
TypeScript-webConnect (binary) over HTTPS

All three let you override.

curl examples

POST to any RPC URL with a JSON body:

sh
# Public — no auth needed.
curl -sS -X POST \
  -H 'Content-Type: application/json' \
  -d '{}' \
  https://api.superis.exchange/sweetspot.api.v1.MarketDataService/ListPairs | jq

# Authenticated — pass the session token.
curl -sS -X POST \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer ${SUPERIS_TOKEN}" \
  -d '{}' \
  https://api.superis.exchange/sweetspot.api.v1.BalanceService/Get | jq

# Historical candles — note from_sec / to_sec are unix seconds.
curl -sS -X POST \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer ${SUPERIS_TOKEN}" \
  -d '{"pair":{"base":{"id":1},"quote":{"id":0}},"interval":"INTERVAL_5M","from_sec":1735689600,"to_sec":1735776000}' \
  https://api.superis.exchange/sweetspot.api.v1.HistoricalService/GetCandles | jq

The JSON shape mirrors the proto field names exactly. Enums travel as their variant name ("INTERVAL_5M", not "5m" or 1).

Connection reuse

A single tonic Channel (Rust), *grpc.ClientConn (Go), or Connect Transport (TypeScript) handles every RPC across every service. Build it once at boot, share it across your service clients, and let HTTP/2 multiplexing handle the per-call traffic.

rust
let channel = Channel::from_static("https://api.superis.exchange:443")
    .connect()
    .await?;

let auth = AuthFlow::new(channel.clone(), Arc::new(my_signer));
let market = MarketDataServiceClient::new(channel.clone());
let balances = BalanceServiceClient::with_interceptor(channel.clone(), auth.interceptor());
let tx = TxServiceClient::with_interceptor(channel.clone(), auth.interceptor());

Streaming

Long-lived server streams (MarketDataService.Subscribe, BalanceService.Subscribe, TxService.SubscribeBlockhash / SubscribeSlots / SubscribeTxStatus) are the recommended path for anything event-driven. Wrap them in ResilientStream to get auto-reconnect + fan-out.

Apache 2.0