Skip to content

Execution

REST vs WebSocket crypto data: reconcile a changing market

Join a REST snapshot to buffered depth updates, verify replacement quantities and catch a book that is coherent but too old to use.

An ivory ceramic arc joins a folded paper ribbon into a ring, with a lime tab marking the seam on black.
Illustration for execution; examples in this article are educational.

REST returns crypto market data in response to requests; WebSocket delivers ongoing updates over a persistent connection. Choose according to the decision's timing and data needs. For a local order book, join the initial state to ongoing updates under the venue's protocol, then check freshness separately. A recent message cannot by itself prove that the book contains every required change.

A price display can begin moving before its underlying book is usable. The application may have received a snapshot and several updates, yet combined them across the wrong boundary. It can also process a perfectly ordered stream too slowly to support its next decision.

This guide follows public market data from the first request to a usable local book. The worked fixture shows the handoff, the resulting quantities and the point where a missing update invalidates it. Private balances and fills require their own reconciliation, covered in the WebSocket recovery guide.

Choose the data shape before the transport

REST usually means requesting a particular resource and receiving a response. A market-data WebSocket subscription delivers ongoing messages through an established connection. Kraken's REST versus WebSocket explanation describes this distinction and explains why an application may combine both interfaces.

Start with the observation your decision needs. A last-traded price describes a transaction. A best bid and ask describe the most competitive displayed quotes. Depth describes quantities across price levels. An application that needs depth cannot replace it with a busy trade feed: cancellations and resting liquidity are different information from completed trades.

WorkloadUseful delivery approachEvidence to retain
Occasional valuation or reportA documented REST price or snapshot endpointInstrument, source, observation time and any caching rules
Continuously changing quote displayA suitable WebSocket quote channelSubscription identity and age of relevant updates
Local aggregated order bookThe channel's required snapshot and update procedureInitial boundary, accepted updates and validation state
Historical researchAn endpoint or dataset with the required historyInterval, pagination, gaps and revision policy

These are selection criteria, not promises about any provider's coverage or speed. A WebSocket can batch messages, and a REST endpoint can return cached data. Read the chosen endpoint's contract before deciding that either interface meets a timing requirement.

Keep the message's meaning attached to the transport choice. The aggregate versus raw trades guide explains another consequence: counting received messages is not automatically counting executions.

The snapshot and the stream need a shared boundary

Imagine requesting a book, waiting for the response and only then subscribing to updates. Changes can occur between the snapshot's observation and subscription startup. The first stream message you see need not contain those changes.

Reversing the order helps only when the provider defines how to join the two observations. Buffering a stream before requesting a snapshot preserves candidate updates, but the client still needs a compatible identifier or other documented handoff rule. Request start time, response arrival time and event time describe different moments; their apparent order does not prove continuity.

Give each maintained book an explicit identity: venue, product, instrument, channel and protocol version. A spot snapshot cannot initialize a perpetual-futures stream just because the displayed symbol looks similar. Likewise, do not carry a verified boundary into a new subscription for another instrument.

Work through a public-book handoff

Binance Spot's local-order-book procedure starts by buffering diff-depth events before obtaining the REST snapshot. It uses snapshot lastUpdateId and event ranges U through u to establish the join. A snapshot behind the first buffered U must be fetched again; buffered events already covered by the snapshot are discarded. The first retained event must satisfy the documented overlap rule. During continuing processing, U greater than the local update ID plus one means the book must be rebuilt. Level quantities replace previous quantities; zero removes a level.

The following is an original hypothetical fixture using those Binance Spot field meanings. Prices, quantities and update IDs are invented. It is a reduced teaching book, not a captured feed or an implementation test.

Assume the snapshot has lastUpdateId = 500 and three levels: a bid at 100.00 for 2.00 base units, an ask at 100.10 for 3.00 units, and an ask at 100.20 for 4.00 units. Prices are quote units per base unit. The stream was opened first and buffered while the snapshot request completed.

Received eventQuantity changes in this fixtureDecision after snapshot 500
U=497, u=499Bid 100.00 becomes 1.90Discard: final ID 499 is already covered
U=500, u=502Bid 100.00 becomes 1.50; ask 100.10 becomes zeroAccept the join: range contains snapshot ID 500
U=503, u=505Bid 100.00 becomes 2.25; ask 100.20 becomes 3.60Apply: next range starts at 502 + 1
U=507, u=508Bid 100.00 would become 2.10Reject: 507 is greater than 505 + 1

