# Balance snapshot at a block

Source: https://docs.settlemint.com/docs/api-reference/token-features/historical-balances-at-block
Reconstruct holder and total-supply balances as of a specific block across one or more tokens in the active DALP system, for audit and point-in-time reporting.



Use the at-block snapshot endpoint when an auditor or integration needs to reconstruct what a holder owned, or what a token's supply was, as of a specific block. It reads the same checkpoint history as the [per-token historical-balances reads](/docs/api-reference/token-features/historical-balances), but answers a different question: balances at or before one block number. You address the query by token or by holder across the active system, rather than one token at a time.

Reach for this endpoint when you need point-in-time evidence: a balance proof for a dispute, a holder position for a regulatory snapshot, or a total supply figure tied to an exact block.

## Endpoint [#endpoint]

| Endpoint                                   | Returns                                                                                |
| ------------------------------------------ | -------------------------------------------------------------------------------------- |
| `GET /api/v2/historical-balances/at-block` | Checkpointed balances at or before a chosen block, filtered by token, holder, or both. |

The endpoint reads checkpoint data for the caller's active system. It requires historical-balances read access. Results never cross system boundaries: a token or holder outside the active system returns no rows rather than an error, so the response cannot reveal whether an address exists in another tenant.

## Required parameters [#required-parameters]

Every request needs two things:

* A `block` query parameter: the non-negative block number to read balances at or before.
* At least one discriminator filter: `filter[tokenAddress][eq]` or `filter[account][eq]`. A request with neither is rejected.

The `block`, `tokenAddress`, `account`, and `kind` inputs are exact-match selectors. They accept the `eq` operator only. Any other operator is rejected at the request boundary, so a query cannot silently match the wrong rows.

## Read one holder across a token [#read-one-holder-across-a-token]

Pass both a token and an account to read that holder's balance in that token as of the block.

```bash
curl --globoff "$DALP_API_URL/api/v2/historical-balances/at-block?block=8154000&filter[tokenAddress][eq]=0x00000000000000000000000000000000000000aa&filter[account][eq]=0xabcdef0000000000000000000000000000000001" \
  --header "X-Api-Key: $DALP_API_TOKEN"
```

The response is a paginated collection envelope with `data`, `meta`, and `links`:

```json
{
  "data": [
    {
      "tokenAddress": "0x00000000000000000000000000000000000000aa",
      "account": "0xabcdef0000000000000000000000000000000001",
      "kind": "account",
      "balance": "1000",
      "balanceExact": "1000000000000000000000",
      "asOfBlockNumber": "8153120",
      "asOfBlockTimestamp": "2026-01-01T00:00:00.000Z",
      "asOfTxHash": "0x0000000000000000000000000000000000000000000000000000000000000045",
      "asOfLogIndex": 0
    }
  ],
  "meta": { "total": 1, "facets": {} },
  "links": {
    "self": "/v2/historical-balances/at-block?block=8154000&filter[tokenAddress][eq]=0x00000000000000000000000000000000000000aa&filter[account][eq]=0xabcdef0000000000000000000000000000000001&page[limit]=50&page[offset]=0&sort=account",
    "first": "/v2/historical-balances/at-block?block=8154000&filter[tokenAddress][eq]=0x00000000000000000000000000000000000000aa&filter[account][eq]=0xabcdef0000000000000000000000000000000001&page[limit]=50&page[offset]=0&sort=account",
    "prev": null,
    "next": null,
    "last": "/v2/historical-balances/at-block?block=8154000&filter[tokenAddress][eq]=0x00000000000000000000000000000000000000aa&filter[account][eq]=0xabcdef0000000000000000000000000000000001&page[limit]=50&page[offset]=0&sort=account"
  }
}
```

Each row reports the balance from the latest checkpoint at or before the requested block. The `asOf` fields point to the checkpoint that produced the balance, so you can cite the exact block, timestamp, and transaction the figure came from.

## Read every holder of a token [#read-every-holder-of-a-token]

Pass only a token to read all of its holders as of the block. Total-supply rows use the zero address as the account.

```bash
curl --globoff "$DALP_API_URL/api/v2/historical-balances/at-block?block=8154000&filter[tokenAddress][eq]=0x00000000000000000000000000000000000000aa&page[limit]=50" \
  --header "X-Api-Key: $DALP_API_TOKEN"
```

To narrow the result to holders only or to the total-supply row, add `filter[kind][eq]=account` or `filter[kind][eq]=totalSupply`. Results sort by account, and equal-key rows stay in a stable order so offset pages do not shift between requests.

## Pagination and sorting [#pagination-and-sorting]

The endpoint returns at most 50 rows per page by default and 200 at most. Set `page[limit]` and `page[offset]` to walk a large holder set, and follow the `links` in each response. Every pagination link carries the original `block` through, so following `next` or `last` reads the same point in time as the first page. Sort by `account` with `sort=account` or `sort=-account`.

The `meta.facets` object is always present but currently returns an empty map. Facet counts for the `kind` field are not computed by this endpoint, so callers cannot rely on it to size holder versus total-supply segments before paging.

## Response fields [#response-fields]

| Field                | Meaning                                                                                                      |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `tokenAddress`       | Token the balance belongs to.                                                                                |
| `account`            | Holder address, or the zero address for a total-supply row.                                                  |
| `kind`               | `account` for a holder balance, `totalSupply` for a supply row, `no-checkpoint` when no balance existed yet. |
| `balance`            | Balance as a decimal string in token units.                                                                  |
| `balanceExact`       | Same balance as a base-unit integer string, for exact arithmetic.                                            |
| `asOfBlockNumber`    | Block of the checkpoint that produced the balance, or `null` for a `no-checkpoint` row.                      |
| `asOfBlockTimestamp` | Timestamp of that checkpoint, or `null` for a `no-checkpoint` row.                                           |
| `asOfTxHash`         | Transaction hash of that checkpoint, or `null` when none applies.                                            |
| `asOfLogIndex`       | Log index within that transaction, or `null` when none applies.                                              |

## Reading balances before activity [#reading-balances-before-activity]

When you request a holder and token together and no checkpoint exists at or before the block, the response still returns a row. If the holder already held a balance during the window between the feature's enable block and their first recorded activity, the row reports that seeded pre-activity balance. If no balance applied, the row reports a `no-checkpoint` kind with a zero balance and `null` checkpoint fields.

This keeps a known holder and token from disappearing from the result just because the block falls before their first transfer. A `no-checkpoint` zero row means the holder owned nothing at that block, not that the query failed.

## Troubleshooting [#troubleshooting]

| Symptom                       | What to check                                                                                             |
| ----------------------------- | --------------------------------------------------------------------------------------------------------- |
| Request is rejected           | Include a `block` value and at least one of `filter[tokenAddress][eq]` or `filter[account][eq]`.          |
| Filter is rejected            | Use the `eq` operator on `tokenAddress`, `account`, and `kind`. Other operators are not accepted.         |
| Result is empty               | Confirm the token and holder belong to the active DALP system and that the block is at or after activity. |
| A holder shows a zero balance | A `no-checkpoint` zero row means the holder held nothing at that block, not that the lookup failed.       |

## Related [#related]

* [Historical balances API](/docs/api-reference/token-features/historical-balances): per-token checkpoint and as-of reads.
* [Token holders and transfers](/docs/api-reference/tokens/token-holders-transfers): current holder state and transfer history.
* [API reference](/docs/api-reference/reference/openapi)
