# Reconcile balances

Source: https://docs.settlemint.com/docs/developer-guides/operations/reconciliate-balances
Compare indexed token balances and token events with your own ledger before investigating a mismatch.



Reconciliation compares a ledger with DALP's indexed token data. Run the check to confirm holders, trace movement history, and separate a pending transaction from a missed event or a ledger-only entry.

This how-to covers read-only checks. The requests below do not change balances or submit corrections. For a pending submission, check transaction status before reconciling.

<Mermaid
  chart="`
flowchart TD
Ledger[&#x22;Internal ledger&#x22;] --> Compare[&#x22;Compare balances and events&#x22;]
Holders[&#x22;GET /api/token/{tokenAddress}/holders&#x22;] --> Compare
Events[&#x22;GET /api/token/{tokenAddress}/events&#x22;] --> Compare
Compare --> Match[&#x22;Balances match&#x22;]
Compare --> Mismatch[&#x22;Investigate mismatch&#x22;]
Mismatch --> Status[&#x22;Check pending transaction status&#x22;]
Mismatch --> EventFilter[&#x22;Filter events by sender or transaction hash&#x22;]
`"
/>

<Callout type="info" title="Indexed data">
  Balance and event routes read indexed chain data. If you are checking a transaction that was just submitted, first
  confirm its current status with [transaction tracking](/docs/developer-guides/operations/transaction-tracking), then
  reconcile after the relevant events have been indexed.
</Callout>

## Prerequisites [#prerequisites]

* Platform URL, such as `https://your-platform.example.com`.
* API key. See [Getting started with the API](/docs/developer-guides/api-integration/getting-started).
* Token contract address for the asset you want to reconcile.
* Your internal balance records and transaction references for comparison.

## Quickstart: query current holder balances [#quickstart-query-current-holder-balances]

Start with the current indexed holders for one token:

```bash
curl -X GET "https://your-platform.example.com/api/token/0xTOKEN_ADDRESS/holders" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"
```

The response groups holder balances under `token.balances`. `value`, `available`, and `frozen` are decimal token amounts derived from the token's decimals.

```json
{
  "token": {
    "balances": [
      {
        "account": { "id": "0x1111111111111111111111111111111111111111" },
        "value": "1000.00",
        "available": "800.00",
        "frozen": "200.00",
        "isFrozen": false,
        "lastUpdatedAt": "2026-01-15T10:30:00.000Z"
      },
      {
        "account": { "id": "0x2222222222222222222222222222222222222222" },
        "value": "500.00",
        "available": "500.00",
        "frozen": "0.00",
        "isFrozen": false,
        "lastUpdatedAt": "2026-01-14T15:20:00.000Z"
      }
    ]
  },
  "totalCount": 2
}
```

For a single holder, include the wallet address as a query parameter:

```bash
curl -X GET "https://your-platform.example.com/api/token/0xTOKEN_ADDRESS/holder?holderAddress=0xHOLDER_ADDRESS" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"
```

## Query balance-affecting events [#query-balance-affecting-events]

Get token events that can explain balance movement:

```bash
curl -X GET "https://your-platform.example.com/api/token/0xTOKEN_ADDRESS/events?eventNames=TransferCompleted&eventNames=MintCompleted&eventNames=BurnCompleted" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"
```

Use `limit` and `offset` when you expect many events.

```json
{
  "events": [
    {
      "id": "evt_01hzzzzzzzzzzzzzzzzzzzzzzz",
      "eventName": "TransferCompleted",
      "txIndex": "0",
      "blockNumber": "12345678",
      "blockTimestamp": "2026-01-15T10:30:00.000Z",
      "transactionHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "emitter": { "id": "0xTOKEN_ADDRESS" },
      "sender": { "id": "0xSENDER_ADDRESS" },
      "values": [
        { "id": "evt_01hzzzzzzzzzzzzzzzzzzzzzzz-account", "name": "account", "value": "0xACCOUNT_ADDRESS" },
        { "id": "evt_01hzzzzzzzzzzzzzzzzzzzzzzz-amount", "name": "amount", "value": "1000000000000000000" }
      ]
    }
  ]
}
```

Event amounts are indexed as raw on-chain integer values. Apply the token decimals before comparing the amount with a human-readable ledger value.

## Compare with your ledger [#compare-with-your-ledger]

For each holder in your ledger:

1. Match the holder wallet address to the `account.id` field from the holder-balance response.
2. Compare your ledger balance with `value`.
3. Compare transferable balance with `available` when your ledger separates frozen or restricted balances.
4. Use `lastUpdatedAt` and token events to narrow the period where the mismatch appeared.

For each ledger transaction:

1. Find the matching token event by transaction hash when you have it.
2. If you do not have the hash, filter by `senderAddress` and event type.
3. Confirm the event name and raw amount match the ledger entry after decimal conversion.
4. Treat an internal ledger entry with no matching event as a failed or still-pending submission until transaction tracking proves otherwise.

## Investigate a mismatch [#investigate-a-mismatch]

Filter by transaction hash when your ledger stores the submitted transaction hash:

```bash
curl -X GET "https://your-platform.example.com/api/token/0xTOKEN_ADDRESS/events?transactionHashes=0xTX_HASH_1&transactionHashes=0xTX_HASH_2" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"
```

Filter by sender when you need events initiated by a specific wallet:

```bash
curl -X GET "https://your-platform.example.com/api/token/0xTOKEN_ADDRESS/events?eventNames=TransferCompleted&senderAddress=0xYOUR_WALLET" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"
```

Use `senderAddress` for transactions submitted by a wallet. Use the event payload and account fields to find events where the wallet participated but did not submit the transaction. Use either `senderAddress` or `walletAddress` on token event queries; the endpoint rejects requests that include both filters.

## Endpoint reference [#endpoint-reference]

| Purpose                 | Endpoint                                                      | Notes                                                                                                                      |
| ----------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| List token holders      | `GET /api/token/{tokenAddress}/holders`                       | Returns positive indexed balances for the token.                                                                           |
| Read one holder balance | `GET /api/token/{tokenAddress}/holder?holderAddress={wallet}` | Returns the indexed balance for one wallet.                                                                                |
| List token events       | `GET /api/token/{tokenAddress}/events`                        | Supports `eventNames`, `senderAddress`, `transactionHashes`, `fromDate`, `toDate`, `walletAddress`, `limit`, and `offset`. |
| List user assets        | `GET /api/user/assets?wallet={wallet}`                        | Returns balances held by one wallet across assets.                                                                         |
| List user events        | `GET /api/user/events`                                        | Supports pagination plus `eventNames`, `senderAddress`, and `transactionHashes` for user-scoped event review.              |

## Event types for reconciliation [#event-types-for-reconciliation]

| Event               | Balance impact                       | Use it to check                                      |
| ------------------- | ------------------------------------ | ---------------------------------------------------- |
| `TransferCompleted` | Sender decreases, receiver increases | Standard transfers between holders.                  |
| `MintCompleted`     | Recipient increases                  | Issuance and additional minting.                     |
| `BurnCompleted`     | Holder decreases                     | Burns and redemptions that reduce supply.            |
| `ForcedTransfer`    | Sender decreases, receiver increases | Custodian-initiated movement when policy permits it. |

## Response fields [#response-fields]

### Balance fields [#balance-fields]

| Field           | Type      | Meaning                                                 |
| --------------- | --------- | ------------------------------------------------------- |
| `account.id`    | `string`  | Holder wallet address.                                  |
| `value`         | `string`  | Total token balance as a decimal amount.                |
| `available`     | `string`  | Balance available for transfer.                         |
| `frozen`        | `string`  | Balance locked by freeze controls.                      |
| `isFrozen`      | `boolean` | Whether the whole holder balance is frozen.             |
| `lastUpdatedAt` | `string`  | ISO 8601 timestamp for the last indexed balance change. |

### Event fields [#event-fields]

| Field             | Type     | Meaning                                                |
| ----------------- | -------- | ------------------------------------------------------ |
| `id`              | `string` | Event identifier.                                      |
| `eventName`       | `string` | Indexed event type.                                    |
| `transactionHash` | `string` | On-chain transaction hash.                             |
| `blockTimestamp`  | `string` | ISO 8601 timestamp for the indexed block.              |
| `blockNumber`     | `string` | Block containing the event.                            |
| `emitter.id`      | `string` | Contract that emitted the event.                       |
| `sender.id`       | `string` | Wallet that submitted the transaction when indexed.    |
| `values`          | `array`  | Event-specific fields, such as account and raw amount. |

## Troubleshooting [#troubleshooting]

| Symptom                            | Check                                                                                                               |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Balance mismatch                   | Check pending transaction status, then compare indexed holder balances again after the event appears.               |
| Missing event                      | Verify the event name and token address. Add `limit` and `offset` if the event is older than the first page.        |
| Amount looks too large             | Convert the raw event amount with the token decimals before comparing it with the ledger amount.                    |
| Sender filter misses an event      | The wallet may be involved without being the submitting sender. Search by transaction hash or wallet-scoped events. |
| Frozen balance differs from ledger | Compare `available`, `frozen`, and `isFrozen` separately instead of comparing only total balance.                   |

## Related operations [#related-operations]

* [Track transaction status](/docs/developer-guides/operations/transaction-tracking) before reconciling a transaction that was just submitted.
* [Handle API errors](/docs/developer-guides/api-integration/error-handling) when a reconciliation query fails.
* [Review the API reference](/docs/developer-guides/api-integration/api-reference) for the full route catalogue.
