Skip to content
Tenzro
Documentation menu
Build and operate

SDKs

The TypeScript and Rust SDKs for Tenzro Network 1, the @tenzro/ai inference packages, and how signing and credentials work.

Tenzro publishes two first-party SDKs with the same shape: tenzro-sdk for TypeScript and tenzro-sdk for Rust. Both wrap the JSON-RPC surface of a node with typed clients per area (wallet, identity, inference, payments, settlement, storage, agents and more), and both include a gateway that can call any method the node serves. For inference-first applications there is also @tenzro/ai, a smaller package built around text generation, streaming and multimodal calls.

All SDKs are open source under Apache 2.0.

Install

bash
# TypeScript (Node 18+, browsers, edge runtimes)
npm install tenzro-sdk

# Rust
cargo add tenzro-sdk

# Inference-first TypeScript API, plus React hooks
npm install @tenzro/ai @tenzro/ai-react

Connect

The TypeScript client takes an endpoint for JSON-RPC and an apiEndpoint for the Web API (health, status and faucet).

ts
import { TenzroClient } from "tenzro-sdk";

const client = new TenzroClient({
  endpoint: "https://rpc.tenzro.xyz",
  apiEndpoint: "https://api.tenzro.xyz",
});

const height = await client.getBlockNumber();
const finalized = await client.getFinalizedBlock();
const balance = await client.getBalance("0xYourAddress"); // bigint, in wei

If 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:

rust
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.xyz")
        .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.xyz") is the one-line form with default settings.

Run inference

List models and send a chat request through the provider client:

ts
const models = await client.inference.listModels();

const reply = await client.provider.chat("<model id>", [
  { role: "user", content: "Summarise the latest block in one sentence." },
]);
rust
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(),
    }])
    .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.xyz/v1. See OpenAI-compatible APIs.

@tenzro/ai

@tenzro/ai is a thin, inference-first layer with top-level functions: generateText, streamText, generateObject, streamObject, embed, embedImage, imageTextSimilarity, forecast, segment, detect, transcribe and embedVideo.

ts
import { streamText, tenzro } from "@tenzro/ai";

const { stream } = streamText({
  model: tenzro("<model id>"),
  messages: [{ role: "user", parts: [{ type: "text", text: "Write a haiku." }] }],
});

for await (const part of stream) {
  if (part.type === "text-delta") process.stdout.write(part.text);
}

@tenzro/ai-react adds useChat and useCompletion hooks, and @tenzro/ai-provider is a kit for publishing your own provider behind the same interface.

Signing and credentials

Network 1 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.

ts
// 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
});
rust
// 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, createPasskeyWallet enrols a passkey (user verification required) and signWithPasskey signs smart-account user operations with it. 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:

VariableHeader sentUsed for
TENZRO_API_KEYX-Tenzro-Api-KeyScoped access issued by an RPC provider. See API keys.
TENZRO_BEARER_JWT and TENZRO_DPOP_PROOFAuthorization: DPoP ... and DPoPOAuth 2.1 sessions bound to a DPoP key
TENZRO_ADMIN_TOKENX-Tenzro-Admin-TokenOperator-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. generateDpopKeyPair, computeJkt and mintDpopProof produce the DPoP proofs. 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:

ts
const dir = await client.gateway.methods({ contains: "forecast" });
for (const m of dir.methods) console.log(m.method, m.gate, m.scope ?? "");

const result = await client.gateway.call("tenzro_getSupplyMetrics", {});
rust
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.
  • @tenzro/ai when all you need is inference with streaming and structured output.
  • The CLI for scripts and operator tasks.

For every client and method, see the SDK reference.