Quickstart

Everything you need to interact with Subtensor programmatically. Pick your language, copy the code.

Connect

All interactions start with a WebSocket connection to a Subtensor node. The finney endpoint is the main public network.

TypeScript (PAPI)
import { createClient } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws";
import { sub } from "@polkadot-api/descriptors"; // generated by: npx papi add sub -w wss://entrypoint-finney.opentensor.ai:443

const client = createClient(getWsProvider("wss://entrypoint-finney.opentensor.ai:443"));
const api = client.getTypedApi(sub);

const finalized = await client.getFinalizedBlock();
console.log(`Connected at block #${finalized.number}`);

You can also browse live chain data on the bittensor.ai chain explorer.

Query Storage

Read on-chain state like balances, stake amounts, and subnet parameters. Storage items are the chain's database.

TypeScript (PAPI)
import { createClient, Binary } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws";
import { sub } from "@polkadot-api/descriptors"; // generated by: npx papi add sub -w wss://entrypoint-finney.opentensor.ai:443

const client = createClient(getWsProvider("wss://entrypoint-finney.opentensor.ai:443"));
const api = client.getTypedApi(sub);

// Query TotalStake storage (no keys - plain value)
const result = await api.query.SubtensorModule.TotalStake.getValue();
console.log("TotalStake:", result);
See all 398 storage items →

Read Constants

Constants are fixed runtime values like limits and defaults. They change only with runtime upgrades, not transactions.

TypeScript (PAPI)
import { createClient, Binary } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws";
import { sub } from "@polkadot-api/descriptors"; // generated by: npx papi add sub -w wss://entrypoint-finney.opentensor.ai:443

const client = createClient(getWsProvider("wss://entrypoint-finney.opentensor.ai:443"));
const api = client.getTypedApi(sub);

// Query InitialMaxAllowedUids constant
const value = await api.constants.SubtensorModule.InitialMaxAllowedUids();
console.log("InitialMaxAllowedUids:", value);
See all 136 constants →

Subscribe to Events

Listen for events emitted by the chain. Events signal that something happened — a stake was added, a subnet was registered, etc.

TypeScript (PAPI)
import { createClient, Binary } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws";
import { sub } from "@polkadot-api/descriptors"; // generated by: npx papi add sub -w wss://entrypoint-finney.opentensor.ai:443

const client = createClient(getWsProvider("wss://entrypoint-finney.opentensor.ai:443"));
const api = client.getTypedApi(sub);

// Subscribe to StakeAdded events
client.finalizedBlock$.subscribe(async (block) => {
  const events = await api.event.SubtensorModule.StakeAdded.get(block.hash);
  for (const evt of events) {
    console.log("StakeAdded:", evt.payload);
  }
});
See all 306 events →

Decode Event Data

After receiving an event, decode its arguments. Balance fields are in RAO (divide by 10⁹ for TAO). Accounts are SS58-encoded.

TypeScript (PAPI)
// Decode StakeAdded event payload (typed object)
const [coldkey, hotkey, tao_amount, alpha_received, netuid, fee_paid_tao] = evt.payload;

Build an Extrinsic

Construct a call with its parameters. This example builds an add_stake call to stake TAO to a hotkey on a subnet.

TypeScript (PAPI)
import { createClient, Binary } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws";
import { sub } from "@polkadot-api/descriptors"; // generated by: npx papi add sub -w wss://entrypoint-finney.opentensor.ai:443

const client = createClient(getWsProvider("wss://entrypoint-finney.opentensor.ai:443"));
const api = client.getTypedApi(sub);

// Build add_stake call (typed, named args)
const hotkey = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
const netuid = 1;
const amount_staked = 1_000_000_000n;

const tx = api.tx.SubtensorModule.add_stake({
  hotkey,
  netuid,
  amount_staked,
});
See all 307 calls →

Submit an Extrinsic

Sign and submit the call, then wait for finalization. Check for success events and handle dispatch errors.

TypeScript (PAPI)
import { getPolkadotSigner } from "polkadot-api/signer";
import { sr25519CreateDerive } from "@polkadot-labs/hdkd";
import { DEV_PHRASE, entropyToMiniSecret, mnemonicToEntropy } from "@polkadot-labs/hdkd-helpers";

// Build a signer (replace DEV_PHRASE with your real seed phrase before running on mainnet)
const entropy = mnemonicToEntropy(DEV_PHRASE);
const miniSecret = entropyToMiniSecret(entropy);
const derive = sr25519CreateDerive(miniSecret);
const aliceKey = derive("//Alice");
const signer = getPolkadotSigner(aliceKey.publicKey, "Sr25519", aliceKey.sign);

// Submit and await finalization
const result = await tx.signAndSubmit(signer);
if (result.ok) {
  console.log("add_stake succeeded in block", result.block.hash);
for (const evt of result.events) {
  if (evt.type === "SubtensorModule" && evt.value.type === "StakeAdded") {
    console.log("StakeAdded emitted:", evt.value.value);
  }
}
} else {
  console.error("add_stake failed:", result.dispatchError);
}

// For MEV-protected (encrypted) submission, see:
// https://subtensor.com/learn/technical/mev-shield

Decode SCALE Types

Substrate uses SCALE encoding for all on-chain data. Decode raw bytes back into typed values.

TypeScript (polkadot.js)
import { TypeRegistry } from "@polkadot/types";

const registry = new TypeRegistry();

// Decode u64 from hex bytes
const decoded = registry.createType("u64", "0x...");
console.log("Value:", decoded.toNumber());
See all 808 SCALE types →

Next Steps

  • Reference – Browse all pallets, events, calls, storage, and types
  • Learn – Understand Subtensor from the ground up
  • API – Programmatic access via REST, GraphQL, and MCP