SDKs
The TypeScript, Rust and Python SDKs for Tenzro Network, hardware device keys, and how signing and credentials work.
Tenzro publishes three first-party SDKs with the same shape: tenzro-sdk for TypeScript, tenzro-sdk for Rust and tenzro for Python. Each wraps the JSON-RPC surface of a node with typed clients per area (wallet, identity, inference, payments, settlement, storage, agents and more), and each includes a gateway that can call any method the node serves.
All SDKs are open source under Apache 2.0.
Install
# TypeScript (Node 18+, browsers, edge runtimes)
npm install tenzro-sdk
# Rust
cargo add tenzro-sdk
# Python (3.10+), with the hardware signer
pip install "tenzro[device]"| Package | Registry | Tenzro Network version |
|---|---|---|
tenzro-sdk (TypeScript) | npm | 0.8.0 |
@tenzro/device-key (TPM / Secure Enclave keys for Node.js) | npm | 0.1.0 |
@tenzro/inject (injected window.tenzro provider) | npm | 0.1.0 |
tenzro-sdk (Rust) | crates.io | 0.8.0 |
tenzro (Python) and tenzro-device-key | PyPI | 0.1.0 |
Signing needs hardware: on a server or desktop the SDKs sign with the machine's TPM 2.0 or Secure Enclave through @tenzro/device-key (TypeScript) or tenzro-device-key (Python); in a browser they use a passkey. Without one they refuse to sign. Every method the SDKs bind is documented with its params, result and errors in the generated JSON-RPC reference.
Connect
The TypeScript client takes an endpoint for JSON-RPC and an apiEndpoint for the Web API (health and status).
import { TenzroClient } from "tenzro-sdk";
const client = new TenzroClient({
endpoint: "https://rpc.tenzro.com",
apiEndpoint: "https://api.tenzro.com",
});
const height = await client.getBlockNumber();
const finalized = await client.getFinalizedBlock();
const balance = await client.getBalance("0xYourAddress"); // bigint, in weiIf you leave out apiEndpoint, the client derives it from endpoint for the public endpoints and for a local node (localhost:8545 maps to localhost:8080).
The Rust client is built from an SdkConfig:
use tenzro_sdk::{TenzroClient, config::SdkConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = SdkConfig::builder()
.endpoint("https://rpc.tenzro.com")
.timeout(30_000)
.max_retries(3)
.build()?;
let client = TenzroClient::connect(config).await?;
println!("height: {}", client.block_number().await?);
let models = client.inference().list_models().await?;
println!("{} models", models.len());
Ok(())
}TenzroClient::new("https://rpc.tenzro.com") is the one-line form with default settings.
Run inference
List models and send a chat request through the provider client:
const models = await client.inference.listModels();
const reply = await client.provider.chat("<model id>", [
{ role: "user", content: "Summarise the latest block in one sentence." },
]);use tenzro_sdk::provider::ChatMessage;
let reply = client
.provider()
.chat("<model id>", vec![ChatMessage {
role: "user".into(),
content: "Summarise the latest block in one sentence.".into(),
..Default::default()
}])
.await?;If you do not want to pick a model yourself, client.inference.routeIntent(...) resolves a use case and budget to a model, and chatByIntent(...) runs the request in one call.
The node also serves OpenAI-compatible routes (/v1/chat/completions, /v1/embeddings, /v1/images/generations, /v1/audio/transcriptions, /v1/videos and more), so any OpenAI client library works when you point its base URL at https://rpc.tenzro.com/v1. See OpenAI-compatible APIs.
Signing and credentials
Tenzro Network is closed by default: anything that moves money or changes state needs a signature from the account that pays. The SDKs never hold your keys. You pass in a signer backed by a passkey, a TPM 2.0 or a Secure Enclave key, and the SDK builds the canonical transaction hash, asks the signer for the composite hybrid signature (classical plus ML-DSA-65) and submits the signed transaction with eth_sendRawTransaction.
// signer: a HybridSigner backed by your passkey or device key
const txHash = await client.wallet.sendSelfCustody({
signer,
to: "0xRecipient",
value: 1_000_000_000_000_000_000n, // 1 TNZO in wei
});// signer: Arc<dyn HybridSigner> backed by your device key
let tx_hash = client
.wallet()
.send_self_custody(&signer, recipient, 1_000_000_000_000_000_000u128)
.await?;In the browser, a passkey enrols with client.passkeyRpc.enroll and signs transactions from its account as a HybridSigner whose P-256 leg is its WebAuthn assertion (user verification required). See Hardware-rooted keys and Console and passkey wallet.
Other credentials are read from the environment in server runtimes, so they stay out of your code:
| Variable | Header sent | Used for |
|---|---|---|
TENZRO_BEARER_JWT and TENZRO_DPOP_PROOF | Authorization: DPoP ... and DPoP | OAuth 2.1 sessions bound to a DPoP key |
TENZRO_ADMIN_TOKEN | X-Tenzro-Admin-Token | Operator-only methods on your own node |
AuthClient (client.auth in TypeScript, client.auth() in Rust) handles onboarding for humans, delegated agents and autonomous agents and returns DPoP-bound tokens. HardwareDpopProver mints the DPoP proofs with the machine's hardware P-256 key, and jwkThumbprint computes the key's thumbprint. See RPC access.
Call any method
Typed clients cover the common paths. Everything else is reachable through the gateway, which reads the method list from the node itself, so a newer node simply reports more:
const dir = await client.gateway.methods({ contains: "forecast" });
for (const m of dir.methods) console.log(m.method, m.gate, m.class);
const result = await client.gateway.call("tenzro_getSupplyMetrics", {});let dir = client.gateway().methods(None, Some("forecast")).await?;
let result = client.gateway().call("tenzro_getSupplyMetrics", serde_json::json!({})).await?;The gateway runs through the same access checks as a direct JSON-RPC call. It reaches exactly what your credentials allow.
Choosing
- TypeScript for web and desktop apps, agents, serverless and edge functions.
- Rust for daemons, high-volume services and anything that embeds a node.
- The CLI for scripts and operator tasks.
For every client and method, see the SDK reference.