Synchronize the catalog
Keep a local catalog that survives disconnects. You need an API key, persistent storage, a streaming JSON parser, and a server-side WebSocket client that can set an Authorization header. For runnable implementations, see Examples.
1. Stage a complete snapshot
Request GET /api/v1/merchant/items/full-dump with gzip support.
Read the complete body into a temporary table or file. Keep ETag, X-Catalog-Cursor, and
X-Catalog-Epoch with that snapshot. Verify successful decompression, complete JSON, and
items_count before replacing the working catalog.
Publish the completed items and their checkpoint together, atomically. A partial download must leave the previous catalog and checkpoint intact. The ETag describes the snapshot, not changes you apply later through the feed.
A 304 has no body: reuse the matching complete cached snapshot and the checkpoint that
belongs to it. Never combine a snapshot checkpoint with a working catalog that has since advanced.
If either checkpoint header is absent, keep serving your existing state or use REST while
waiting for a newly generated snapshot with both headers. Do not start a complete mirror from
a connection without a cursor.
2. Replay from the snapshot cursor
Open the WebSocket with the saved snapshot cursor and Bearer header. Check
that the hello epoch matches the snapshot epoch. The hello cursor is a connection-time head;
it does not mean those changes have been applied.
For each batch, apply its events in order: insert or replace offer.added, set the absolute
price for offer.price_changed, and remove offer.removed. Unknown IDs on price/removal events
are safe to ignore. Snapshot and replay may overlap, so reapplying events must be safe.
Commit the whole batch and its cursor together. Do not advance a cursor ahead of durable item changes. See the frame and event contracts for the exact fields.
3. Continue with live updates
Replay and live batches use the same format and connection; no subscribe message is needed.
Reply to each JSON ping with the text message {"type":"pong"}. A WebSocket control pong
alone does not satisfy this heartbeat. A ping cursor may be saved only after earlier batches
on that connection have been applied.
Use an hourly snapshot to refresh attributes outside the feed’s price/visibility changes. Stage the replacement, stop applying the previous stream, publish the new snapshot and checkpoint, then replay from that checkpoint before serving the updated mirror.
4. Recover without skipping changes
| Situation | Next action |
|---|---|
Transport disconnect or 1001 / 4002 | Back off and reconnect with the last fully applied cursor. |
4001 resync_required or an epoch mismatch | Obtain a newly generated full snapshot and repeat the flow. Do not reconnect indefinitely with the rejected cursor. |
JSON ping reports engine: "degraded" | Temporarily refresh through REST snapshots; changes may not be entering the feed. |
4003 too_many_connections | Coordinate client instances and keep at most two connections per key. |
HTTP 429 | Wait for Retry-After; full dump requests are limited to one per 60 seconds. |
HTTP 503 FEED_NOT_READY | Back off; wait for the feed and a usable snapshot checkpoint. |
The retained replay tail is bounded; it has no guaranteed duration. A new snapshot is the recovery path when the tail no longer covers your checkpoint. See Reconnect and limits.