After accepting the join, the best bid quantity is 1.50. The 100.10 ask disappears, so the best remaining ask is 100.20 for 4.00. After the next accepted event, the bid quantity is 2.25 and the ask quantity is 3.60. The displayed spread at this verified boundary is 100.20 − 100.00 = 0.20 quote units.

Adding the bid quantities would produce 2.00 + 1.50 + 2.25 = 5.75 units. That calculation is wrong for this contract: 1.50 and 2.25 are replacement quantities, not additional orders to accumulate.

The final row leaves update 506 uncovered. Applying its attractive-looking bid would not recover the missing information. Invalidate the book and restart the supported initialization procedure. Retain 505 as the last accepted boundary in the diagnostic record; it no longer certifies a current book.

A depth snapshot also has a coverage boundary. Binance documents a maximum initial depth of 5,000 levels per side and warns that quantities beyond the snapshot remain unknown until changed. A coherent retained book therefore still needs a statement of the depth it actually covers.

A WebSocket can deliver the snapshot itself

REST initialization is specific to the selected protocol. Coinbase Exchange's level2 channel documentation describes a snapshot message delivered through the WebSocket, followed by l2update messages. Its sizes are also replacement sizes, with zero indicating removal.

For that channel, inventing an additional REST-to-stream join would add a second source of state without establishing a documented need. Follow the channel's initialization contract, including its product identity and update semantics. The Binance range comparison above is not a portable rule to apply to Coinbase's differently structured messages.

Where a venue supplies checksums, use the specified validation scope and formatting. The order-book checksum guide explains why a passing check supports only the covered representation. A checksum does not establish that the checked state is recent enough for the next action.

Freshness can fail after continuity passes

Track when the provider says an event occurred, when your client received it and when your book consumer applied it. Verify each provider timestamp's meaning and units. Comparing provider time with local time also requires a defensible clock offset; a negative apparent delay can be a clock problem.

Here is a second explicitly hypothetical example. Assume aligned clocks and times expressed as milliseconds from a shared reference. An event occurs at 1,000 ms, arrives at 1,080 ms and is applied at 1,390 ms. The next decision occurs at 1,400 ms.

The event is 400 ms old at decision time. It arrived 320 ms ago and spent 310 ms waiting between receipt and application. Yet a metric based only on the last application time reports an age of 10 ms. The consumer has just processed old work.

If this fictional workflow's written age budget is 250 ms, the observation fails that budget despite passing sequence checks. The budget is an illustrative engineering choice, not a recommended threshold or an exchange latency claim. Measure local elapsed durations with a monotonic clock so a wall-clock correction does not rewrite them.

Lack of changes in a quiet market is different from a queue growing behind an active feed. Define what evidence each channel provides for distinguishing silence, transport health and current state. A heartbeat may demonstrate a working connection while the relevant consumer is delayed. The bot health-check guide develops those separate health states.

Make acceptance and rejection observable

Use a short worksheet before allowing a downstream depth calculation to consume the book. Fill it for each channel, rather than using one shared green connection indicator.

CheckRecordReject or investigate when
IdentityVenue, product, symbol, channel and revisionSnapshot and updates refer to different books
InitializationSnapshot boundary and first retained eventThe documented join cannot be established
ContinuityLast accepted boundary and next event rangeA required boundary is uncovered
Quantity semanticsReplacement or delta rule; zero handlingReplaying the fixture gives the wrong levels
CoverageRetained depth and known limitationsA calculation needs liquidity outside verified coverage
FreshnessRelevant receipt age, queue delay and event-time interpretationA written age budget fails or clocks are unreliable

Exercise the failure paths deliberately: delay the snapshot response, replay a covered event, remove a required update, pause the consumer and change the subscribed symbol. The expected result should be explicit for each case. A gap or buffer overflow must not silently produce an accepted book; a delayed consumer must not become healthy merely because it is still running.

Keep snapshot retries within the venue's request budget. If initialization repeatedly fails, expose a degraded state and retain enough public evidence to reproduce the join failure. The rate-limit guide explains why recovery traffic belongs in the same operating budget as routine requests.

Before consuming a book, require a concise record: which market it represents, how its starting state joined the updates, the last accepted boundary, its coverage and its measured age. If one of those facts is missing, the moving prices have not yet answered whether the book is usable.

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.