Reconcile 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.
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, then reconcile after the relevant events have been indexed.
Prerequisites
- Platform URL, such as
https://your-platform.example.com. - API key. See Getting started with the API.
- Token contract address for the asset you want to reconcile.
- Your internal balance records and transaction references for comparison.
Quickstart: query current holder balances
Start with the current indexed holders for one token:
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.
{
"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:
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
Get token events that can explain balance movement:
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.
{
"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
For each holder in your ledger:
- Match the holder wallet address to the
account.idfield from the holder-balance response. - Compare your ledger balance with
value. - Compare transferable balance with
availablewhen your ledger separates frozen or restricted balances. - Use
lastUpdatedAtand token events to narrow the period where the mismatch appeared.
For each ledger transaction:
- Find the matching token event by transaction hash when you have it.
- If you do not have the hash, filter by
senderAddressand event type. - Confirm the event name and raw amount match the ledger entry after decimal conversion.
- Treat an internal ledger entry with no matching event as a failed or still-pending submission until transaction tracking proves otherwise.
Investigate a mismatch
Filter by transaction hash when your ledger stores the submitted transaction hash:
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:
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
| 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 | 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
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
| 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
| 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
- Track transaction status before reconciling a transaction that was just submitted.
- Handle API errors when a reconciliation query fails.
- Review the API reference for the full route catalogue.
Durable Execution Engine recovery
Recover Durable Execution Engine-backed DALP workflows with operator-only DAPI routes for health checks, redeployment, stale deployment cleanup, and stuck workflow recovery.
Equity tokenization through APIs
Run the API-led ACME Holdings equity tokenization walkthrough without confusing it with the console version.