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

# Index API

Decoded rows over plain HTTP, every endpoint a `GET` under `/v1/index`. Envelope, cursors and filters work the same on all of them: see [REST conventions](/docs/rest-api).

## Events

Decoded events and the transfers and calls built from them.

### Decoded events by event_type

`GET /v1/index/events`

One `event_type` per request, oldest first unless `order=desc`. Which filters and `fields` apply depends on the type; anything a type does not accept is refused.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `event_type` | enum, required | The event type to read. Required, unless you pass `types` instead. Values: `ft_transfer`, `nft_transfer`, `stx_transfer`, `stx_mint`, `stx_burn`, `stx_lock`, `ft_mint`, `ft_burn`, `nft_mint`, `nft_burn`, `print`. |
| `types` | string | Alias for `event_type`, the Streams spelling. Takes one value; a comma-separated set is refused. Mutually exclusive with `event_type`. |
| `order` | enum | `asc` (default) reads oldest first. `desc` reads newest first: with no height range, page one is the newest rows of the last day. A `desc` page's `next_cursor` starts with `desc:` and pages older; a cursor resumes only under the order that issued it, and the other order is refused with 400. Values: `asc`, `desc`. |
| `contract_id` | string | Contract principal, or a comma-separated set of up to 20 (e.g. `SP1.sbtc-token,SP1.sbtc-registry`). Mutually exclusive with `trait`. |
| `trait` | enum | Only contracts that declare or implement this SIP standard, resolved as of the page's `to_height`. Mutually exclusive with `contract_id`. Values: `sip-009`, `sip-010`, `sip-013`. |
| `asset_identifier` | string | Asset identifier (`<contract>::<asset>`). ft and nft transfer, mint and burn types only. |
| `sender` | string | Sending principal. Types with a sender only; on `stx_lock` it is the locked address. |
| `recipient` | string | Receiving principal. Types with a recipient only. |
| `tx_context` | boolean | `true` adds the submitting transaction's `tx_sender`, `tx_type`, `tx_status`, `tx_contract_id` and `tx_function_name` to each row. |
| `wait` | integer | Seconds (max 25) to hold the response open when there's nothing new past your cursor/from_height, instead of answering immediately. Returns early the moment new data commits, or at the timeout — either way you get a normal response, just later. Omit for the old poll-and-retry behavior. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `fields` | string | Comma-separated columns to return: the universal ones, the type's own columns, and the `tx_*` columns when `tx_context=true`. `cursor`, `block_height` and `event_type` always come back; an unknown name is refused. Leaving out `block_time` skips a join. |

#### Returns

