Index
Index is the decoded read layer for Stacks. An L2 decoder consumes the raw Streams firehose and normalizes every event type — STX, FT, and NFT transfers, mints and burns, and print events — plus contract calls, into typed, queryable rows. Filter by contract, wallet, or block range, with no decoders to write or maintain.
Reads are open during beta — anonymous works, and an just raises your rate limit.
For your own app-specific shape, see Subgraphs; for raw events, see Streams.
How it works
decoded once — query forever
The decoder reads Streams and writes normalized rows for every decoded event_type; contract calls come straight from the transaction record with their arguments and result decoded. The Index API serves them, filtered and cursor-paginated. Decoding happens once, on shared infra — you just query.
Querying
/v1/index/events?event_type=… serves every decoded event type, and /v1/index/contract-calls serves decoded contract calls. Filter by contract_id, sender, and block range, and page forward on a cursor. (ft-transfers and nft-transfers remain as typed aliases.) The SDK wraps list + cursor-walking:
import { Index } from "@secondlayer/sdk";
const index = new Index({ apiKey: process.env.SL_INDEX_API_KEY });
// One page of decoded events for any type
const { events, next_cursor } = await index.events.list({
eventType: "stx_transfer",
sender: "SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE",
limit: 50,
});
// Or stream every contract call to a contract across pages
for await (const call of index.contractCalls.walk({ contractId })) {
await handle(call);
}Try it
Code · curl, fetch
curl "https://api.secondlayer.tools/v1/index/ft-transfers?limit=5"const res = await fetch(
"https://api.secondlayer.tools/v1/index/ft-transfers?limit=5",
);
const data = await res.json();