<!-- source: https://secondlayer.tools/docs -->

# Introduction

Decoded Stacks chain data, backfilled from genesis, reorg-safe and kept current. Trust, and [verify it yourself](/docs/verification).

## Where do you start?

```ts index.ts

await new Index().events.consume({
  eventType: "ft_transfer",
  fromCursor: await db.loadCheckpoint(),
  onBatch: async (events, envelope, ctx) => {
    await db.commit(events, ctx.cursor);
    return ctx.cursor;
  },
  onReorg: (reorg) => db.deleteFromHeight(reorg.fork_point_height),
});
```

Write rows and the cursor in one transaction, and roll back to the last good block when a reorg lands. You keep your schema and serve it however you already do. [Index →](/docs/index)

```ts subgraph.config.ts

  name: "sbtc-flows",
  startBlock: 8000000,
  sources: { transfers: { type: "ft_transfer", assetIdentifier: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token" } },
  schema: { transfers: { columns: { amount: { type: "uint" }, sender: { type: "principal" } } } },
  handlers: {
    transfers: (event, ctx) => ctx.insert("transfers", { amount: event.amount, sender: event.sender }),
  },
});
```

The first deploy backfills from your start block, and one write per event fills a table that REST serves. You get an API you didn't write. That's the point, and the tradeoff. [Subgraphs →](/docs/subgraphs)

```ts indexer.ts
await sl.streams.events.consume({
  types: ["ft_transfer"],
  fromCursor: await db.loadCheckpoint(),
  onBatch: async (events, envelope, ctx) => {
    await db.insertEvents(events, ctx.cursor);
    return ctx.cursor;
  },
  onReorg: (reorg) => db.deleteFromHeight(reorg.fork_point_height),
});
```

You get raw, signed frames to decode, and a reorg rewinds to the fork point and re-delivers. This is what Index is built on. [Streams →](/docs/streams)

## Get started

Five commands from key to a row you can check against Bitcoin. Keys come from [/account/keys](/account/keys).

Using an agent? `bunx skills add ryanwaits/secondlayer --skill secondlayer -y`

### Install and set your key

Every command and example reads these two variables.

```bash
bun add -g @secondlayer/cli

```

### Create a subgraph

Scaffolds a typed subgraph from a contract's events.

```bash
secondlayer subgraphs create my-balances --from-contract SP....my-contract
```

### Deploy

Set a `startBlock` first: the event and transaction rows it reads bill. Reads of your own tables are free.

```bash
secondlayer subgraphs deploy subgraphs/my-balances.ts
```

### Query

```bash
curl -H "Authorization: Bearer $SECONDLAYER_API_KEY" \
  "$SECONDLAYER_API_URL/v1/subgraphs/my-balances/balances"
```

### Verify

Proves the block your rows came from against Bitcoin. [Verification →](/docs/verification)

```bash
secondlayer verify block 9137005
```

Prefer your own box? [Self-host](/docs/self-host) is the same product on your Postgres.

## Notes for agents

- Quickstart: 'secondlayer subgraphs create my-balances --from-contract <contract id>', then 'secondlayer subgraphs deploy subgraphs/my-balances.ts' with a startBlock set.
- Hosted: export SECONDLAYER_API_URL=https://api.secondlayer.tools and SECONDLAYER_API_KEY ('sk-sl_*', from /account/keys); read with 'Authorization: Bearer $SECONDLAYER_API_KEY'. Self-hosting: see /docs/self-host.
- Own index: 'secondlayer codegen index --target kysely' for the mirror schema; write a consume() loop that commits rows and the checkpoint in one transaction; handle onReorg by deleting from fork_point_height up.
- Before deploying, 'secondlayer status' confirms the instance is up and ingesting; 'secondlayer verify all' checks data against the signed archive.
- After deploying, 'secondlayer verify block <height>' proves a block against Bitcoin from the checkpoint in the CLI.
- Scaffold subgraphs with 'secondlayer subgraphs scaffold' so the module package and dependencies are prepared.

## Setup

Ensure setup once, skipping any step already done:
- Skill: `bunx skills add ryanwaits/secondlayer --skill secondlayer -y`
- CLI: `bun add -g @secondlayer/cli`
- Instance: `secondlayer init` writes `INSTANCE_TOKEN`. Loopback `/v1` reads need no key.
- Hosted/archive: export `SECONDLAYER_API_KEY` (`sk-sl_*`) or buy credits with `secondlayer credits buy` (`balance`, `refill`), then `secondlayer whoami`