A cursor envelope; `events` holds `IndexEvent` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/events \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "events": [
    {
      "cursor": "9048921:2",
      "block_height": 9048921,
      "block_time": "2026-09-23T15:09:05.000Z",
      "tx_id": "0x55249ff4ec221ff6852b7fa37cf3729c7c50bc63f0da760f96e6886e2e8a911e",
      "tx_index": 4,
      "event_index": 2,
      "event_type": "stx_transfer",
      "contract_id": null,
      "sender": "SPX4KR3G5Z1SZT4RVF4ATHV4ZP4KXPWSZ4424W6K",
      "recipient": "SP2Z2CBMGWB9MQZAF5Z8X56KS69XRV3SJF4WKJ7J9",
      "amount": "50",
      "memo": null
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### Fungible token transfers

`GET /v1/index/ft-transfers`

Same rows as `/v1/index/events?event_type=ft_transfer`, oldest first unless `order=desc`, with a typed row. Filters combine with AND.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `order` | enum | `asc` (default) reads oldest first. `desc` reads newest first: with no height range, page one is the newest rows of the last day. A `desc` page's `next_cursor` starts with `desc:` and pages older; a cursor resumes only under the order that issued it, and the other order is refused with 400. Values: `asc`, `desc`. |
| `contract_id` | string | Token contract. One principal; no comma-separated set here. |
| `asset_identifier` | string | Asset identifier (`<contract>::<asset>`). |
| `sender` | string | Sending principal. |
| `recipient` | string | Receiving principal. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `fields` | string | Comma-separated columns to return, from `block_time`, `tx_id`, `tx_index`, `event_index`, `contract_id`, `asset_identifier`, `sender`, `recipient`, `amount` and `event_type`. `cursor` and `block_height` always come back; an unknown name is refused. |

#### Returns

A cursor envelope; `events` holds `FtTransfer` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/ft-transfers \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "events": [
    {
      "cursor": "9048918:3",
      "block_height": 9048918,
      "block_time": "2026-09-23T15:08:18.000Z",
      "tx_id": "0xc342cb7616498a84a8dcfac62a991c31c037d8c6f98a11f987f0719fd619e672",
      "tx_index": 2,
      "event_index": 3,
      "event_type": "ft_transfer",
      "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
      "asset_identifier": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token",
      "sender": "SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.v0-8-market",
      "recipient": "SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.v0-vault-sbtc",
      "amount": "15000"
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### NFT transfers

`GET /v1/index/nft-transfers`

Same rows as `/v1/index/events?event_type=nft_transfer`, oldest first unless `order=desc`, with a typed row. Filters combine with AND.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `order` | enum | `asc` (default) reads oldest first. `desc` reads newest first: with no height range, page one is the newest rows of the last day. A `desc` page's `next_cursor` starts with `desc:` and pages older; a cursor resumes only under the order that issued it, and the other order is refused with 400. Values: `asc`, `desc`. |
| `contract_id` | string | NFT contract. One principal; no comma-separated set here. |
| `asset_identifier` | string | Asset identifier (`<contract>::<asset>`). |
| `sender` | string | Sending principal. |
| `recipient` | string | Receiving principal. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `fields` | string | Comma-separated columns to return, from `block_time`, `tx_id`, `tx_index`, `event_index`, `contract_id`, `asset_identifier`, `sender`, `recipient`, `value` and `event_type`. `cursor` and `block_height` always come back; an unknown name is refused. |

#### Returns

A cursor envelope; `events` holds `NftTransfer` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/nft-transfers \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "events": [
    {
      "cursor": "9048916:0",
      "block_height": 9048916,
      "block_time": "2026-09-23T15:07:41.000Z",
      "tx_id": "0x269d7877002b998ad3a3ee35f661610cc8f2be6eec604905311d52cf1cf80caa",
      "tx_index": 0,
      "event_index": 0,
      "event_type": "nft_transfer",
      "contract_id": "SPVD6CE8RW90BGGKJZTKCSMGKS7HP0K8364TFR48.bitcoin-faces-airdrop",
      "asset_identifier": "SPVD6CE8RW90BGGKJZTKCSMGKS7HP0K8364TFR48.bitcoin-faces-airdrop::bitcoin-faces",
      "sender": "SP3KMHQ80ZGT037R2FCHV1F7Z0X25EV6GVEYNAB87",
      "recipient": "SP37YJNKVKP3KD5SFK71NW7DC25RRF4HKWWQRH3NT",
      "value": "0x010000000000000000000000000008331e"
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### Decoded contract-call transactions

`GET /v1/index/contract-calls`

Top-level `contract_call` transactions in canonical blocks, oldest first, with arguments and result decoded. Failed calls are included; check `status`. The cursor is `<block_height>:<tx_index>`. `reorgs` covers every height on the page.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `contract_id` | string | Contract principal, or a comma-separated set of up to 20 (e.g. `SP1.sbtc-token,SP1.sbtc-registry`). Mutually exclusive with `trait`. |
| `trait` | enum | Only contracts that declare or implement this SIP standard, resolved as of the page's `to_height`. Mutually exclusive with `contract_id`. Values: `sip-009`, `sip-010`, `sip-013`. |
| `function_name` | string | Called function. Exact match. |
| `sender` | string | Transaction sender principal. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<tx_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |

#### Returns

A cursor envelope; `contract_calls` holds `ContractCall` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/contract-calls \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "contract_calls": [
    {
      "cursor": "9048502:1",
      "block_height": 9048502,
      "block_time": "2026-09-23T13:14:42.000Z",
      "tx_id": "0x198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
      "tx_index": 1,
      "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
      "function_name": "transfer",
      "sender": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
      "status": "success",
      "args": [
        "300",
        "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
        "SPD3SCZDZ52X4ZX1878XWBFBJ29YRX0MFW9Z9W4V",
        null
      ],
      "result": true,
      "result_hex": "0x0703"
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

## Blocks and transactions

Canonical blocks, full transactions and inclusion proofs.

### Canonical block-hash map

`GET /v1/index/canonical`

One row per height on the canonical chain, oldest first. Orphaned blocks never appear, so you can check your own chain against it. Lean by design; `/v1/index/blocks` is the full block. Not metered.

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |

#### Returns

A cursor envelope; `canonical` holds `CanonicalBlock` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/canonical \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "canonical": [
    {
      "cursor": "9048503:0",
      "block_height": 9048503,
      "block_hash": "0x5560590afefe994adbe2188586a44ba3668e8964a7e64bb137c0df216531da0c",
      "parent_hash": "0x2a20974330e301b65086d3cde9b0006c9b7471479ba9a3fc2ca72621479655cc",
      "burn_block_height": 968276,
      "burn_block_hash": "0x000000000000000000019d25cd76d06a9eea796a906ac88300cd70fd70ccdb57"
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  }
}
```

### Canonical blocks

`GET /v1/index/blocks`

Canonical blocks, oldest first. The cursor is `<block_height>:0`. The window follows the ingest tip, so it can run ahead of the decoded `tip.block_height`.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `wait` | integer | Seconds (max 25) to hold the response open when there's nothing new past your cursor/from_height, instead of answering immediately. Returns early the moment new data commits, or at the timeout — either way you get a normal response, just later. Omit for the old poll-and-retry behavior. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |

#### Returns

A cursor envelope; `blocks` holds `Block` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/blocks \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "blocks": [
    {
      "cursor": "9048502:0",
      "block_height": 9048502,
      "block_hash": "0x2a20974330e301b65086d3cde9b0006c9b7471479ba9a3fc2ca72621479655cc",
      "parent_hash": "0x10606e958095ef9b964e3c3f2d9eb75bf8577fb8c09c24ee492b767f7504abea",
      "burn_block_height": 968276,
      "burn_block_hash": "0x000000000000000000019d25cd76d06a9eea796a906ac88300cd70fd70ccdb57",
      "index_block_hash": "0x990152a894e12288960c8b68e5790ad7994f9d261e9ad8adc13c72e76f914339",
      "block_time": "2026-09-23T13:14:42.000Z",
      "canonical": true
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  }
}
```

### Block by height or hash

`GET /v1/index/blocks/{height_or_hash}`

A height returns the canonical block there. A hash returns that block whether or not it is canonical, so check `canonical` to spot an orphan. Not metered.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `height_or_hash` | string, required | A block height (digits only) or a `0x`-prefixed block hash. |

#### Responses

- `200` The block and the tip it was read against
- `401` This bind requires the instance token, and it was missing or wrong
- `404` No block at that height or with that hash (`Block not found`)
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/blocks/9048502 \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "block": {
    "cursor": "9048502:0",
    "block_height": 9048502,
    "block_hash": "0x2a20974330e301b65086d3cde9b0006c9b7471479ba9a3fc2ca72621479655cc",
    "parent_hash": "0x10606e958095ef9b964e3c3f2d9eb75bf8577fb8c09c24ee492b767f7504abea",
    "burn_block_height": 968276,
    "burn_block_hash": "0x000000000000000000019d25cd76d06a9eea796a906ac88300cd70fd70ccdb57",
    "index_block_hash": "0x990152a894e12288960c8b68e5790ad7994f9d261e9ad8adc13c72e76f914339",
    "block_time": "2026-09-23T13:14:42.000Z",
    "canonical": true
  },
  "tip": {
    "block_height": 9048938,
    "finalized_height": 9048671,
    "lag_seconds": 23,
    "source_block_height": 9048938
  }
}
```

### Full transaction documents

`GET /v1/index/transactions`

Transactions in canonical blocks, oldest first, with fee, nonce, post-conditions and payload detail decoded from the raw bytes. Filters combine with AND. The cursor is `<block_height>:<tx_index>`. `reorgs` covers every height on the page.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `type` | string | Transaction type as stored, e.g. `contract_call`, `token_transfer`, `smart_contract`, `coinbase`, `tenure_change`. Exact match. |
| `sender` | string | Sender principal. Exact match. |
| `contract_id` | string | Called or deployed contract. One principal. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<tx_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `fields` | string | Comma-separated columns to return, from `block_time`, `burn_block_height`, `tx_index`, `tx_type`, `sender`, `status`, `fee`, `nonce`, `sponsored`, `anchor_mode`, `post_condition_mode`, `post_conditions`, `contract_call`, `smart_contract`, `token_transfer`. `cursor`, `block_height` and `tx_id` always come back; an unknown name is refused. |

#### Returns

A cursor envelope; `transactions` holds `Transaction` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/transactions \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "transactions": [
    {
      "cursor": "9048502:1",
      "tx_id": "0x198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
      "block_height": 9048502,
      "block_time": "2026-09-23T13:14:42.000Z",
      "burn_block_height": 968276,
      "tx_index": 1,
      "tx_type": "contract_call",
      "sender": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
      "status": "success",
      "fee": "3000",
      "nonce": "265",
      "sponsored": false,
      "anchor_mode": "any",
      "post_condition_mode": "deny",
      "post_conditions": [
        {
          "type": "ft",
          "principal": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
          "asset_identifier": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token",
          "condition_code": 1,
          "condition_code_name": "sent_eq",
          "amount": "300"
        }
      ],
      "contract_call": {
        "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
        "function_name": "transfer",
        "function_args": [
          "300",
          "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
          "SPD3SCZDZ52X4ZX1878XWBFBJ29YRX0MFW9Z9W4V",
          null
        ],
        "function_args_hex": [
          "010000000000000000000000000000012c",
          "05164ba0f04696ab911b7009e3421913e1f5768c2224",
          "05161a3cb3edf945d27fa141d1de2deb9093ec74147f",
          "09"
        ],
        "result": true,
        "result_hex": "0x0703"
      }
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### Transaction by tx_id

`GET /v1/index/transactions/{tx_id}`

One transaction document, only if it sits in a canonical block. A transaction still pending is at `/v1/index/mempool/{tx_id}`. Not metered.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `tx_id` | string, required | Transaction id, `0x`-prefixed hex. |

#### Responses

- `200` The transaction and the tip it was read against
- `401` This bind requires the instance token, and it was missing or wrong
- `404` No canonical transaction with that id (`Transaction not found`)
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/transactions/{tx_id} \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "transaction": {
    "cursor": "9048502:1",
    "tx_id": "0x198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
    "block_height": 9048502,
    "block_time": "2026-09-23T13:14:42.000Z",
    "burn_block_height": 968276,
    "tx_index": 1,
    "tx_type": "contract_call",
    "sender": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
    "status": "success",
    "fee": "3000",
    "nonce": "265",
    "sponsored": false,
    "anchor_mode": "any",
    "post_condition_mode": "deny",
    "post_conditions": [
      {
        "type": "ft",
        "principal": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
        "asset_identifier": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token",
        "condition_code": 1,
        "condition_code_name": "sent_eq",
        "amount": "300"
      }
    ],
    "contract_call": {
      "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
      "function_name": "transfer",
      "function_args": [
        "300",
        "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
        "SPD3SCZDZ52X4ZX1878XWBFBJ29YRX0MFW9Z9W4V",
        null
      ],
      "function_args_hex": [
        "010000000000000000000000000000012c",
        "05164ba0f04696ab911b7009e3421913e1f5768c2224",
        "05161a3cb3edf945d27fa141d1de2deb9093ec74147f",
        "09"
      ],
      "result": true,
      "result_hex": "0x0703"
    }
  },
  "tip": {
    "block_height": 9048938,
    "finalized_height": 9048671,
    "lag_seconds": 23,
    "source_block_height": 9048938
  }
}
```

### Transaction inclusion proof

`GET /v1/index/transactions/{tx_id}/proof`

What you need to check, without trusting this API, that a transaction is in a signed Nakamoto block: the raw tx, the raw block header, and the tx merkle path. `consensus` adds the cycle's signer set when the node can resolve it. The SDK's `verifyTransactionProof` runs every check. The instance must reach its Stacks node. Immutable once served.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `tx_id` | string, required | Transaction id, `0x`-prefixed hex. |

#### Returns

One `TransactionProof` object.

#### Responses

- `200` The inclusion proof
- `401` This bind requires the instance token, and it was missing or wrong
- `404` The transaction or its block is not indexed or not on the node (`PROOF_UNAVAILABLE`)
- `429` Rate limited; retry after `Retry-After` seconds
- `503` The Stacks node is unreachable (`PROOF_NODE_UNAVAILABLE`), or the stored transactions do not reproduce the block's merkle root (`PROOF_TX_SET_INCOMPLETE`)

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/transactions/{tx_id}/proof \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "txid": "198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
  "index_block_hash": "990152a894e12288960c8b68e5790ad7994f9d261e9ad8adc13c72e76f914339",
  "block_height": 9048502,
  "tx_index": 1,
  "raw_tx": "000000000104004ba0f04696ab911b7009e3421913e1f5768c222400000000000001090000000000000bb8000123767ba956a0545b2543f059d003500767330fad1f4e6cce3d734c8719bfca9226c07dc6e64edb83078cb34e83c6b430d4a260628af821041f51eb5f21e444390302000000010102164ba0f04696ab911b7009e3421913e1f5768c222414f6decc7cfff2a413bd7cd4f53c25ad7fd1899acc0a736274632d746f6b656e0a736274632d746f6b656e01000000000000012c0214f6decc7cfff2a413bd7cd4f53c25ad7fd1899acc0a736274632d746f6b656e087472616e7366657200000004010000000000000000000000000000012c05164ba0f04696ab911b7009e3421913e1f5768c222405161a3cb3edf945d27fa141d1de2deb9093ec74147f09",
  "raw_header": "0100000000008a11b60000006643539084f394038c2267d08e5e5c52b9da2d99f4360c91a5314c3cac40ac15f4397b92360ccaa5adaeda6ebc5587511f33b1495fe1d1f66d10b0bfc1ef83918390f25ad4f0b7f5ddf76fa79782e92da2315856590664d9c179ccc0143e35f99140069ea4517ab4ca79e39f0e54b406b1b68b5f8c29e25750000000006ab3d0c2012ae8acc3a85100ae9eecf07468c694fee3cb585c423a0df3054991c77f4fa3fb4fc7b300f1b332f02ec0488c4033c7eb72abec17999c01326d222225f430e56d000000130016f1a9fb8ef3c85b04bd863818f4b47680de8f33e375b2872fbdd5b94d1664624488458f13383478becec32e9ce8ac9b2d0292d2773b37bf1c5943e87cf35b31006dbcd0a22c1eaf81d34dd1c2f25a1e05b7d6e5fdd3c5d8c7e4b96aa4472088e14d8b7ece3427f77fbcfd4027e7bd27be1388ddb68efb8debf8dfe48da558987400e3df41a2cc852d41b6db8f67c8e6c7bf1c31d185c87b019d349a5d6713c951ca43837c05b62a9f0b58ac4403a98233f1e1573e031fae90306ccd618dff1ce8eb01f4bba3a39010779d4870906d1f7e66115b8146f6b70b4e4fee3a402fa484c1d40146832b8fb21ab3328d7588e3861d9c614522692bd14fb763c77a2203d0b86a010075c0105d54deac9a6388734e0519d7ba90024727f02d65b8fd2cd788eca9350c6f6c7ff52200e41cefbf19873bcb9c17068ca9b093fd032dd68683348e95550083c787948e7bd477341747c8769ce2e9c8a420cb137d3609b5e90163f0c56ac3747219c113b0b5018aefa1dc9bd415b21b48173cb9c42f96f19cf143a77261340092179e100c58cfc2b3ee3271eca056ad98c986a1b434296eb1bb00986f3c1a7e70d89fdcbb983f216b9b9d5b5bf21093f58bf2e022fb0010f6706010ebe8c09f01bf06697f3e93883ebf59f83a98bc032d7b3da70886b6e44309cd77855dc1bf8c099084b40609c0a4e3d04806a0fd23391ad79745ba52b122838e3edf6359aa2d006d529e1f590e58b3d1519b719d1149e1babfa1cf20b164167199da2804dec7004159c9f6cb90f265b0d7c3338905de677087bbf9e40a7f06159a4697014756c501726fe445f8a4c876138ff40581e34a659463f97d7b2d1cc843b82d5c8ec9cd2e326ab34b509f4c193f424ebd2ddd729f007687c88b66af59ddda1036b1c7da8700d9a1b7f528df90661c608fd1935d95abb0f638b780573101837863353daf50c529e02703891e885ffa2603ca19a8ab1724c07795e6ab458e93abdca27ac67c3600c4202f95645edb945c2659345fd1dc5043d9fd178c398ddb2ed55ffc5bb9c62f2a61ada05578631cd6523fadf4a47be96133216b5cd421222a1289914ec41d5600ae2119da699f9eea1a8c49b0cf63c2ed5191d141491f11893869e04f24ad14d20dabc52b11e4418cd46610709c7d6456ff0a235760dc39c7e4c057fc8802fa4101813c588a7730569283f517b53949f67aa46a214530dab382da6ec3afc7014ede023706361ec717f8487a88f9d8ae9f912b3033124fccf8c98e5bcf382208febf016ad6d2d6a0c77ae937dc663b7111ab145e4df0248bcb1da80dce6b5bf0061539705f37412cf59476a22ee6677c20c9b980f263f8c1d4c79acd8d7166ff1a7b4f00aecd8f47fee2d6819993aa0d2e3e4872e2a95550c7403491f9764ebfa832f38b61704739abda8cfb0e05d8020efa5e49a5704dbd82f79fd3638b61005c37867c00025ea0925e7583f2f43c9ad4ff6ceaa8ef6bb62cb15265ebf684ca9005f5bb9312009b7e7bc171291c4c2530b74b275e57fc53072cd381a1cb27dc63232c0835007a5b80bc0b5af6848568468cc2a10f74789e1a1e0bcf6f18bb45f8df4e7a19f55c26f593b23aa76c2b7171aff4b062a58f6611da097071298621735521c7ee110062254da4170c6e66963e8a74c9a4fb5797e4247f5ccd8784c82d70ae96f5f01644e6b7733ca93f0e065fc165e152b4abd602687f2f081ab39c8f0943d3b51ea90001000000010100000000",
  "tx_merkle_path": [
    {
      "position": "left",
      "hash": "ea5ecd867b9945b06aecdf77117de46ae9fd055b137be1fecc1dee38f56b19af"
    },
    {
      "position": "right",
      "hash": "398e676d798b758c66c50e21a83b4c6c8c20a5ffc8552b61d1df160f36a0c23c"
    },
    {
      "position": "right",
      "hash": "d1315b8f5f61861868657a0ab2c8c62332bb77a74a833567427a9f95ab86c1eb"
    }
  ],
  "consensus": {
    "reward_cycle": 143,
    "reward_set": {
      "signers": [
        {
          "signing_key": "0209130bec93e83b23d3366adfcbe0a1641057b9c48102572d892fe8f78de2bee7",
          "weight": 646
        },
        {
          "signing_key": "0216436e7785e1dc55cf4350ac1f90e45daf0ec5b57bce13a32551a513446e71d1",
          "weight": 9
        }
      ],
      "total_weight": 4000
    }
  }
}
```

## Mempool

Pending transactions before they confirm.

### Pending transactions

`GET /v1/index/mempool`

Pending transactions this instance's node has seen since the observer connected, in arrival order. A single-node, go-forward view: the backlog from before the observer connected is never replayed. Confirmed transactions leave the list. No height window. Never cached.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `sender` | string | Sender principal. Exact match. |
| `type` | string | Transaction type as stored, e.g. `contract_call`, `token_transfer`. Exact match. |
| `contract_id` | string | Called contract. Exact match. |
| `function_name` | string | Called function. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | Opaque `next_cursor` from a previous page. Pass it back unchanged. Mutually exclusive with `from_cursor`. |
| `from_cursor` | string | Same as `cursor`. |

#### Returns

A cursor envelope; `mempool` holds `MempoolTransaction` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/mempool \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "mempool": [
    {
      "cursor": "bToyNjg4Mjc0",
      "tx_id": "0x00a5cd852c25c5bb5cc7f97c60b88a6a635c001ad431e2133f366be85d5ce0f0",
      "tx_type": "token_transfer",
      "sender": "SM1Z09F6431EQT8GCTEF496TCT5JDTPJ3VFF9Q766",
      "received_at": "2026-09-23T15:11:05.629Z",
      "fee": "1732",
      "nonce": "37",
      "sponsored": false,
      "anchor_mode": "any",
      "post_condition_mode": "deny",
      "post_conditions": [],
      "token_transfer": {
        "recipient": "SMJWA5YRH2DRANX3V96Z6JJSFBE03Z9Y0WHN3XSQ",
        "amount": "79559850769",
        "memo": "572826509"
      }
    }
  ],
  "next_cursor": "bToyNjg4Mjc0",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  }
}
```

### Pending transaction by tx_id

`GET /v1/index/mempool/{tx_id}`

One pending transaction. It 404s once the transaction confirms (read it from `/v1/index/transactions/{tx_id}`) or drops. Never cached.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `tx_id` | string, required | Transaction id, `0x`-prefixed hex. |

#### Responses

- `200` The pending transaction and the current tip
- `401` This bind requires the instance token, and it was missing or wrong
- `404` Not pending on this instance: confirmed, dropped, or never seen (`Pending transaction not found`)
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/mempool/{tx_id} \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "transaction": {
    "cursor": "bToyNjg4Mjc0",
    "tx_id": "0x00a5cd852c25c5bb5cc7f97c60b88a6a635c001ad431e2133f366be85d5ce0f0",
    "tx_type": "token_transfer",
    "sender": "SM1Z09F6431EQT8GCTEF496TCT5JDTPJ3VFF9Q766",
    "received_at": "2026-09-23T15:11:05.629Z",
    "fee": "1732",
    "nonce": "37",
    "sponsored": false,
    "anchor_mode": "any",
    "post_condition_mode": "deny",
    "post_conditions": [],
    "token_transfer": {
      "recipient": "SMJWA5YRH2DRANX3V96Z6JJSFBE03Z9Y0WHN3XSQ",
      "amount": "79559850769",
      "memo": "572826509"
    }
  },
  "tip": {
    "block_height": 9048938,
    "finalized_height": 9048671,
    "lag_seconds": 23,
    "source_block_height": 9048938
  }
}
```

## Contracts

What a contract prints.

### Print payload schemas for a contract

`GET /v1/index/contracts/{contract_id}/print-schema`

Infers the shape of a contract's `print` payloads from its canonical print events, grouped by the tuple's `topic` field. Reads the newest 1500 and oldest 500 events, so fields the contract stopped emitting still show. Takes no query parameters. Held in memory for 5 minutes per contract. Not metered.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `contract_id` | string, required | Contract principal, `<address>.<name>`. Anything that does not look like one is refused. |

#### Returns

One `PrintSchema` object.

#### Responses

- `200` Inferred print schemas
- `400` `contract_id` is not a contract principal, or a query parameter was sent (`VALIDATION_ERROR`)
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/contracts/SP2BM6AQSMQ04CX8KDE62QBFVZTDZ2ZX80GZJSBZ4.zc-claim-helper-v2/print-schema \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "contract_id": "SP2BM6AQSMQ04CX8KDE62QBFVZTDZ2ZX80GZJSBZ4.zc-claim-helper-v2",
  "topics": [
    {
      "topic": "zc-claim-ok",
      "count": 2,
      "first_height": 9004646,
      "last_height": 9004646,
      "non_tuple": false,
      "fields": [
        {
          "name": "earned",
          "camel_name": "earned",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "reward-cycle",
          "camel_name": "rewardCycle",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "staker",
          "camel_name": "staker",
          "clarity_type": "principal",
          "ts_type": "string",
          "column_type": "principal",
          "always_present": true
        },
        {
          "name": "withdrawal-request",
          "camel_name": "withdrawalRequest",
          "clarity_type": "(optional ?)",
          "ts_type": "unknown | null",
          "column_type": "jsonb",
          "always_present": true,
          "optional_some_rate": 0
        }
      ]
    },
    {
      "topic": "claim-many",
      "count": 1,
      "first_height": 9004646,
      "last_height": 9004646,
      "non_tuple": false,
      "fields": [
        {
          "name": "err-count",
          "camel_name": "errCount",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "manager",
          "camel_name": "manager",
          "clarity_type": "principal",
          "ts_type": "string",
          "column_type": "principal",
          "always_present": true
        },
        {
          "name": "ok-count",
          "camel_name": "okCount",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "submitted",
          "camel_name": "submitted",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        }
      ]
    }
  ],
  "sampled": false,
  "total_events": 3,
  "total_events_capped": false,
  "sample": {
    "size": 3,
    "newest_height": 9004646,
    "oldest_height": 9004646
  },
  "tip": {
    "block_height": 9048938,
    "finalized_height": 9048671,
    "lag_seconds": 23,
    "source_block_height": 9048938
  }
}
```

## State writes

Every map and variable write, in order.

### State writes

`GET /v1/index/state-writes`

The exact MARF writes each canonical block committed, in the node's write order: every changed leaf of the block's state trie, named. Oldest first; the cursor is `<block_height>:<ordinal>`. `block_height` reads one block. Present only from the height this instance's node subscribed to the `state_writes` observer key, with no earlier history. The window follows the ingest tip. `reorgs` overlaps by height.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `block_height` | integer | Read one block: the same as `from_height` and `to_height` both set to it, which it excludes. A cursor with it must sit at that height. |
| `contract_id` | string | One contract, `<address>.<contract-name>`: only keys under `vm::<contract_id>::` (its data maps, data vars and token balances). Exact, no wildcards. |
| `tx_context` | boolean | `true` adds the writing transaction's `tx_id`, `tx_sender`, `tx_type`, `tx_status`, `tx_contract_id` and `tx_function_name` to each row; null for block-level writes. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<ordinal>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |

#### Returns

A cursor envelope; `state_writes` holds `StateWrite` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/state-writes \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "state_writes": [
    {
      "cursor": "100:1",
      "block_height": 100,
      "ordinal": 1,
      "tx_index": 0,
      "key": "vm::ST3FEXKRAY93SR2MERXNSAXWGV9XSDNM1MVEFY5TH.store::0::map::0d0000000568656c6c6f",
      "value_hex": "30313030303030303030303030303030303030303030303030303030303030303031"
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

## PoX

Stacking actions, reward cycles and PoX-5 events.

### PoX-4 stacking actions

`GET /v1/index/stacking`

Decoded PoX-4 contract calls (`stack-stx`, `delegate-stx`, `stack-aggregation-commit-indexed`, …), one row per call, oldest first. Pages on `<block_height>:<tx_index>`. With no cursor or `from_height`, the read covers the last day. PoX-4 stopped at the epoch 4.0 fork, so read history with `from_height` and use `/v1/index/pox5/events` for what came after.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `function_name` | string | PoX-4 function name, e.g. `stack-stx` or `delegate-stack-stx`. Exact match. |
| `stacker` | string | Stacker principal named in the call. Exact match. Solo `stack-stx` calls leave it null, so filter those by `caller`. |
| `caller` | string | Transaction sender. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<tx_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |

#### Returns

A cursor envelope; `stacking` holds `StackingAction` objects.

#### Responses

- `200` Cursor-paginated envelope
- `304` The page is past finality and matches your `If-None-Match` ETag.
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/stacking \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "stacking": [
    {
      "cursor": "8647822:1",
      "block_height": 8647822,
      "block_time": "2026-07-27T18:39:09.000Z",
      "burn_block_height": 959869,
      "tx_id": "0x995fb653065c74596b63e6cc9c10fb8fa7b8f3574d5ea089b45d3e11d9e7336e",
      "tx_index": 1,
      "function_name": "stack-stx",
      "caller": "SP14S259H3AC9PXWJ8EVX9ER5NZ58R03GR4QAKHCB",
      "stacker": null,
      "delegate_to": null,
      "amount_ustx": "4491100000000",
      "lock_period": 1,
      "pox_addr": {
        "version": 6,
        "hashbytes": "0x6f0fbc92d6ad56a9d7783b7420ae6731434831e3484d82ad54afe32d7fc7ad6d",
        "btc": "bc1pdu8meykk44t2n4mc8d6zptn8x9p5sv0rfpxc9t254l3j6l7844ksz4jjcs"
      },
      "start_cycle": 139,
      "end_cycle": 139,
      "reward_cycle": null,
      "signer_key": "0x031b91a32ab90b80d40715e8875fb3dfe996aa1e6f5e62ba05d34542aa58ad43b5",
      "result_ok": true
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### Reward cycles of the current PoX (PoX-5)

`GET /v1/index/pox/cycles`

One row per pox-5 reward cycle, descending, exact to the node: total stacked, reward-eligible STX, bond sats, sBTC custodied, rewards allocated/claimed, and cumulative rewards-per-token. Without a cursor, your list starts at the next reward cycle (the current one plus one) and goes back in time. Pass a higher `cursor` to reach cycles further in the future, which PoX-5 bonds can lock many cycles ahead. `pox_version` marks the era; at the next PoX fork this endpoint follows the chain and reports the new PoX instead. PoX-4 history is final and not served here; rebuild it from `/v1/index/stacking` on a self-hosted instance. Frozen cycles cache for an hour; the still-open current cycle caches briefly.

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 100 | Cycles per page, 1 to 100. Defaults to 20; anything else is refused. |
| `cursor` | integer | `next_cursor` from the previous page, or any reward cycle (exclusive) to page from. Returns cycles below it. Omit it and the list starts at the next reward cycle. |

#### Returns

A cursor envelope; `cycles` holds `Pox5Cycle` objects.

#### Responses

- `200` Reward cycles, descending from the next reward cycle
- `400` `limit` or `cursor` is out of range, or an unknown parameter was sent
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/pox/cycles \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "pox_version": 5,
  "cycles": [
    {
      "reward_cycle": 141,
      "start_burn_height": 962150,
      "prepare_start_burn_height": 962050,
      "end_burn_height": 964249,
      "total_stacked_ustx": "392447554847960",
      "reward_eligible_ustx": "392447554847960",
      "stakers": 3035,
      "signers_in_set": 36,
      "bond_sats": {
        "1": "23017037628"
      },
      "bond_total_sats": "23017037628",
      "sbtc_custodied_sats": "16016587628",
      "rewards_allocated_stx": "297713728",
      "rewards_allocated_bond": "13810222",
      "reserve_deposit": "52537716",
      "rewards_per_token_stx": "758607677183",
      "rewards_per_token_bond": {
        "1": "599999974940302"
      },
      "distributions": 2,
      "rewards_claimed": "162018760",
      "computed_through_height": 8665732,
      "is_current": false,
      "is_frozen": true
    }
  ],
  "next_cursor": 141,
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  }
}
```

### A PoX-5 reward cycle by cycle number

`GET /v1/index/pox/cycles/{reward_cycle}`

One pox-5 reward cycle, the same shape as a row of `/v1/index/pox/cycles` plus its per-signer breakdown. 404 when the cycle doesn't exist yet. A cycle number below 141 (pox-5's first) 404s with a note that PoX-4 cycles are final and not served here.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `reward_cycle` | integer, required | Reward cycle number. |

#### Responses

- `200` The cycle, with its signers
- `400` `reward_cycle` is not a non-negative integer
- `401` This bind requires the instance token, and it was missing or wrong
- `404` The cycle doesn't exist yet, or (below 141) is PoX-4 history: final and not served here; rebuild it from /v1/index/stacking on a self-hosted instance
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/pox/cycles/141 \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "pox_version": 5,
  "cycle": {
    "reward_cycle": 141,
    "start_burn_height": 962150,
    "prepare_start_burn_height": 962050,
    "end_burn_height": 964249,
    "total_stacked_ustx": "392447554847960",
    "reward_eligible_ustx": "392447554847960",
    "stakers": 3035,
    "signers_in_set": 36,
    "bond_sats": {
      "1": "23017037628"
    },
    "bond_total_sats": "23017037628",
    "sbtc_custodied_sats": "16016587628",
    "rewards_allocated_stx": "297713728",
    "rewards_allocated_bond": "13810222",
    "reserve_deposit": "52537716",
    "rewards_per_token_stx": "758607677183",
    "rewards_per_token_bond": {
      "1": "599999974940302"
    },
    "distributions": 2,
    "rewards_claimed": "162018760",
    "computed_through_height": 8665732,
    "is_current": false,
    "is_frozen": true,
    "signers": [
      {
        "signer": "SPMPMA1V6P430M8C91QS1G9XJ95S59JS1TZFZ4Q4.fastpool-max500-signer-manager",
        "delegated_ustx": "51000000000000",
        "stx_only_ustx": "51000000000000",
        "reward_shares_ustx": "51000000000000",
        "in_set": true,
        "rewards_claimed": "19011164"
      }
    ]
  },
  "tip": {
    "block_height": 9048929,
    "finalized_height": 9048671,
    "lag_seconds": 22,
    "source_block_height": 9048929
  }
}
```

### Decoded PoX-5 boot-contract events

`GET /v1/index/pox5/events`

Decoded print log of the pox-5 boot contract (SIP-045 Bitcoin Staking) — all 19 topics (stake, stake-update, register-signer, unstake, claim-rewards, etc.), one row per print. Starts at the epoch 4.0 hard fork, where /v1/index/stacking's pox-4 feed ends.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `topic` | enum | One print topic. Omit for all of them. Values: `set-bond-admin`, `set-pause-admin`, `pause-rewards`, `setup-bond`, `add-to-allowlist`, `register-for-bond`, `update-bond-registration`, `register-signer`, `stake`, `stake-update`, `announce-l1-early-exit`, `unstake-sbtc`, `unstake`, `calculate-rewards`, `bond-distribution`, `claim-rewards`, `claim-staker-rewards-for-signer`, `grant-signer-key`, `revoke-signer-grant`. |
| `staker` | string | Staker principal. Exact match. |
| `signer` | string | The signer: a signer-manager contract. Set on every topic that involves a signer, so `signer=` returns a pool's full activity. |
| `signer_manager` | string | The same principal, as printed on claim and grant topics (`claim-rewards`, `claim-staker-rewards-for-signer`, `grant-signer-key`, `revoke-signer-grant`). Kept for compatibility; `signer` covers it. |
| `bond_index` | integer | Bond index. Exact match. |
| `reward_cycle` | integer | Reward cycle. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `confirmed` | boolean | `true` stops the page at the finality boundary, so every row is past the reorg margin. |
| `fields` | string | Comma-separated columns to return. `cursor`, `block_height` and `topic` always come back; an unknown name is refused. |

#### Returns

A cursor envelope; `events` holds `Pox5Event` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl -G https://api.secondlayer.tools/v1/index/pox5/events \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY" \
  -d topic=stake \
  -d signer=SP8HK160YD5GHXP69VGA0TC7AQJ1X4CDW3XVERSE.xverse-signer-manager-3
```

```json
{
  "events": [
    {
      "cursor": "9048679:0",
      "block_height": 9048679,
      "block_time": "2026-09-23T13:55:35.000Z",
      "tx_id": "0xba5c3e57f65a7e92f917c0e8c32bdf11cedb31baefe708c8a3b9177437420ea9",
      "tx_index": 0,
      "event_index": 0,
      "topic": "stake",
      "staker": "SP19YK5M97734AJZAA2X8W6J9GGNVM9JFZ751H0F1",
      "signer": "SP8HK160YD5GHXP69VGA0TC7AQJ1X4CDW3XVERSE.xverse-signer-manager-3",
      "signer_manager": null,
      "bond_index": null,
      "amount_ustx": "550000000",
      "amount_sats": null,
      "reward_cycle": null,
      "first_reward_cycle": 144,
      "unlock_cycle": 240,
      "unlock_burn_height": 1170050,
      "is_l1_lock": null,
      "signer_key": null,
      "data": {
        "topic": "stake",
        "signer": "SP8HK160YD5GHXP69VGA0TC7AQJ1X4CDW3XVERSE.xverse-signer-manager-3",
        "staker": "SP19YK5M97734AJZAA2X8W6J9GGNVM9JFZ751H0F1",
        "num-cycles": "96",
        "amount-ustx": "550000000",
        "unlock-cycle": "240",
        "first-reward-cycle": "144",
        "unlock-burn-height": "1170050"
      }
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

## Runes

The rune catalog, activity and balances.

### Rune catalog

`GET /v1/index/runes`

Every etched rune, with the identity bundle (id, name, spaced_name, symbol, divisibility) every Runes response carries plus its computed supply, mint/burn counters and mint terms. `search` prefix-matches the name (spacers and case ignored); `sort` is etch order (`number`, default) or busiest-first (`mints`).

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `search` | string | Name prefix, spacers and case ignored (e.g. `dog` matches `DOG•GO•TO•THE•MOON`). |
| `sort` | enum | `number` (etch order, oldest first — default) or `mints` (busiest first). Values: `number`, `mints`. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `cursor` | string | Opaque token from a previous page's `next_cursor`. Resumes after it — pass back unchanged. |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |

#### Returns

A cursor envelope; `runes` holds `RuneEntry` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/runes \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "runes": [
    {
      "id": "840000:3",
      "number": "3",
      "name": "DOGGOTOTHEMOON",
      "spaced_name": "DOG•GO•TO•THE•MOON",
      "symbol": "🐕",
      "divisibility": 5,
      "premine": "10000000000000000",
      "supply": "10000000000000000",
      "burned": "2440680717188",
      "mints": "0",
      "turbo": false,
      "etching_txid": "e79134080a83fe3e0e06ed6990c5a9b63b362313341745707a2bff7d788a1375",
      "etched_height": 840000,
      "etched_tx_index": 3,
      "terms": null
    }
  ],
  "tip": {
    "block_height": 968925,
    "finalized_height": 968919,
    "lag_seconds": 210
  },
  "reorgs": [
    {
      "id": "7",
      "detected_at": "2026-08-11T04:22:10.000Z",
      "fork_point_height": 851203,
      "old_hash": "0000000000000000000123abc1230000000000000000000000000000000000",
      "new_hash": "0000000000000000000456def4560000000000000000000000000000000000",
      "orphaned_from": 851203,
      "orphaned_to": 851204,
      "new_tip_height": 851205
    }
  ]
}
```

### A single rune's entry

`GET /v1/index/runes/{rune}`

One rune's full entry by id or name, with computed `supply` (`premine + mints × terms.amount`). 404 when no rune matches.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `rune` | string, required | A rune id (`<block>:<tx>`, e.g. `840000:3`) or name — spacers and case are ignored, so `DOG•GO•TO•THE•MOON`, `dog.go.to.the.moon` and `doggotothemoon` are the same rune. |

#### Responses

- `200` The rune
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `404` No rune matches this id/name, or Runes isn't configured on this instance (`code: NOT_FOUND`, the latter case also carries `details.notes`)
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/runes/840000:3 \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "rune": {
    "id": "840000:3",
    "number": "3",
    "name": "DOGGOTOTHEMOON",
    "spaced_name": "DOG•GO•TO•THE•MOON",
    "symbol": "🐕",
    "divisibility": 5,
    "premine": "10000000000000000",
    "supply": "10000000000000000",
    "burned": "2440680717188",
    "mints": "0",
    "turbo": false,
    "etching_txid": "e79134080a83fe3e0e06ed6990c5a9b63b362313341745707a2bff7d788a1375",
    "etched_height": 840000,
    "etched_tx_index": 3,
    "terms": null
  },
  "tip": {
    "block_height": 968925,
    "finalized_height": 968919,
    "lag_seconds": 210
  }
}
```

### Rune etches, mints, transfers and burns

`GET /v1/index/runes/activity`

Every rune-moving event — etch, mint, transfer, burn — filterable by rune/address/kind/txid and cursor-paginated. Returns events[], next_cursor, tip, reorgs[]. Cursor: <block_height>:<event_index>, same shape as every other decoded-event feed.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `rune` | string | A rune id (`<block>:<tx>`, e.g. `840000:3`) or name — spacers and case are ignored, so `DOG•GO•TO•THE•MOON`, `dog.go.to.the.moon` and `doggotothemoon` are the same rune. |
| `address` | string | Mainnet Bitcoin address. Exact match. |
| `kind` | string | One or more of `rune_etch`, `rune_mint`, `rune_transfer`, `rune_burn`, comma-separated. |
| `txid` | string | Bitcoin txid, hex with no `0x` prefix (Rune txids come back as stored, unlike Stacks ones). Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |

#### Returns

A cursor envelope; `events` holds `RuneEvent` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl -G https://api.secondlayer.tools/v1/index/runes/activity \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY" \
  -d rune=840000:3 \
  -d kind=rune_mint,rune_transfer
```

```json
{
  "events": [
    {
      "cursor": "968919:3",
      "block_height": 968919,
      "tx_index": 144,
      "txid": "77c95d193e680429fe7f801a68488bd30919d011f23542141a7fae5244b002b4",
      "event_index": 3,
      "kind": "rune_transfer",
      "amount": "2933553300",
      "vout": 2,
      "address": "bc1pjku9h7ckjt8802mu79zt7vv8d6mhp0x57gkppcls57ex4rkq9cxqs52pr3",
      "rune": {
        "id": "840000:3",
        "name": "DOGGOTOTHEMOON",
        "spaced_name": "DOG•GO•TO•THE•MOON",
        "symbol": "🐕",
        "divisibility": 5
      }
    }
  ],
  "tip": {
    "block_height": 968925,
    "finalized_height": 968919,
    "lag_seconds": 210
  },
  "reorgs": [
    {
      "id": "7",
      "detected_at": "2026-08-11T04:22:10.000Z",
      "fork_point_height": 851203,
      "old_hash": "0000000000000000000123abc1230000000000000000000000000000000000",
      "new_hash": "0000000000000000000456def4560000000000000000000000000000000000",
      "orphaned_from": 851203,
      "orphaned_to": 851204,
      "new_tip_height": 851205
    }
  ]
}
```

### Rune balances by address or outpoint

`GET /v1/index/runes/balances`

Current per-outpoint rune balances. Exactly one of `address` or `outpoint` is required; `rune` narrows either to one rune. Returns balances[], next_cursor, tip.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `address` | string | Mainnet Bitcoin address. Mutually exclusive with `outpoint`; exactly one is required. |
| `outpoint` | string | `<txid>:<vout>`. Mutually exclusive with `address`; exactly one is required. |
| `rune` | string | A rune id (`<block>:<tx>`, e.g. `840000:3`) or name — spacers and case are ignored, so `DOG•GO•TO•THE•MOON`, `dog.go.to.the.moon` and `doggotothemoon` are the same rune. Narrows the result to one rune. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `cursor` | string | Opaque token from a previous page's `next_cursor`. Resumes after it — pass back unchanged. |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |

#### Returns

A cursor envelope; `balances` holds `RuneBalance` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl -G https://api.secondlayer.tools/v1/index/runes/balances \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY" \
  -d outpoint=2d2b54008790a44c9c3e630faa521a50f8ab122625c4eb8fb84705051c4fc611:0 \
  -d rune=840000:3
```

```json
{
  "balances": [
    {
      "rune": {
        "id": "840000:3",
        "name": "DOGGOTOTHEMOON",
        "spaced_name": "DOG•GO•TO•THE•MOON",
        "symbol": "🐕",
        "divisibility": 5
      },
      "address": "bc1phnp234rd5hel0h8ulqvnq3zrww2td0a8q48hjcg7mv67j97jnxfq9ayczm",
      "txid": "2d2b54008790a44c9c3e630faa521a50f8ab122625c4eb8fb84705051c4fc611",
      "vout": 0,
      "amount": "88980600"
    }
  ],
  "tip": {
    "block_height": 968925,
    "finalized_height": 968919,
    "lag_seconds": 210
  },
  "reorgs": [
    {
      "id": "7",
      "detected_at": "2026-08-11T04:22:10.000Z",
      "fork_point_height": 851203,
      "old_hash": "0000000000000000000123abc1230000000000000000000000000000000000",
      "new_hash": "0000000000000000000456def4560000000000000000000000000000000000",
      "orphaned_from": 851203,
      "orphaned_to": 851204,
      "new_tip_height": 851205
    }
  ]
}
```

## sBTC

Peg-ins, peg-outs and the peg summary.

### Decoded sBTC peg events

`GET /v1/index/sbtc/events`

Every decoded `sbtc-registry` print, all topics, one row per event, oldest first: deposits, withdrawal create/accept/reject, signer key rotations and protocol-contract updates. With no cursor or `from_height`, the read covers the last day.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `topic` | enum | One print topic. Omit for all of them; an unknown topic is refused. Values: `completed-deposit`, `withdrawal-create`, `withdrawal-accept`, `withdrawal-reject`, `key-rotation`, `update-protocol-contract`. |
| `sender` | string | Stacks principal on the event (the withdrawal requester on `withdrawal-create`). Exact match. |
| `request_id` | integer | Withdrawal request id. Exact match. |
| `bitcoin_txid` | string | Bitcoin txid on the event, `0x`-prefixed hex. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `confirmed` | boolean | `true` stops the page at the finality boundary, so every row is past the reorg margin. |

#### Returns

A cursor envelope; `events` holds `SbtcEvent` objects.

#### Responses

- `200` Cursor-paginated envelope
- `304` The page is past finality and matches your `If-None-Match` ETag.
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/sbtc/events \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "events": [
    {
      "cursor": "9048486:2",
      "block_height": 9048486,
      "block_time": "2026-09-23T13:10:19.000Z",
      "tx_id": "0x0e09fd3cf7628a2cc81083aa9dbb7eebc7bae5cbe277c370e0f8bfc3d1fe00a9",
      "tx_index": 2,
      "event_index": 2,
      "topic": "withdrawal-create",
      "request_id": 3406,
      "amount": "3127",
      "sender": "SP2ADCJ6606CFHERS3HKABWB6PF5XBANXBQ4GSE86",
      "recipient_btc_version": 4,
      "recipient_btc_hashbytes": "0x9c32e45a19cf9c028bccf12816e62bbfc8eb5fb8",
      "bitcoin_txid": null,
      "output_index": null,
      "sweep_txid": null,
      "burn_hash": null,
      "burn_height": null,
      "signer_bitmap": null,
      "max_fee": "1500",
      "fee": null,
      "governance_contract_type": null,
      "governance_new_contract": null,
      "signer_aggregate_pubkey": null,
      "signer_threshold": null,
      "signer_address": null,
      "signer_keys_count": null
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### Completed sBTC deposits

`GET /v1/index/sbtc/deposits`

Completed deposits, one row per `completed-deposit` event, oldest first. The event fires once the signers have swept the BTC in, so every row is final on the peg side. With no cursor or `from_height`, the read covers the last day.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `sender` | string | Stacks principal on the event. Exact match. Mainnet deposits currently carry none. |
| `bitcoin_txid` | string | Deposit's Bitcoin txid, `0x`-prefixed hex. Exact match. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `confirmed` | boolean | `true` stops the page at the finality boundary, so every row is past the reorg margin. |
| `fields` | string | Comma-separated columns to return, from: `block_time`, `tx_id`, `tx_index`, `event_index`, `amount`, `sender`, `bitcoin_txid`, `output_index`, `recipient_btc_version`, `recipient_btc_hashbytes`. `cursor` and `block_height` always come back; an unknown name is refused. |

#### Returns

A cursor envelope; `deposits` holds `SbtcDeposit` objects.

#### Responses

- `200` Cursor-paginated envelope
- `304` The page is past finality and matches your `If-None-Match` ETag.
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/sbtc/deposits \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "deposits": [
    {
      "cursor": "9048911:4",
      "block_height": 9048911,
      "block_time": "2026-09-23T15:06:29.000Z",
      "tx_id": "0x8600af4a0b2a911e6494d1feea0691068d8b329be0ef2c0d11a7d5aed8f9f4e5",
      "tx_index": 2,
      "event_index": 4,
      "amount": "79856",
      "sender": null,
      "bitcoin_txid": "0x2c11f9e20d21c96daed5d851c07d0e7c4361e552ebd78a8385f06fbb2f9892d3",
      "output_index": 1,
      "recipient_btc_version": null,
      "recipient_btc_hashbytes": null
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### sBTC peg-in by Bitcoin txid

`GET /v1/index/sbtc/deposits/{bitcoin_txid}`

One completed deposit, looked up by the Bitcoin txid of the deposit. Past finality it is cached for good and answers `If-None-Match` with 304.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `bitcoin_txid` | string, required | Deposit's Bitcoin txid, `0x`-prefixed hex, as it appears in `bitcoin_txid`. |

#### Responses

- `200` The deposit
- `304` The resource is past finality and matches your `If-None-Match` ETag.
- `401` This bind requires the instance token, and it was missing or wrong
- `404` No completed deposit has this Bitcoin txid
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/sbtc/deposits/0x2c11f9e20d21c96daed5d851c07d0e7c4361e552ebd78a8385f06fbb2f9892d3 \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "deposit": {
    "cursor": "9048911:4",
    "block_height": 9048911,
    "block_time": "2026-09-23T15:06:29.000Z",
    "tx_id": "0x8600af4a0b2a911e6494d1feea0691068d8b329be0ef2c0d11a7d5aed8f9f4e5",
    "tx_index": 2,
    "event_index": 4,
    "amount": "79856",
    "sender": null,
    "bitcoin_txid": "0x2c11f9e20d21c96daed5d851c07d0e7c4361e552ebd78a8385f06fbb2f9892d3",
    "output_index": 1,
    "recipient_btc_version": null,
    "recipient_btc_hashbytes": null,
    "status": "COMPLETED"
  },
  "tip": {
    "block_height": 9048929,
    "finalized_height": 9048671,
    "lag_seconds": 22,
    "source_block_height": 9048929
  }
}
```

### sBTC withdrawals, one per request

`GET /v1/index/sbtc/withdrawals`

Withdrawals, one row per `request_id`, ordered by when they were requested. Each row carries its current status from the latest accept or reject, the BTC sweep the signers committed to, and that sweep's Bitcoin settlement. The height window and cursor apply to the request event. Status can change after a row is final, so pages are never long-cached.

#### Filters

| Name | Type | Description |
| --- | --- | --- |
| `status` | enum | Current lifecycle status. Values: `REQUESTED`, `ACCEPTED`, `REJECTED`. |
| `sender` | string | Requester's Stacks principal. Exact match. |
| `request_id` | integer | Withdrawal request id. Exact match. |
| `settlement_confirmed` | boolean | `true` returns withdrawals whose sweep has confirmed on Bitcoin. `false` returns the rest, including ones with no sweep yet. |
| `confirmed_after` | string · date-time | ISO 8601 timestamp. Returns only withdrawals whose sweep confirmed on Bitcoin strictly after it. Combine with `from_height=0` to scan all history. |

#### Range and paging

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer · 1 to 1000 | Page size; capped at 1000. |
| `cursor` | string | `<block_height>:<event_index>` from a previous page's `next_cursor`. Resumes after it. |
| `from_cursor` | string | Same as `cursor`. Mutually exclusive with it and with `from_height`. |
| `from_height` | integer | First block height to read. Mutually exclusive with a cursor. With neither, the read starts one day behind the tip. |
| `to_height` | integer | Last block height to read, inclusive. |
| `confirmed` | boolean | `true` stops the page at the finality boundary, so every row is past the reorg margin. |
| `fields` | string | Comma-separated columns to return, from: `status`, `amount`, `sender`, `recipient_btc_version`, `recipient_btc_hashbytes`, `sweep_txid`, `settlement_confirmed`, `btc_confirmations`, `btc_block_height`, `confirmed_at`, `requested_at`, `resolved_at`. `cursor` and `request_id` always come back; an unknown name is refused. |

#### Returns

A cursor envelope; `withdrawals` holds `SbtcWithdrawal` objects.

#### Responses

- `200` Cursor-paginated envelope
- `400` A parameter, filter, cursor or body field was refused; `code` says which
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/sbtc/withdrawals \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "withdrawals": [
    {
      "cursor": "9048225:2",
      "request_id": 3405,
      "status": "ACCEPTED",
      "amount": "221653",
      "sender": "SP2WRMQD3G4G8BR0120Y390CT6A8BTE6MB0JQ5EHA",
      "recipient_btc_version": 4,
      "recipient_btc_hashbytes": "0xa7d5ce640208ed037950d4c849c805e881209d6a",
      "sweep_txid": "0x0efad88eb01e248fd8321ada99cb74f7258948226eae106f8be5a5917d7473e4",
      "settlement_confirmed": true,
      "btc_confirmations": 8,
      "btc_block_height": 968278,
      "confirmed_at": "2026-09-23T14:35:25.473Z",
      "requested_at": "2026-09-23T12:01:45.000Z",
      "resolved_at": "2026-09-23T13:24:47.000Z"
    }
  ],
  "next_cursor": "7960000:42",
  "tip": {
    "block_height": 9048690,
    "finalized_height": 9048457,
    "lag_seconds": 4,
    "source_block_height": 9048692
  },
  "reorgs": [
    {
      "id": "3f16c2c5-9551-4ae9-adb0-923668e5c65e",
      "detected_at": "2026-09-15T15:39:38.129Z",
      "fork_point_height": 8996511,
      "old_index_block_hash": "0x45ba0195071488eda13afa66d8ce8612558a739f781be5a032d96332797c4174",
      "new_index_block_hash": "0xa686ff58e7c5ccb26c850a7eaffa7e7274fcbc081c706344eb6f1e1446023df0",
      "orphaned_range": {
        "from": "8996511:0",
        "to": "8996512:2701"
      },
      "new_canonical_tip": "8996511:0"
    }
  ]
}
```

### sBTC peg-out lifecycle by request_id

`GET /v1/index/sbtc/withdrawals/{request_id}`

One withdrawal's full lifecycle: the request, the accept or reject, and the Bitcoin settlement of its sweep. Once it is accepted or rejected and past finality, it is cached for good and answers `If-None-Match` with 304.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `request_id` | integer, required | Withdrawal request id. |

#### Responses

- `200` The withdrawal's lifecycle
- `304` The resource is past finality and matches your `If-None-Match` ETag.
- `400` `request_id` is not a non-negative integer
- `401` This bind requires the instance token, and it was missing or wrong
- `404` No withdrawal request has this id
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/sbtc/withdrawals/3405 \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "withdrawal": {
    "request_id": 3405,
    "status": "ACCEPTED",
    "amount": "221653",
    "sender": "SP2WRMQD3G4G8BR0120Y390CT6A8BTE6MB0JQ5EHA",
    "recipient_btc_version": 4,
    "recipient_btc_hashbytes": "0xa7d5ce640208ed037950d4c849c805e881209d6a",
    "requested": {
      "block_height": 9048225,
      "block_time": "2026-09-23T12:01:45.000Z",
      "tx_id": "0x0e132d74a062d9327bbf25b371dd3fa7171f5e3479131b046106c1f6086a9780"
    },
    "accepted": {
      "block_height": 9048547,
      "block_time": "2026-09-23T13:24:47.000Z",
      "tx_id": "0xddedcfe67fe6c63339781619867816a69fc054e4a83b7358a8f07e983f2a1b68",
      "sweep_txid": "0x0efad88eb01e248fd8321ada99cb74f7258948226eae106f8be5a5917d7473e4",
      "signer_bitmap": "0"
    },
    "rejected": null,
    "settlement": {
      "sweep_txid": "0x0efad88eb01e248fd8321ada99cb74f7258948226eae106f8be5a5917d7473e4",
      "btc_confirmations": 8,
      "settlement_confirmed": true,
      "btc_block_height": 968278,
      "confirmed_at": "2026-09-23T14:35:25.473Z"
    },
    "finalized": true
  },
  "tip": {
    "block_height": 9048929,
    "finalized_height": 9048671,
    "lag_seconds": 22,
    "source_block_height": 9048929
  }
}
```

### sBTC peg summary scoreboard

`GET /v1/index/sbtc/summary`

All-time totals for the whole bridge: deposit and withdrawal counts, net peg flow, and circulating sBTC supply read from `sbtc-token` on this instance's node. Takes no parameters.

#### Responses

- `200` The bridge totals
- `401` This bind requires the instance token, and it was missing or wrong
- `429` Rate limited; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/index/sbtc/summary \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "summary": {
    "total_deposits": 28077,
    "total_withdrawals_requested": 3408,
    "total_withdrawals_accepted": 3328,
    "total_withdrawals_rejected": 78,
    "net_peg_flow_sats": "247872312898",
    "total_locked_sats": "247872312898",
    "unmatched_withdrawal_accepts": 0,
    "sbtc_supply_sats": "247872312898"
  },
  "tip": {
    "block_height": 9048929,
    "finalized_height": 9048671,
    "lag_seconds": 22,
    "source_block_height": 9048929
  }
}
```

## Bitcoin outputs

Whether an output is spent, and by what.

### Bitcoin output spend status

`GET /v1/bitcoin/outspend/{txid}/{vout}`

Whether one Bitcoin output is spent, and by which transaction, read live from this instance's Bitcoin node. A spend in the mempool shows on the next read, with `mempool: true`. A confirmed spend names its block. The spender of a confirmed spend is found by reading blocks back from the tip, up to 144 of them. A spend deeper than that answers `spent: true` with a null `spending_txid` and a `note`. Answers can change with the mempool and with reorgs, so they are cached for 2 seconds at most. Hosted: one row per answer, 20 requests per second per key. Self-host needs Bitcoin Core 24 or later with `txindex=1` at `BITCOIN_RPC_URL`.

#### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `txid` | string, required | The txid of the transaction that created the output, display order: 64 hex characters, `0x` optional. |
| `vout` | integer, required | The output's index in that transaction, from 0. |

#### Returns

One `BitcoinOutspend` object.

#### Responses

- `200` The output's spend status
- `400` The txid is not 64 hex characters, or vout is not a non-negative integer (`VALIDATION_ERROR`)
- `401` This bind requires the instance token, and it was missing or wrong
- `404` No transaction with that txid, no output at that index, or an `OP_RETURN` output, which can never be spent
- `429` Rate limited; retry after `Retry-After` seconds
- `502` The Bitcoin node could not be read, or lacks a method this needs (`BITCOIN_SOURCE_ERROR`)
- `503` `BITCOIN_UNAVAILABLE`: this instance has no Bitcoin node (`BITCOIN_RPC_URL` unset). `BITCOIN_BUSY`: block reads are at capacity; retry after `Retry-After` seconds

#### Example

```bash
curl https://api.secondlayer.tools/v1/bitcoin/outspend/f80a188d012dbb733748db003b987cc98fc4a636cbd071734decb298c1bad80b/0 \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "txid": "f80a188d012dbb733748db003b987cc98fc4a636cbd071734decb298c1bad80b",
  "vout": 0,
  "spent": true,
  "spending_txid": "3b7a6f0c2d9e1a4b5c8d7e6f0a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3",
  "spending_vin": 0,
  "confirmed": true,
  "mempool": false,
  "block_height": 968470,
  "block_hash": "00000000000000000001c3b0d1a9f5e2e5b2a9c2d0f6c7e1b8a4d3c2b1a09f8e"
}
```

## Discovery

What this index serves.

### Index discovery

`GET /v1/index`

Lists every Index route with its accepted filters, plus the per-`event_type` column and filter vocabulary for `/v1/index/events`. Open: it runs before auth, so it never needs a token.

#### Returns

One `IndexDiscovery` object.

#### Responses

- `200` Index routes and filters

#### Example

```bash
curl https://api.secondlayer.tools/v1/index \
  -H "Authorization: Bearer $SECONDLAYER_API_KEY"
```

```json
{
  "routes": [
    {
      "path": "/v1/index/ft-transfers",
      "method": "GET",
      "description": "Alias for /events?event_type=ft_transfer. Fungible token transfers, decoded + filterable.",
      "filters": [
        "limit",
        "cursor",
        "from_cursor",
        "from_height",
        "to_height",
        "order",
        "contract_id",
        "sender",
        "recipient",
        "asset_identifier",
        "fields"
      ]
    },
    {
      "path": "/v1/index/blocks",
      "method": "GET",
      "description": "Canonical blocks, cursor-paginated. Returns blocks[] ({block_height, block_hash, parent_hash, burn_block_height, burn_block_hash, block_time, canonical}), next_cursor, tip.",
      "filters": [
        "limit",
        "cursor",
        "from_cursor",
        "from_height",
        "to_height"
      ]
    }
  ],
  "cursor": {
    "format": "<block_height>:<event_index>",
    "semantics": "opaque resume token; pass back unchanged to continue. Equals last event's cursor (inclusive on output, exclusive on input). Under order=desc it carries a `desc:` prefix and resumes only under order=desc."
  }
}
```

## Objects

### The Index discovery object

Every Index route with the filters it accepts.

| Field | Type | Description |
| --- | --- | --- |
| `routes` | array of object | One entry per route: `path`, `method`, `description`, and `filters` where it takes any. The `/v1/index/events` entry adds `event_types` and `event_type_filters` (columns and accepted filters per type). |
| `auth` | string | How to authenticate, in prose. |
| `cursor` | object | Cursor format and how to resume with it. |

```json
{
  "routes": [
    {
      "path": "/v1/index/ft-transfers",
      "method": "GET",
      "description": "Alias for /events?event_type=ft_transfer. Fungible token transfers, decoded + filterable.",
      "filters": [
        "limit",
        "cursor",
        "from_cursor",
        "from_height",
        "to_height",
        "order",
        "contract_id",
        "sender",
        "recipient",
        "asset_identifier",
        "fields"
      ]
    },
    {
      "path": "/v1/index/blocks",
      "method": "GET",
      "description": "Canonical blocks, cursor-paginated. Returns blocks[] ({block_height, block_hash, parent_hash, burn_block_height, burn_block_hash, block_time, canonical}), next_cursor, tip.",
      "filters": [
        "limit",
        "cursor",
        "from_cursor",
        "from_height",
        "to_height"
      ]
    }
  ],
  "cursor": {
    "format": "<block_height>:<event_index>",
    "semantics": "opaque resume token; pass back unchanged to continue. Equals last event's cursor (inclusive on output, exclusive on input). Under order=desc it carries a `desc:` prefix and resumes only under order=desc."
  }
}
```

### The Index event object

One decoded event, flat. The universal columns are always there; the rest depend on `event_type`, and a type's own columns are always set for its rows.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the row landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp, ISO 8601 UTC. |
| `tx_id` | string | Transaction id, `0x`-prefixed hex. |
| `tx_index` | integer | The transaction's position in its block. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `event_type` | enum | The event type. Decides which columns are set. Values: `ft_transfer`, `nft_transfer`, `stx_transfer`, `stx_mint`, `stx_burn`, `stx_lock`, `ft_mint`, `ft_burn`, `nft_mint`, `nft_burn`, `print`. |
| `contract_id` | string · nullable | Contract that emitted the event. `null` for STX transfers, mints, burns and locks. |
| `asset_identifier` | string · nullable | `<contract>::<asset>`, on ft and nft types. |
| `sender` | string · nullable | Sending principal. The locked address on `stx_lock`. |
| `recipient` | string · nullable | Receiving principal. |
| `amount` | string · nullable | Amount as a decimal string (bigint-safe). microSTX on STX types. |
| `value` | string · nullable | NFT id as hex-encoded Clarity, on nft types. |
| `memo` | string · nullable | Transfer memo, on `stx_transfer`. |
| `payload` | object | Decoded print payload on `print`; `{ unlock_height }` on `stx_lock`. |
| `tx_sender` | string · nullable | Submitting transaction's sender. Only with `tx_context=true`. |
| `tx_type` | string · nullable | Submitting transaction's type. Only with `tx_context=true`. |
| `tx_status` | string · nullable | Submitting transaction's status. Only with `tx_context=true`. |
| `tx_contract_id` | string · nullable | Contract the submitting transaction called or deployed. Only with `tx_context=true`. |
| `tx_function_name` | string · nullable | Function the submitting transaction called. Only with `tx_context=true`. |

```json
{
  "cursor": "9048921:2",
  "block_height": 9048921,
  "block_time": "2026-09-23T15:09:05.000Z",
  "tx_id": "0x55249ff4ec221ff6852b7fa37cf3729c7c50bc63f0da760f96e6886e2e8a911e",
  "tx_index": 4,
  "event_index": 2,
  "event_type": "stx_transfer",
  "contract_id": null,
  "sender": "SPX4KR3G5Z1SZT4RVF4ATHV4ZP4KXPWSZ4424W6K",
  "recipient": "SP2Z2CBMGWB9MQZAF5Z8X56KS69XRV3SJF4WKJ7J9",
  "amount": "50",
  "memo": null
}
```

### The FT transfer object

One fungible token transfer.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the row landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp, ISO 8601 UTC. |
| `tx_id` | string | Transaction id, `0x`-prefixed hex. |
| `tx_index` | integer | The transaction's position in its block. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `event_type` | enum | Always `ft_transfer`. Values: `ft_transfer`. |
| `contract_id` | string | Token contract. |
| `asset_identifier` | string | `<contract>::<asset>`. |
| `sender` | string | Sending principal. |
| `recipient` | string | Receiving principal. |
| `amount` | string | Amount in the token's base units, as a decimal string (bigint-safe). |

```json
{
  "cursor": "9048918:3",
  "block_height": 9048918,
  "block_time": "2026-09-23T15:08:18.000Z",
  "tx_id": "0xc342cb7616498a84a8dcfac62a991c31c037d8c6f98a11f987f0719fd619e672",
  "tx_index": 2,
  "event_index": 3,
  "event_type": "ft_transfer",
  "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
  "asset_identifier": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token",
  "sender": "SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.v0-8-market",
  "recipient": "SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.v0-vault-sbtc",
  "amount": "15000"
}
```

### The NFT transfer object

One NFT transfer.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the row landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp, ISO 8601 UTC. |
| `tx_id` | string | Transaction id, `0x`-prefixed hex. |
| `tx_index` | integer | The transaction's position in its block. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `event_type` | enum | Always `nft_transfer`. Values: `nft_transfer`. |
| `contract_id` | string | NFT contract. |
| `asset_identifier` | string | `<contract>::<asset>`. |
| `sender` | string | Sending principal. |
| `recipient` | string | Receiving principal. |
| `value` | string | The token id as hex-encoded Clarity. |

```json
{
  "cursor": "9048916:0",
  "block_height": 9048916,
  "block_time": "2026-09-23T15:07:41.000Z",
  "tx_id": "0x269d7877002b998ad3a3ee35f661610cc8f2be6eec604905311d52cf1cf80caa",
  "tx_index": 0,
  "event_index": 0,
  "event_type": "nft_transfer",
  "contract_id": "SPVD6CE8RW90BGGKJZTKCSMGKS7HP0K8364TFR48.bitcoin-faces-airdrop",
  "asset_identifier": "SPVD6CE8RW90BGGKJZTKCSMGKS7HP0K8364TFR48.bitcoin-faces-airdrop::bitcoin-faces",
  "sender": "SP3KMHQ80ZGT037R2FCHV1F7Z0X25EV6GVEYNAB87",
  "recipient": "SP37YJNKVKP3KD5SFK71NW7DC25RRF4HKWWQRH3NT",
  "value": "0x010000000000000000000000000008331e"
}
```

### The Contract call object

One top-level contract-call transaction, arguments and result decoded to JSON. Clarity integers come back as decimal strings.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<tx_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the row landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp, ISO 8601 UTC. |
| `tx_id` | string | Transaction id, `0x`-prefixed hex. |
| `tx_index` | integer | The transaction's position in its block. |
| `contract_id` | string | Called contract. |
| `function_name` | string | Called function. |
| `sender` | string | Transaction sender principal. |
| `status` | string | Execution status, e.g. `success` or `abort_by_response`. |
| `args` | array of object | Decoded arguments, in call order. |
| `result` | object | Decoded result. `null` when there is none. |
| `result_hex` | string · nullable | The result as hex-encoded Clarity. |

```json
{
  "cursor": "9048502:1",
  "block_height": 9048502,
  "block_time": "2026-09-23T13:14:42.000Z",
  "tx_id": "0x198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
  "tx_index": 1,
  "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
  "function_name": "transfer",
  "sender": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
  "status": "success",
  "args": [
    "300",
    "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
    "SPD3SCZDZ52X4ZX1878XWBFBJ29YRX0MFW9Z9W4V",
    null
  ],
  "result": true,
  "result_hex": "0x0703"
}
```

### The Canonical block object

One height of the canonical chain: the hash, its parent, and the Bitcoin anchor. Every row is canonical.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:0`. Pass as `cursor`. |
| `block_height` | integer | Stacks block height. |
| `block_hash` | string | The block's hash. |
| `parent_hash` | string | The parent block's hash, to check linkage. |
| `burn_block_height` | integer | The Bitcoin block it anchors to. |
| `burn_block_hash` | string · nullable | That Bitcoin block's hash. |

```json
{
  "cursor": "9048503:0",
  "block_height": 9048503,
  "block_hash": "0x5560590afefe994adbe2188586a44ba3668e8964a7e64bb137c0df216531da0c",
  "parent_hash": "0x2a20974330e301b65086d3cde9b0006c9b7471479ba9a3fc2ca72621479655cc",
  "burn_block_height": 968276,
  "burn_block_hash": "0x000000000000000000019d25cd76d06a9eea796a906ac88300cd70fd70ccdb57"
}
```

### The State write object

One MARF write a block committed, as the node's `state_writes` observer key delivered it.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<ordinal>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block height. |
| `ordinal` | integer | Position in the block's write order, from 0. A separate clock from event_index. |
| `tx_index` | integer · nullable | The writing transaction's index in the block; null for block-level writes. |
| `key` | string | The full MARF key, e.g. `vm::<contract>::0::map::<hex>` or `vm-account::<address>::19`. |
| `value_hex` | string | The value written, hex as the node sent it. |
| `tx_id` | string · nullable | Writing transaction's id. Only with `tx_context=true`; null for block-level writes. |
| `tx_sender` | string · nullable | Writing transaction's sender. Only with `tx_context=true`. |
| `tx_type` | string · nullable | Writing transaction's type. Only with `tx_context=true`. |
| `tx_status` | string · nullable | Writing transaction's status. Only with `tx_context=true`. |
| `tx_contract_id` | string · nullable | Contract the writing transaction called or deployed. Only with `tx_context=true`. |
| `tx_function_name` | string · nullable | Function the writing transaction called. Only with `tx_context=true`. |

```json
{
  "cursor": "100:1",
  "block_height": 100,
  "ordinal": 1,
  "tx_index": 0,
  "key": "vm::ST3FEXKRAY93SR2MERXNSAXWGV9XSDNM1MVEFY5TH.store::0::map::0d0000000568656c6c6f",
  "value_hex": "30313030303030303030303030303030303030303030303030303030303030303031"
}
```

### The Block object

A Stacks block: chain linkage and Bitcoin anchor. Only what ingest stores; no miner, tx count or cost data.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:0`. Pass as `cursor`. |
| `block_height` | integer | Stacks block height. |
| `block_hash` | string | The block's hash. |
| `parent_hash` | string | The parent block's hash. |
| `burn_block_height` | integer | The Bitcoin block it anchors to. |
| `burn_block_hash` | string · nullable | That Bitcoin block's hash. |
| `index_block_hash` | string · nullable | Nakamoto block id. Pass it as `?tip=` to a node read-only call to pin the read to this block. `null` on rows ingested before it was stored. |
| `block_time` | string · date-time · nullable | That block's timestamp, ISO 8601 UTC. |
| `canonical` | boolean | Whether the block is on the canonical chain. Always `true` in the list; a hash lookup can return an orphan. |

```json
{
  "cursor": "9048502:0",
  "block_height": 9048502,
  "block_hash": "0x2a20974330e301b65086d3cde9b0006c9b7471479ba9a3fc2ca72621479655cc",
  "parent_hash": "0x10606e958095ef9b964e3c3f2d9eb75bf8577fb8c09c24ee492b767f7504abea",
  "burn_block_height": 968276,
  "burn_block_hash": "0x000000000000000000019d25cd76d06a9eea796a906ac88300cd70fd70ccdb57",
  "index_block_hash": "0x990152a894e12288960c8b68e5790ad7994f9d261e9ad8adc13c72e76f914339",
  "block_time": "2026-09-23T13:14:42.000Z",
  "canonical": true
}
```

### The Transaction object

A confirmed transaction: stored columns plus what decodes from the raw bytes. Payload objects appear only for the matching `tx_type`. Decoded fields are `null` when the raw bytes do not decode (burnchain ops).

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<tx_index>`. Pass as `cursor`. |
| `tx_id` | string | Transaction id, `0x`-prefixed hex. |
| `block_height` | integer | Stacks block the row landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp, ISO 8601 UTC. |
| `burn_block_height` | integer · nullable | The Bitcoin block its Stacks block anchors to. |
| `tx_index` | integer | The transaction's position in its block. |
| `status` | string | Execution status, e.g. `success` or `abort_by_response`. |
| `tx_type` | string | `token_transfer`, `contract_call`, `smart_contract`, `coinbase`, `tenure_change` or `poison_microblock`, decoded from the raw bytes. Falls back to the stored type when they do not decode. |
| `sender` | string | Sender principal. |
| `fee` | string · nullable | Fee in microSTX as a decimal string. `null` when the raw bytes do not decode. |
| `nonce` | string · nullable | Sender nonce as a decimal string. |
| `sponsored` | boolean · nullable | Whether a sponsor paid the fee. |
| `anchor_mode` | enum · nullable | Anchor mode from the raw bytes. Values: `on_chain_only`, `off_chain_only`, `any`. |
| `post_condition_mode` | enum · nullable | Post-condition mode from the raw bytes. Values: `allow`, `deny`. |
| `post_conditions` | array of PostCondition | Decoded post-conditions. Empty when there are none. |
| `token_transfer` | object | `token_transfer` only. |
| `coinbase` | object | `coinbase` only. |
| `tenure_change` | object | `tenure_change` only. |
| `contract_call` | object | `contract_call` only. |
| `smart_contract` | object | `smart_contract` only. |

```json
{
  "cursor": "9048502:1",
  "tx_id": "0x198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
  "block_height": 9048502,
  "block_time": "2026-09-23T13:14:42.000Z",
  "burn_block_height": 968276,
  "tx_index": 1,
  "tx_type": "contract_call",
  "sender": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
  "status": "success",
  "fee": "3000",
  "nonce": "265",
  "sponsored": false,
  "anchor_mode": "any",
  "post_condition_mode": "deny",
  "post_conditions": [
    {
      "type": "ft",
      "principal": "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
      "asset_identifier": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token",
      "condition_code": 1,
      "condition_code_name": "sent_eq",
      "amount": "300"
    }
  ],
  "contract_call": {
    "contract_id": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
    "function_name": "transfer",
    "function_args": [
      "300",
      "SP15T1W26JTNS26VG17HM468KW7TQD3124KTYA9EJ",
      "SPD3SCZDZ52X4ZX1878XWBFBJ29YRX0MFW9Z9W4V",
      null
    ],
    "function_args_hex": [
      "010000000000000000000000000000012c",
      "05164ba0f04696ab911b7009e3421913e1f5768c2224",
      "05161a3cb3edf945d27fa141d1de2deb9093ec74147f",
      "09"
    ],
    "result": true,
    "result_hex": "0x0703"
  }
}
```

### The Transaction proof object

Everything needed to verify inclusion offline. Hex values have no `0x` prefix.

| Field | Type | Description |
| --- | --- | --- |
| `txid` | string | Transaction id. Recompute it from `raw_tx`. |
| `index_block_hash` | string | Nakamoto block id. Recompute it from `raw_header`. |
| `block_height` | integer | Stacks block height. |
| `tx_index` | integer | The transaction's position in the block; the merkle leaf index. |
| `raw_tx` | string | The serialized transaction. |
| `raw_header` | string | The serialized Nakamoto block header, signer signatures included. |
| `tx_merkle_path` | array of object | Sibling hashes from the leaf up to the header's tx merkle root. |
| `consensus` | object | The reward cycle and its signer set, to check the header's signatures pass 70% of signer weight. Absent when the node cannot resolve the set. |

```json
{
  "txid": "198d642edb1104a1757a8c353ad61231d0422ecb6ba83aa1ce45d05df44157e0",
  "index_block_hash": "990152a894e12288960c8b68e5790ad7994f9d261e9ad8adc13c72e76f914339",
  "block_height": 9048502,
  "tx_index": 1,
  "raw_tx": "000000000104004ba0f04696ab911b7009e3421913e1f5768c222400000000000001090000000000000bb8000123767ba956a0545b2543f059d003500767330fad1f4e6cce3d734c8719bfca9226c07dc6e64edb83078cb34e83c6b430d4a260628af821041f51eb5f21e444390302000000010102164ba0f04696ab911b7009e3421913e1f5768c222414f6decc7cfff2a413bd7cd4f53c25ad7fd1899acc0a736274632d746f6b656e0a736274632d746f6b656e01000000000000012c0214f6decc7cfff2a413bd7cd4f53c25ad7fd1899acc0a736274632d746f6b656e087472616e7366657200000004010000000000000000000000000000012c05164ba0f04696ab911b7009e3421913e1f5768c222405161a3cb3edf945d27fa141d1de2deb9093ec74147f09",
  "raw_header": "0100000000008a11b60000006643539084f394038c2267d08e5e5c52b9da2d99f4360c91a5314c3cac40ac15f4397b92360ccaa5adaeda6ebc5587511f33b1495fe1d1f66d10b0bfc1ef83918390f25ad4f0b7f5ddf76fa79782e92da2315856590664d9c179ccc0143e35f99140069ea4517ab4ca79e39f0e54b406b1b68b5f8c29e25750000000006ab3d0c2012ae8acc3a85100ae9eecf07468c694fee3cb585c423a0df3054991c77f4fa3fb4fc7b300f1b332f02ec0488c4033c7eb72abec17999c01326d222225f430e56d000000130016f1a9fb8ef3c85b04bd863818f4b47680de8f33e375b2872fbdd5b94d1664624488458f13383478becec32e9ce8ac9b2d0292d2773b37bf1c5943e87cf35b31006dbcd0a22c1eaf81d34dd1c2f25a1e05b7d6e5fdd3c5d8c7e4b96aa4472088e14d8b7ece3427f77fbcfd4027e7bd27be1388ddb68efb8debf8dfe48da558987400e3df41a2cc852d41b6db8f67c8e6c7bf1c31d185c87b019d349a5d6713c951ca43837c05b62a9f0b58ac4403a98233f1e1573e031fae90306ccd618dff1ce8eb01f4bba3a39010779d4870906d1f7e66115b8146f6b70b4e4fee3a402fa484c1d40146832b8fb21ab3328d7588e3861d9c614522692bd14fb763c77a2203d0b86a010075c0105d54deac9a6388734e0519d7ba90024727f02d65b8fd2cd788eca9350c6f6c7ff52200e41cefbf19873bcb9c17068ca9b093fd032dd68683348e95550083c787948e7bd477341747c8769ce2e9c8a420cb137d3609b5e90163f0c56ac3747219c113b0b5018aefa1dc9bd415b21b48173cb9c42f96f19cf143a77261340092179e100c58cfc2b3ee3271eca056ad98c986a1b434296eb1bb00986f3c1a7e70d89fdcbb983f216b9b9d5b5bf21093f58bf2e022fb0010f6706010ebe8c09f01bf06697f3e93883ebf59f83a98bc032d7b3da70886b6e44309cd77855dc1bf8c099084b40609c0a4e3d04806a0fd23391ad79745ba52b122838e3edf6359aa2d006d529e1f590e58b3d1519b719d1149e1babfa1cf20b164167199da2804dec7004159c9f6cb90f265b0d7c3338905de677087bbf9e40a7f06159a4697014756c501726fe445f8a4c876138ff40581e34a659463f97d7b2d1cc843b82d5c8ec9cd2e326ab34b509f4c193f424ebd2ddd729f007687c88b66af59ddda1036b1c7da8700d9a1b7f528df90661c608fd1935d95abb0f638b780573101837863353daf50c529e02703891e885ffa2603ca19a8ab1724c07795e6ab458e93abdca27ac67c3600c4202f95645edb945c2659345fd1dc5043d9fd178c398ddb2ed55ffc5bb9c62f2a61ada05578631cd6523fadf4a47be96133216b5cd421222a1289914ec41d5600ae2119da699f9eea1a8c49b0cf63c2ed5191d141491f11893869e04f24ad14d20dabc52b11e4418cd46610709c7d6456ff0a235760dc39c7e4c057fc8802fa4101813c588a7730569283f517b53949f67aa46a214530dab382da6ec3afc7014ede023706361ec717f8487a88f9d8ae9f912b3033124fccf8c98e5bcf382208febf016ad6d2d6a0c77ae937dc663b7111ab145e4df0248bcb1da80dce6b5bf0061539705f37412cf59476a22ee6677c20c9b980f263f8c1d4c79acd8d7166ff1a7b4f00aecd8f47fee2d6819993aa0d2e3e4872e2a95550c7403491f9764ebfa832f38b61704739abda8cfb0e05d8020efa5e49a5704dbd82f79fd3638b61005c37867c00025ea0925e7583f2f43c9ad4ff6ceaa8ef6bb62cb15265ebf684ca9005f5bb9312009b7e7bc171291c4c2530b74b275e57fc53072cd381a1cb27dc63232c0835007a5b80bc0b5af6848568468cc2a10f74789e1a1e0bcf6f18bb45f8df4e7a19f55c26f593b23aa76c2b7171aff4b062a58f6611da097071298621735521c7ee110062254da4170c6e66963e8a74c9a4fb5797e4247f5ccd8784c82d70ae96f5f01644e6b7733ca93f0e065fc165e152b4abd602687f2f081ab39c8f0943d3b51ea90001000000010100000000",
  "tx_merkle_path": [
    {
      "position": "left",
      "hash": "ea5ecd867b9945b06aecdf77117de46ae9fd055b137be1fecc1dee38f56b19af"
    },
    {
      "position": "right",
      "hash": "398e676d798b758c66c50e21a83b4c6c8c20a5ffc8552b61d1df160f36a0c23c"
    },
    {
      "position": "right",
      "hash": "d1315b8f5f61861868657a0ab2c8c62332bb77a74a833567427a9f95ab86c1eb"
    }
  ],
  "consensus": {
    "reward_cycle": 143,
    "reward_set": {
      "signers": [
        {
          "signing_key": "0209130bec93e83b23d3366adfcbe0a1641057b9c48102572d892fe8f78de2bee7",
          "weight": 646
        },
        {
          "signing_key": "0216436e7785e1dc55cf4350ac1f90e45daf0ec5b57bce13a32551a513446e71d1",
          "weight": 9
        }
      ],
      "total_weight": 4000
    }
  }
}
```

### The Mempool transaction object

A pending transaction: the transaction document before it has a block, so no height, index, status or result, plus when this instance first saw it.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | Opaque. Pass it back as `cursor` unchanged. |
| `tx_id` | string | Transaction id, `0x`-prefixed hex. |
| `received_at` | string · date-time · nullable | When this instance's node first saw it, ISO 8601 UTC. |
| `tx_type` | string | `token_transfer`, `contract_call`, `smart_contract`, `coinbase`, `tenure_change` or `poison_microblock`, decoded from the raw bytes. Falls back to the stored type when they do not decode. |
| `sender` | string | Sender principal. |
| `fee` | string · nullable | Fee in microSTX as a decimal string. `null` when the raw bytes do not decode. |
| `nonce` | string · nullable | Sender nonce as a decimal string. |
| `sponsored` | boolean · nullable | Whether a sponsor paid the fee. |
| `anchor_mode` | enum · nullable | Anchor mode from the raw bytes. Values: `on_chain_only`, `off_chain_only`, `any`. |
| `post_condition_mode` | enum · nullable | Post-condition mode from the raw bytes. Values: `allow`, `deny`. |
| `post_conditions` | array of PostCondition | Decoded post-conditions. Empty when there are none. |
| `token_transfer` | object | `token_transfer` only. |
| `coinbase` | object | `coinbase` only. |
| `tenure_change` | object | `tenure_change` only. |
| `contract_call` | object | `contract_call` only. No result yet. |
| `smart_contract` | object | `smart_contract` only. |

```json
{
  "cursor": "bToyNjg4Mjc0",
  "tx_id": "0x00a5cd852c25c5bb5cc7f97c60b88a6a635c001ad431e2133f366be85d5ce0f0",
  "tx_type": "token_transfer",
  "sender": "SM1Z09F6431EQT8GCTEF496TCT5JDTPJ3VFF9Q766",
  "received_at": "2026-09-23T15:11:05.629Z",
  "fee": "1732",
  "nonce": "37",
  "sponsored": false,
  "anchor_mode": "any",
  "post_condition_mode": "deny",
  "post_conditions": [],
  "token_transfer": {
    "recipient": "SMJWA5YRH2DRANX3V96Z6JJSFBE03Z9Y0WHN3XSQ",
    "amount": "79559850769",
    "memo": "572826509"
  }
}
```

### The Print schema object

A contract's print payloads, grouped by `topic` and typed field by field from the events sampled.

| Field | Type | Description |
| --- | --- | --- |
| `contract_id` | string | The contract read. |
| `topics` | array of object | One entry per `topic` value. Prints with no string `topic` group under `*`. |
| `sampled` | boolean | `true` when the contract has more print events than were read. |
| `total_events` | integer | Canonical print events for the contract, capped at 50000. |
| `total_events_capped` | boolean | `true` when `total_events` hit the cap. |
| `sample` | object | What was read. |
| `tip` | Tip |  |

```json
{
  "contract_id": "SP2BM6AQSMQ04CX8KDE62QBFVZTDZ2ZX80GZJSBZ4.zc-claim-helper-v2",
  "topics": [
    {
      "topic": "zc-claim-ok",
      "count": 2,
      "first_height": 9004646,
      "last_height": 9004646,
      "non_tuple": false,
      "fields": [
        {
          "name": "earned",
          "camel_name": "earned",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "reward-cycle",
          "camel_name": "rewardCycle",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "staker",
          "camel_name": "staker",
          "clarity_type": "principal",
          "ts_type": "string",
          "column_type": "principal",
          "always_present": true
        },
        {
          "name": "withdrawal-request",
          "camel_name": "withdrawalRequest",
          "clarity_type": "(optional ?)",
          "ts_type": "unknown | null",
          "column_type": "jsonb",
          "always_present": true,
          "optional_some_rate": 0
        }
      ]
    },
    {
      "topic": "claim-many",
      "count": 1,
      "first_height": 9004646,
      "last_height": 9004646,
      "non_tuple": false,
      "fields": [
        {
          "name": "err-count",
          "camel_name": "errCount",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "manager",
          "camel_name": "manager",
          "clarity_type": "principal",
          "ts_type": "string",
          "column_type": "principal",
          "always_present": true
        },
        {
          "name": "ok-count",
          "camel_name": "okCount",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        },
        {
          "name": "submitted",
          "camel_name": "submitted",
          "clarity_type": "uint",
          "ts_type": "bigint",
          "column_type": "uint",
          "always_present": true
        }
      ]
    }
  ],
  "sampled": false,
  "total_events": 3,
  "total_events_capped": false,
  "sample": {
    "size": 3,
    "newest_height": 9004646,
    "oldest_height": 9004646
  },
  "tip": {
    "block_height": 9048938,
    "finalized_height": 9048671,
    "lag_seconds": 23,
    "source_block_height": 9048938
  }
}
```

### The PoX-4 stacking action object

One decoded PoX-4 contract call. Which columns are set depends on `function_name`; a failed call sets only the base fields.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<tx_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the call landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp. |
| `burn_block_height` | integer | Bitcoin block that Stacks block anchors to. |
| `tx_id` | string | The calling transaction. |
| `tx_index` | integer | Its position in the block. With `block_height`, the cursor. |
| `function_name` | string | PoX-4 function called, e.g. `stack-stx`. |
| `caller` | string | Transaction sender. |
| `stacker` | string · nullable | Stacker the call acts on, on delegate-side calls. Null on solo `stack-stx`, where `caller` is the stacker. |
| `delegate_to` | string · nullable | Pool operator, on `delegate-stx`. |
| `amount_ustx` | string · nullable | microSTX as a decimal string (bigint-safe): the amount locked, delegated or increased by. |
| `lock_period` | integer · nullable | Cycles locked, or extended by. |
| `pox_addr` | object | Bitcoin reward address. Every field is null when the call names none. |
| `start_cycle` | integer · nullable | First reward cycle the lock covers. |
| `end_cycle` | integer · nullable | Last reward cycle the lock covers. |
| `reward_cycle` | integer · nullable | Reward cycle named by aggregation and signer-key calls. What `/v1/index/pox/cycles` groups on. |
| `signer_key` | string · nullable | Signer public key, `0x`-prefixed hex. |
| `result_ok` | boolean | Whether the call returned `ok`. |

```json
{
  "cursor": "8647822:1",
  "block_height": 8647822,
  "block_time": "2026-07-27T18:39:09.000Z",
  "burn_block_height": 959869,
  "tx_id": "0x995fb653065c74596b63e6cc9c10fb8fa7b8f3574d5ea089b45d3e11d9e7336e",
  "tx_index": 1,
  "function_name": "stack-stx",
  "caller": "SP14S259H3AC9PXWJ8EVX9ER5NZ58R03GR4QAKHCB",
  "stacker": null,
  "delegate_to": null,
  "amount_ustx": "4491100000000",
  "lock_period": 1,
  "pox_addr": {
    "version": 6,
    "hashbytes": "0x6f0fbc92d6ad56a9d7783b7420ae6731434831e3484d82ad54afe32d7fc7ad6d",
    "btc": "bc1pdu8meykk44t2n4mc8d6zptn8x9p5sv0rfpxc9t254l3j6l7844ksz4jjcs"
  },
  "start_cycle": 139,
  "end_cycle": 139,
  "reward_cycle": null,
  "signer_key": "0x031b91a32ab90b80d40715e8875fb3dfe996aa1e6f5e62ba05d34542aa58ad43b5",
  "result_ok": true
}
```

### The PoX-5 reward cycle object

Materialized per-cycle rollup of pox-5.clar's own state (plan 078), exact to the node.

| Field | Type | Description |
| --- | --- | --- |
| `reward_cycle` | integer | The reward cycle. |
| `start_burn_height` | integer | Bitcoin block at which this cycle starts. |
| `prepare_start_burn_height` | integer | Bitcoin block at which this cycle's totals froze: the start of the prior cycle's prepare phase. |
| `end_burn_height` | integer | Bitcoin block at which this cycle ends. |
| `total_stacked_ustx` | string | STX + bond ustx delegated to signers this cycle, as a decimal string. |
| `reward_eligible_ustx` | string | STX actually counted toward rewards. Signers below the 50,000 STX threshold don't count, even though they're in `total_stacked_ustx`. |
| `stakers` | integer | Distinct stakers (STX and bond) with a position this cycle. |
| `signers_in_set` | integer | Signers that met the 50,000 STX delegation threshold this cycle. |
| `bond_sats` | object | Bond index (as a string key) -> sats staked for this cycle. |
| `bond_total_sats` | string | Sum of `bond_sats` for this cycle. |
| `sbtc_custodied_sats` | string | sBTC currently custodied by pox-5 (non-L1 bonds only). A running total, not scoped to this cycle: the contract's `get-total-sbtc-staked` takes no cycle argument. |
| `rewards_allocated_stx` | string | STX rewards allocated to this cycle's distributions so far. |
| `rewards_allocated_bond` | string | Bond (sBTC) rewards allocated to this cycle's distributions so far. |
| `reserve_deposit` | string | STX deposited to the protocol reserve from this cycle's distributions. |
| `rewards_per_token_stx` | string · nullable | Cumulative STX rewards per micro-STX for this cycle. `null` before the first distribution. |
| `rewards_per_token_bond` | object | Bond index (as a string key) -> cumulative rewards-per-sat for this cycle. |
| `distributions` | integer | Distributions run for this cycle so far (0, 1, or 2). |
| `rewards_claimed` | string | Rewards claimed for this cycle so far, across every signer. |
| `computed_through_height` | integer | Stacks block height this rollup was last computed through. |
| `is_current` | boolean | True for the cycle containing the tip's burn height. |
| `is_frozen` | boolean | True once totals can no longer change: the tip has reached `prepare_start_burn_height`. Closed and current cycles are always frozen; only a not-yet-started future cycle is open. |

```json
{
  "reward_cycle": 141,
  "start_burn_height": 962150,
  "prepare_start_burn_height": 962050,
  "end_burn_height": 964249,
  "total_stacked_ustx": "392447554847960",
  "reward_eligible_ustx": "392447554847960",
  "stakers": 3035,
  "signers_in_set": 36,
  "bond_sats": {
    "1": "23017037628"
  },
  "bond_total_sats": "23017037628",
  "sbtc_custodied_sats": "16016587628",
  "rewards_allocated_stx": "297713728",
  "rewards_allocated_bond": "13810222",
  "reserve_deposit": "52537716",
  "rewards_per_token_stx": "758607677183",
  "rewards_per_token_bond": {
    "1": "599999974940302"
  },
  "distributions": 2,
  "rewards_claimed": "162018760",
  "computed_through_height": 8665732,
  "is_current": false,
  "is_frozen": true
}
```

### The PoX-5 event object

One print event from the pox-5 boot contract, decoded. Promoted columns cover the common filters; `data` always holds the complete tuple, so no topic loses fields.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the print landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp. |
| `tx_id` | string | Transaction that emitted the print. |
| `tx_index` | integer | Its position in the block. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `topic` | enum | The print topic. Decides which columns are set. Values: `set-bond-admin`, `set-pause-admin`, `pause-rewards`, `setup-bond`, `add-to-allowlist`, `register-for-bond`, `update-bond-registration`, `register-signer`, `stake`, `stake-update`, `announce-l1-early-exit`, `unstake-sbtc`, `unstake`, `calculate-rewards`, `bond-distribution`, `claim-rewards`, `claim-staker-rewards-for-signer`, `grant-signer-key`, `revoke-signer-grant`. |
| `staker` | string · nullable | Staker principal. |
| `signer` | string · nullable | Signer-manager contract, on stake-side topics. |
| `signer_manager` | string · nullable | Signer-manager contract, on claim and grant topics. |
| `bond_index` | integer · nullable | The bond this event belongs to, on bond topics. |
| `amount_ustx` | string · nullable | microSTX as a decimal string (bigint-safe). |
| `amount_sats` | string · nullable | Satoshis as a decimal string (bigint-safe). |
| `reward_cycle` | integer · nullable | Reward cycle the event refers to, on reward and claim topics. |
| `first_reward_cycle` | integer · nullable | First cycle a stake earns in. |
| `unlock_cycle` | integer · nullable | Cycle the stake unlocks at. |
| `unlock_burn_height` | integer · nullable | Bitcoin block height the stake unlocks at. |
| `is_l1_lock` | boolean · nullable | Bond registrations: whether the lockup is on Bitcoin L1. |
| `signer_key` | string · nullable | Signer public key, on key-grant topics. |
| `data` | object | The full decoded print tuple. Nested shapes (btc-lockup, bond-rewards, bond-periods) come through intact. |

```json
{
  "cursor": "9048679:0",
  "block_height": 9048679,
  "block_time": "2026-09-23T13:55:35.000Z",
  "tx_id": "0xba5c3e57f65a7e92f917c0e8c32bdf11cedb31baefe708c8a3b9177437420ea9",
  "tx_index": 0,
  "event_index": 0,
  "topic": "stake",
  "staker": "SP19YK5M97734AJZAA2X8W6J9GGNVM9JFZ751H0F1",
  "signer": "SP8HK160YD5GHXP69VGA0TC7AQJ1X4CDW3XVERSE.xverse-signer-manager-3",
  "signer_manager": null,
  "bond_index": null,
  "amount_ustx": "550000000",
  "amount_sats": null,
  "reward_cycle": null,
  "first_reward_cycle": 144,
  "unlock_cycle": 240,
  "unlock_burn_height": 1170050,
  "is_l1_lock": null,
  "signer_key": null,
  "data": {
    "topic": "stake",
    "signer": "SP8HK160YD5GHXP69VGA0TC7AQJ1X4CDW3XVERSE.xverse-signer-manager-3",
    "staker": "SP19YK5M97734AJZAA2X8W6J9GGNVM9JFZ751H0F1",
    "num-cycles": "96",
    "amount-ustx": "550000000",
    "unlock-cycle": "240",
    "first-reward-cycle": "144",
    "unlock-burn-height": "1170050"
  }
}
```

### The Rune entry object

One etched rune's full entry — identity, premine/mint/burn counters, computed supply, and mint terms.

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | `<block>:<tx>` of the etch, e.g. `840000:3`. |
| `number` | string | Etch sequence number (u128 decimal string) — 0 is genesis. |
| `name` | string | The rune's name with spacers stripped, uppercase. |
| `spaced_name` | string | The name as etched, spacers (`•`) included. |
| `symbol` | string · nullable | The etched display symbol, if any. |
| `divisibility` | integer | Decimal places a whole unit divides into. |
| `premine` | string | Premined amount, u128 decimal string. |
| `supply` | string | Computed: `premine + mints × terms.amount` (0 with no terms). u128 decimal string. |
| `burned` | string | Total burned, u128 decimal string. |
| `mints` | string | Total mint transactions, u128 decimal string. |
| `turbo` | boolean | Whether the etch opted into future protocol upgrades. |
| `etching_txid` | string | The etch transaction's Bitcoin txid. |
| `etched_height` | integer | Bitcoin block the etch landed in. |
| `etched_tx_index` | integer | The etch transaction's position in that block. |
| `terms` | object · nullable | Mint terms, or `null` for a premine-only rune that was never mintable. |

```json
{
  "id": "840000:3",
  "number": "3",
  "name": "DOGGOTOTHEMOON",
  "spaced_name": "DOG•GO•TO•THE•MOON",
  "symbol": "🐕",
  "divisibility": 5,
  "premine": "10000000000000000",
  "supply": "10000000000000000",
  "burned": "2440680717188",
  "mints": "0",
  "turbo": false,
  "etching_txid": "e79134080a83fe3e0e06ed6990c5a9b63b362313341745707a2bff7d788a1375",
  "etched_height": 840000,
  "etched_tx_index": 3,
  "terms": null
}
```

### The Rune event object

One etch/mint/transfer/burn event from `rune_events`, with the rune's identity embedded so an activity feed never needs a second lookup to show a name.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Bitcoin block the event landed in. |
| `tx_index` | integer | The transaction's position in that block. |
| `txid` | string | The Bitcoin transaction's txid. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `kind` | enum | What happened. Values: `rune_etch`, `rune_mint`, `rune_transfer`, `rune_burn`. |
| `amount` | string | u128 decimal string. |
| `vout` | integer · nullable | The output the amount landed on, when this event has one. |
| `address` | string · nullable | The output's mainnet address. Only ever set on a `rune_transfer` event. |
| `rune` | RuneRefSummary |  |

```json
{
  "cursor": "968919:3",
  "block_height": 968919,
  "tx_index": 144,
  "txid": "77c95d193e680429fe7f801a68488bd30919d011f23542141a7fae5244b002b4",
  "event_index": 3,
  "kind": "rune_transfer",
  "amount": "2933553300",
  "vout": 2,
  "address": "bc1pjku9h7ckjt8802mu79zt7vv8d6mhp0x57gkppcls57ex4rkq9cxqs52pr3",
  "rune": {
    "id": "840000:3",
    "name": "DOGGOTOTHEMOON",
    "spaced_name": "DOG•GO•TO•THE•MOON",
    "symbol": "🐕",
    "divisibility": 5
  }
}
```

### The Rune balance object

A rune's balance on one unspent output, with the rune's identity embedded.

| Field | Type | Description |
| --- | --- | --- |
| `rune` | RuneRefSummary |  |
| `address` | string · nullable | The output's mainnet address, or `null` for a non-standard script. |
| `txid` | string | The outpoint's Bitcoin txid. |
| `vout` | integer | The outpoint's output index. |
| `amount` | string | u128 decimal string. |

```json
{
  "rune": {
    "id": "840000:3",
    "name": "DOGGOTOTHEMOON",
    "spaced_name": "DOG•GO•TO•THE•MOON",
    "symbol": "🐕",
    "divisibility": 5
  },
  "address": "bc1phnp234rd5hel0h8ulqvnq3zrww2td0a8q48hjcg7mv67j97jnxfq9ayczm",
  "txid": "2d2b54008790a44c9c3e630faa521a50f8ab122625c4eb8fb84705051c4fc611",
  "vout": 0,
  "amount": "88980600"
}
```

### The sBTC event object

One decoded `sbtc-registry` print. Every topic shares this shape; `topic` decides which columns are set.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the print landed in. |
| `block_time` | string · date-time · nullable | That block's timestamp. |
| `tx_id` | string | Transaction that emitted the print. |
| `tx_index` | integer | Its position in the block. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `topic` | enum | The print topic. Values: `completed-deposit`, `withdrawal-create`, `withdrawal-accept`, `withdrawal-reject`, `key-rotation`, `update-protocol-contract`. |
| `request_id` | integer · nullable | Withdrawal request id, on withdrawal topics. |
| `amount` | string · nullable | Sats as a decimal string, on deposits and withdrawal requests. |
| `sender` | string · nullable | Stacks principal, e.g. the withdrawal requester. |
| `recipient_btc_version` | integer · nullable | Bitcoin address type of the recipient: 0 p2pkh, 1 p2sh, 2 p2sh-p2wpkh, 3 p2sh-p2wsh, 4 p2wpkh, 5 p2wsh, 6 p2tr. |
| `recipient_btc_hashbytes` | string · nullable | Recipient's hash bytes, `0x`-prefixed hex. |
| `bitcoin_txid` | string · nullable | Bitcoin txid, `0x`-prefixed hex: the deposit transaction, or the sweep on an accept. |
| `output_index` | integer · nullable | Output within that Bitcoin transaction. |
| `sweep_txid` | string · nullable | Signers' sweep transaction on Bitcoin. |
| `burn_hash` | string · nullable | Bitcoin block hash the signers anchored the event to. |
| `burn_height` | integer · nullable | That Bitcoin block's height. |
| `signer_bitmap` | string · nullable | Bitmap of the signers' votes, as a decimal string. |
| `max_fee` | string · nullable | Most the requester will pay in BTC fees, in sats. |
| `fee` | string · nullable | BTC fee charged on an accepted withdrawal, in sats. |
| `governance_contract_type` | integer · nullable | Which protocol contract changed, on `update-protocol-contract`. |
| `governance_new_contract` | string · nullable | The new contract, on `update-protocol-contract`. |
| `signer_aggregate_pubkey` | string · nullable | The registry's aggregate-key field, on `key-rotation` (33 bytes, hex). In v1 it is the signers' aggregate public key. Once DKG is disabled (no height set yet) it is the marker `0xFF || bitcoin block hash`, not a key, so do not derive addresses from it. |
| `signer_threshold` | integer · nullable | New signature threshold, on `key-rotation`. |
| `signer_address` | string · nullable | New signer principal, on `key-rotation`. |
| `signer_keys_count` | integer · nullable | Number of signer keys in the new set, on `key-rotation`. |

```json
{
  "cursor": "9048486:2",
  "block_height": 9048486,
  "block_time": "2026-09-23T13:10:19.000Z",
  "tx_id": "0x0e09fd3cf7628a2cc81083aa9dbb7eebc7bae5cbe277c370e0f8bfc3d1fe00a9",
  "tx_index": 2,
  "event_index": 2,
  "topic": "withdrawal-create",
  "request_id": 3406,
  "amount": "3127",
  "sender": "SP2ADCJ6606CFHERS3HKABWB6PF5XBANXBQ4GSE86",
  "recipient_btc_version": 4,
  "recipient_btc_hashbytes": "0x9c32e45a19cf9c028bccf12816e62bbfc8eb5fb8",
  "bitcoin_txid": null,
  "output_index": null,
  "sweep_txid": null,
  "burn_hash": null,
  "burn_height": null,
  "signer_bitmap": null,
  "max_fee": "1500",
  "fee": null,
  "governance_contract_type": null,
  "governance_new_contract": null,
  "signer_aggregate_pubkey": null,
  "signer_threshold": null,
  "signer_address": null,
  "signer_keys_count": null
}
```

### The sBTC deposit object

A completed peg-in: one `completed-deposit` event. Keyed by the Bitcoin txid; deposits carry no request id.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | `<block_height>:<event_index>`. Pass as `cursor`. |
| `block_height` | integer | Stacks block the deposit completed in. |
| `block_time` | string · date-time · nullable | That block's timestamp. |
| `tx_id` | string | Stacks transaction that completed the deposit. |
| `tx_index` | integer | Its position in the block. |
| `event_index` | integer | The event's position in the block. With `block_height`, the cursor. |
| `amount` | string · nullable | Sats minted, as a decimal string. |
| `sender` | string · nullable | Stacks principal on the event. Null on mainnet deposits today. |
| `bitcoin_txid` | string · nullable | The deposit's Bitcoin txid, `0x`-prefixed hex. |
| `output_index` | integer · nullable | The deposit output within that Bitcoin transaction. |
| `recipient_btc_version` | integer · nullable | Bitcoin address type of the recipient: 0 p2pkh, 1 p2sh, 2 p2sh-p2wpkh, 3 p2sh-p2wsh, 4 p2wpkh, 5 p2wsh, 6 p2tr. |
| `recipient_btc_hashbytes` | string · nullable | Recipient's hash bytes, `0x`-prefixed hex. |

```json
{
  "cursor": "9048911:4",
  "block_height": 9048911,
  "block_time": "2026-09-23T15:06:29.000Z",
  "tx_id": "0x8600af4a0b2a911e6494d1feea0691068d8b329be0ef2c0d11a7d5aed8f9f4e5",
  "tx_index": 2,
  "event_index": 4,
  "amount": "79856",
  "sender": null,
  "bitcoin_txid": "0x2c11f9e20d21c96daed5d851c07d0e7c4361e552ebd78a8385f06fbb2f9892d3",
  "output_index": 1,
  "recipient_btc_version": null,
  "recipient_btc_hashbytes": null
}
```

### The sBTC withdrawal object

A peg-out rolled up to one row per `request_id`: the request, its current status, and the Bitcoin settlement of its sweep.

| Field | Type | Description |
| --- | --- | --- |
| `cursor` | string | The request event's `<block_height>:<event_index>`. Pass as `cursor`. |
| `request_id` | integer | Withdrawal request id. |
| `status` | enum | `REQUESTED` until the signers act, then `ACCEPTED` or `REJECTED` from the latest resolution event. Values: `REQUESTED`, `ACCEPTED`, `REJECTED`. |
| `amount` | string · nullable | Sats requested, as a decimal string. |
| `sender` | string · nullable | Requester's Stacks principal. |
| `recipient_btc_version` | integer · nullable | Bitcoin address type of the recipient: 0 p2pkh, 1 p2sh, 2 p2sh-p2wpkh, 3 p2sh-p2wsh, 4 p2wpkh, 5 p2wsh, 6 p2tr. |
| `recipient_btc_hashbytes` | string · nullable | Recipient's hash bytes, `0x`-prefixed hex. |
| `sweep_txid` | string · nullable | Bitcoin sweep the signers committed to on accept. Null until then. |
| `settlement_confirmed` | boolean · nullable | True once the sweep has confirmed on Bitcoin, false while it is pending, null when there is no sweep or it has not been seen yet. |
| `btc_confirmations` | integer · nullable | Bitcoin confirmations on the sweep at the last check. |
| `btc_block_height` | integer · nullable | Bitcoin block the sweep landed in. |
| `confirmed_at` | string · date-time · nullable | When the sweep reached the confirmation threshold. |
| `requested_at` | string · date-time · nullable | Block time of the request. |
| `resolved_at` | string · date-time · nullable | Block time of the accept or reject. Null while requested. |

```json
{
  "cursor": "9048225:2",
  "request_id": 3405,
  "status": "ACCEPTED",
  "amount": "221653",
  "sender": "SP2WRMQD3G4G8BR0120Y390CT6A8BTE6MB0JQ5EHA",
  "recipient_btc_version": 4,
  "recipient_btc_hashbytes": "0xa7d5ce640208ed037950d4c849c805e881209d6a",
  "sweep_txid": "0x0efad88eb01e248fd8321ada99cb74f7258948226eae106f8be5a5917d7473e4",
  "settlement_confirmed": true,
  "btc_confirmations": 8,
  "btc_block_height": 968278,
  "confirmed_at": "2026-09-23T14:35:25.473Z",
  "requested_at": "2026-09-23T12:01:45.000Z",
  "resolved_at": "2026-09-23T13:24:47.000Z"
}
```

### The Bitcoin output spend object

One output's spend status. An unspent output carries only `txid`, `vout` and `spent`.

| Field | Type | Description |
| --- | --- | --- |
| `txid` | string | The output's transaction, display order, no `0x`. |
| `vout` | integer | The output's index. |
| `spent` | boolean | True once any transaction spends it, in the mempool or in a block. |
| `spending_txid` | string · nullable | The spending transaction. Null for a confirmed spend deeper than the blocks a lookup reads; `note` says so. |
| `spending_vin` | integer · nullable | The index of the spending input in that transaction. |
| `confirmed` | boolean | True when the spend is in a block of the active chain. |
| `mempool` | boolean | True when the spend is only in the mempool so far. |
| `block_height` | integer · nullable | Height of the block with the spend. Null in the mempool. |
| `block_hash` | string · nullable | Hash of the block with the spend. Null in the mempool. |
| `note` | string | Present when the answer is incomplete: why the spender is not named. |

```json
{
  "txid": "f80a188d012dbb733748db003b987cc98fc4a636cbd071734decb298c1bad80b",
  "vout": 0,
  "spent": true,
  "spending_txid": "3b7a6f0c2d9e1a4b5c8d7e6f0a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3",
  "spending_vin": 0,
  "confirmed": true,
  "mempool": false,
  "block_height": 968470,
  "block_hash": "00000000000000000001c3b0d1a9f5e2e5b2a9c2d0f6c7e1b8a4d3c2b1a09f8e"
}
```

## Notes for agents

- Base: 'GET $SECONDLAYER_API_URL/v1/index/<endpoint>' with 'Authorization: Bearer $SECONDLAYER_API_KEY' on hosted; a loopback instance needs no key.
- List endpoints return a cursor envelope; page by passing next_cursor back as cursor, and undo rows named in reorgs[].
- One endpoint as markdown: 'https://secondlayer.tools/docs/api-reference/<anchor>.md', e.g. list-ft-transfers.
- Prefer @secondlayer/sdk (index.*) over hand-rolled paging.

## 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`
