Open beta — reads need no key

We decode the chain.
You build the index.

Every Stacks event, decoded into typed rows. Read them keyless, or sweep them into your own app index — cursors, reorgs, and backfill on every page.

import { Index } from "@secondlayer/sdk";
import { db } from "./index-db";

const index = new Index();
const MARKETPLACE = "SPNWZ…E0VQ0S.marketplace-v4";

// Tail every decoded call to a contract —
// no node to run, no Clarity to parse.
for await (const call of index.contractCalls.walk({
  contractId: MARKETPLACE,
  functionName: "purchase-asset",
})) {
  const [collection, tokenId] = call.args;

  await db
    .insertInto("sales")
    .values({
      tx_id: call.tx_id,
      buyer: call.sender,
      collection: String(collection),
      token_id: String(tokenId),
      block_height: call.block_height,
    })
    .execute();
}

One decoded row set.
Three ways in: SDK, CLI, Agent.

Filter, paginate, and cursor-walk the same decoded rows from the typed SDK, your terminal, or an agent.

Read the Index docs

SDK

Typed list and cursor-walking in TypeScript, fully inferred.

const index = new Index();

for await (const t of
  index.ftTransfers.walk({ contractId })) {
  // t is fully typed
  console.log(t.sender, t.amount);
}

CLI

Pipeable and scriptable, with JSON whenever you ask for it.

$ sl index events \
  --event-type stx_transfer --json
  | jq '.events | length'
2,481

Agent

The whole surface speaks MCP — an agent queries with zero setup.

agent
secondlayer · mcp
12 tools · keyless reads
Index every sBTC transfer to my contract
⬡ index_events · ft_transfer
2,481 rows streamed

Build your index.
We run the rest.

No node, no key, no infra to run. Just decoded rows — cursors, reorgs, and backfill — over the same Streams firehose our decoder runs on. See it live in the sBTC Peg Explorer — a full page built on nothing but the keyless API.