Skip to content

Connection security

Exchange API balances: snapshots versus deltas

A deposit, a duplicate and a missed withdrawal show why changed assets can carry absolute balances and why a fresh snapshot does not explain every movement.

Ivory tiles sit in a tray beside a glass divider and a curved chute carrying ivory tiles and one lime tile.
Illustration for connection security; examples in this article are educational.

An exchange API balance snapshot states an amount at an observation boundary; a balance delta states a signed change to an amount. Replace a field with an absolute value, but add a delta only once and only to a compatible starting state. A message containing just changed assets can still carry absolute balances. Record the payload semantics, account scope and reconciliation boundary before combining REST responses with private-stream events.

Classify the value and the asset list separately

Two independent questions govern a balance update: does each number replace or change the stored value, and does the message cover the whole account or a subset? Calling every WebSocket message a “delta” hides this distinction.

Payload contractExample valueCorrect operationMeaning of an omitted asset
Complete snapshot for a defined scopeUSDT balance is 1,000Establish that scope's state at its boundaryInterpret under the endpoint's coverage and filtering rules
Partial update with absolute valuesUSDT balance is now 1,125Replace the included field; preserve unrelated assetsNo update for that asset
Additive movementUSDT changed by +125Add once to the matching balance basisNo movement reported for that asset

“Absolute” describes the number, while “partial” describes coverage. They can both be true. Treating a partial asset list as a complete replacement can erase untouched holdings. Treating an absolute number as a movement can multiply the apparent account balance.

A snapshot read can also have filters. Binance Spot account information supports omitZeroBalances: setting it to true returns only nonzero balances. Preserve that request option with the response. Omission under a documented snapshot filter and omission from a changed-assets stream message need different handling.

Keep the field identity precise: venue, environment, account or subaccount, wallet or product, asset, units and balance field. An additive wallet movement cannot automatically update an available-margin valuation. The available-versus-total balance guide covers that separate question of what a field measures. Here the problem is how an observation changes stored state.

Binance illustrates two different event meanings

Binance Spot's outboundAccountPosition contains assets potentially affected by the triggering event. Its published payload gives each included asset's f free amount and l locked amount. These are balance values for those assets, rather than instructions to add those amounts. Merge the included asset fields without clearing assets absent from the message. See the Binance Spot account-update payload.

The separate balanceUpdate event reports deposits, withdrawals and transfers between accounts. Its d field is explicitly a balance delta, with a identifying the asset and T the clear time. The Binance user-data event documentation and balance-update schema establish that narrower meaning. A consumer that watches only this event does not thereby capture every trading-related balance change.

These two observations can describe overlapping economic activity. Choose a defined state authority and use other observations as supporting evidence or reconciliation inputs. Adding a movement after accepting an absolute balance that already contains it counts the same activity twice. The exact event ordering and inclusion boundary must come from the applicable protocol; the event names alone do not establish either.

A deposit, a duplicate and a missed withdrawal

Consider this hypothetical consumer for one unleveraged wallet. It starts with 1,000 USDT and four ABC. The fictional protocol supplies stable movement identifiers D1 and D2 and absolute observations with known boundaries. Those identifiers and guarantees are assumptions for the exercise, not Binance field names or delivery promises. There are no trades, fees, reservations or other movements.

StepEvidence processedLocal USDTLocal ABCExplanation
1Opening complete snapshot1,0004Establish the starting state
2D1: deposit +125 USDT1,1254Apply the previously unseen movement
3D1 delivered again1,1254Recognize the same movement; apply no second effect
4Partial absolute update: USDT is 1,125, includes D11,1254Replace USDT; preserve ABC
5Observation gap; D2 withdraws 30 USDT but is not received1,125, unverified4, unverifiedStored values are no longer a verified current account view
6Recovery snapshot: USDT 1,095 and ABC 41,0954Establish a new boundary; explain the missing movement separately

The checked closing USDT amount is 1,000 + 125 − 30 = 1,095. Applying the duplicate deposit would overstate it by 125, producing 1,220 after the withdrawal. Adding the absolute 1,125 at step 4 to the existing 1,125 would instead produce 2,250 at that step. Replacing the account with step 4's one-asset list would incorrectly discard four ABC.

A recovery snapshot can repair the current balance while leaving the historical explanation incomplete. It does not tell you which transfer, trade or charge caused an unexplained difference. Retain the prior state and recovery observation so that the correction remains auditable.

Join a snapshot to a stream without double counting

