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

L2 decoderreads StreamsDecoded eventsstx · ft · nft · printIndex/v1/indexYour appfilter · paginate

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

Try /v1/index/ft-transfers
GET/v1/index/ft-transfers?limit=5
not run yet
"events":
"event_type": "ft_transfer",
"block_height": 7869999,
"tx_id": "0xabc…",
"event_index": 12,
"contract_id": "SP2…token-usda",
"sender": "SP3…",
"recipient": "SP1…",
"amount": "1000000"
}
]
,
"next_cursor": "7870001:7"
}
PressSendto run this against live data.
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();