Skip to main content

SDKs

Senticore maintains official preview SDKs for TypeScript, Python, and Rust. Each one wraps the same surface: public market data, private/trading reads and writes, Order Entry batch submission, and WebSocket helpers.

Preview status

The current preview label is 0.1.0-preview.x. The TypeScript package is public on npm as @sentico-labs/sdk. Python and Rust are repository previews until their public registry releases (PyPI / crates.io) are completed.

Packages

LanguagePackageRegistry statusRepo path
TypeScript@sentico-labs/sdkPublic npm previewsdks/typescript
Pythonsenticore-sdkRepository previewsdks/python
Rustsenticore-sdkRepository previewsdks/rust

Configuration model

A client is constructed from an environment and a single credential. There is one host per environment, path-routed:

  • mainnethttps://api.sentico-labs.xyz
  • localhttp://localhost:8080

There is no testnet host. To point at a custom edge, pass baseUrl to override the environment default.

The credential is one API key triple — apiKey (spk_...), apiSecret (sps_...), apiPassphrase (spp_...) — reused across REST, WebSocket, and FIX. Access is differentiated by scopes and the fast-lane entitlement, not by separate credentials. See Authentication for scopes and the request-signing scheme, and Connectivity for hosts, ports, and routing.

Every client exposes four namespaces:

  • .public — anonymous market-data reads (no auth).
  • .trading — private reads and signed/delegated trading writes.
  • .orderEntry — professional/institutional Order Entry batch submission.
  • .ws — public and private WebSocket helpers.
Breaking change

The previous multi-URL config has been removed. The fields publicHttpBaseUrl, tradingHttpBaseUrl, publicWsUrl, privateWsUrl, orderEntryHttpBaseUrl, every mm* alias (mmApiKey, mmHttpBaseUrl, mmBinaryPath), and bearerToken as a primary credential are no longer accepted. Construct clients with environment + credential.

TypeScript

npm install @sentico-labs/[email protected]
import { SenticoreClient, signedActionFromLocalPayload } from "@sentico-labs/sdk";

const client = new SenticoreClient({
environment: "mainnet",
credential: {
apiKey: process.env.SENTICORE_API_KEY!,
apiSecret: process.env.SENTICORE_API_SECRET!,
apiPassphrase: process.env.SENTICORE_API_PASSPHRASE!,
},
});

// Public read — no auth.
const markets = await client.public.listMarkets();
const book = await client.public.getMarketOrderbook(1, { book: "YES", depth: 20 });
console.log(markets.data, book.requestId);

// Order Entry takes SIGNED actions — build/sign locally (see Signing), then submit.
const signedAction = signedActionFromLocalPayload(payload, signerPrivateKey);
const accepted = await client.orderEntry.submitActions([signedAction], {
idempotencyKey: "client-batch-1",
responseMode: "full",
});
console.log(accepted.data);

Python

git clone https://github.com/sentico-labs/senticore.git
cd senticore/sdks/python
python -m pip install -e .
import os
from senticore import SenticoreClient, signed_action_from_local_payload

client = SenticoreClient(
environment="mainnet",
credential={
"api_key": os.environ["SENTICORE_API_KEY"],
"api_secret": os.environ["SENTICORE_API_SECRET"],
"api_passphrase": os.environ["SENTICORE_API_PASSPHRASE"],
},
)

# Public read — no auth.
markets = client.public.list_markets()
print(markets.data)

# Order Entry takes SIGNED actions — build/sign locally (see Signing), then submit.
signed_action = signed_action_from_local_payload(payload, signer_private_key)
accepted = client.order_entry.submit_actions(
[signed_action],
idempotency_key="client-batch-1",
response_mode="full",
)
print(accepted.data)
client.close()

Rust

[dependencies]
senticore-sdk = { path = "sdks/rust" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
use senticore_sdk::{
sign_action_from_local_payload, Credential, Environment, OrderEntrySubmitOptions,
SenticoreClient,
};

#[tokio::main]
async fn main() -> senticore_sdk::Result<()> {
let client = SenticoreClient::new(
Environment::Mainnet,
Credential::new(
std::env::var("SENTICORE_API_KEY").unwrap(),
std::env::var("SENTICORE_API_SECRET").unwrap(),
std::env::var("SENTICORE_API_PASSPHRASE").unwrap(),
),
)?;

// Public read — no auth.
let markets = client.public.list_markets().await?;
println!("{:?}", markets.data);

// Order Entry takes SIGNED actions — build/sign locally (see Signing), then submit.
let signed_action = sign_action_from_local_payload(&payload, &signer_private_key)?;
let opts = OrderEntrySubmitOptions::new()
.idempotency_key("client-batch-1")
.response_mode("full");
let accepted = client.order_entry.submit_actions(&[signed_action], opts).await?;
println!("{:?}", accepted.data);

Ok(())
}

Order Entry batch shape

All three SDKs encode the same batch payload:

{ "version": 1, "actions": [], "idempotencyKey": "client-batch-1" }

The client posts it to the canonical Order Entry endpoints — JSON at POST /api/v1/order-entry/orders and compact/binary at POST /api/v1/order-entry/orders/compact. The credential authorizes the low-latency lane and rate tier via the fast-lane entitlement; it does not replace the signature inside the batch — every mutating action still needs a valid owner or delegated-signer signature. See Signing for the hot-path signing model and the exact low-level action payloads.

Legacy route names

The names MM, BSL, and binary are legacy aliases for Order Entry. The following routes are still live for existing integrations and resolve to the same Order Entry plane: POST /api/v1/bsl/orders/compact, POST /api/v1/bsl/orders/batch, POST /api/v1/mm/orders/batch.bin, and POST /api/order-entry/binary. New integrations should use the canonical /api/v1/order-entry/... paths.

WebSocket

Public market-data channels need no auth. For private streams, the client issues a short-lived token (one signed REST call to POST /api/v1/ws/token) and sends it in the socket auth frame:

const token = await client.trading.issuePrivateWsToken(account, { ttlMs: 60_000 });
const socket = client.ws.connectPrivate(account, token.data.token, (frame) => {
console.log(frame);
});

See the WebSocket overview for channels and the reconnect/resume model.

Next steps