Bootstrap is difficult because the account can change while the snapshot request is in flight. A stream-first buffer helps retain evidence, but buffering alone does not establish which buffered events the snapshot already includes.

Suppose a snapshot showing 1,125 USDT already includes D1 from the example. Replaying a buffered +125 afterward would create a false 1,250 USDT. Conversely, discarding every buffered message could lose an event that occurred after the snapshot boundary.

Use this sequence when designing the handoff:

  1. Confirm the intended authenticated stream and retain incoming observations with their source metadata.
  2. Fetch the account snapshot for the identical account and field scope; preserve request, response and documented update information.
  3. Apply the provider's documented ordering and boundary rules to distinguish observations included in the snapshot from later ones.
  4. Reconcile the resulting state before permitting decisions that require a verified balance.

Do not borrow an order-book sequence procedure for a private wallet feed unless that feed documents the same guarantee. An event time, account-update time and local receipt time answer different questions. Comparing timestamps is insufficient when the provider has not established that they form a shared, complete ordering boundary.

If the contract lacks an exact handoff mechanism, label the view provisional and use supported account and history queries to investigate the overlap. Repeated agreement during a quiet period is useful evidence, but it is not proof that every historical event arrived. The WebSocket recovery guide addresses the wider continuity problem.

Bybit provides another concrete bootstrap warning: its private wallet stream sends no initial snapshot when subscription succeeds, and unrealized-PnL changes do not trigger wallet events. A successful subscription therefore cannot initialize all balances or prove that a valuation stayed unchanged during silence. These are explicit limits in the Bybit wallet-stream documentation.

Deduplicate movements without erasing legitimate changes

An additive consumer needs an identity for the economic movement under the provider's contract. Scope that identity to the appropriate account and record type. Two equal-sized deposits can be different deposits; two events sharing a millisecond can be different events.

A timestamp-plus-amount hash is not automatically a safe movement key. It may collapse two legitimate movements or miss the same movement represented differently. Binance's published balanceUpdate payload supplies event time, asset, delta and clear time; it does not label any of these fields as a unique transfer identifier. Do not invent a stronger uniqueness guarantee than the contract provides.

Where a supported durable identity exists, commit the “already applied” record and balance effect together. Otherwise a crash after changing the balance but before recording the identity can cause a replay to apply it again. Retaining deduplication records only in memory creates the same risk after restart.

Where a stream lacks sufficient identity or continuity evidence, consider using its events to request fresh absolute state and using supported transaction history for the movement ledger. This is an integration design choice requiring reconciliation, not a claim that every venue exposes a complete replayable ledger.

Absolute updates need their own safeguards. Applying the same absolute observation twice is harmless only if a newer observation has not intervened. A delayed 1,125 observation must not overwrite a justified later 1,095 state. Nor should a consumer simply keep the largest balance: legitimate withdrawals and purchases reduce balances. Resolve precedence through documented version or time semantics, or expose the conflict for recovery.

Validate the resulting state and its explanation

For a single native-asset balance with complete movement coverage between two known boundaries, check:

Closing balance = opening balance + sum of distinct signed movements

Use exact decimal values and compare matching fields. A sum of transfers cannot explain a field also affected by fees and trades unless those effects are included. A USD-equivalent valuation can change with prices even when native asset quantities do not.

Keep three acceptance questions separate: does the current absolute state agree, is the event history complete for the interval, and are the causes explained? The recovery snapshot in step 6 can answer the first while D2's record is still missing. Plan retrieval before records age out; history retention and export coverage explains why an endpoint's lookback limit can constrain later investigation.

Replay at least the worked example's duplicate, partial asset update, overlap and gap. Also restart the consumer between applying D1 and receiving its duplicate; deliver an older absolute update after the recovery snapshot; and process two distinct movements with the same timestamp. Each exercise should produce either the justified state or an explicit unresolved condition, never an unexplained adjustment chosen to make totals match.

A verified balance is still only one input to an action. Check exchange trading modes and status separately before submitting an instruction: matching cash does not establish that the requested order type is currently permitted.

Before using a balance to authorize another order, write down which values replace, which values add, how duplicate movements are identified and where the last reconciled boundary sits. Run the replay fixtures against those four rules. A balance becomes useful when its amount and the evidence supporting it survive the same recovery process.

Keep the context with the example.

Each worked example is illustrative, with its sources and assumptions in the article. Read our editorial standards for authorship, verification and corrections.