Skip to main content
Every frame, in both directions, is a JSON object with the same envelope. A message’s own fields live in payload and nowhere else.

Replies and pushes

A reply carries your requestId. The server never interprets it and does not enforce uniqueness. A message without one is accepted, but then two replies of the same type cannot be told apart. Send one on every message, and one generic send(message) → reply helper can serve every operation. Keep it to 32 characters. Up to 64 are accepted, but an error echoes only the first 32, followed by …, so a longer one matches nothing on a refusal. A UUID without its hyphens is exactly 32 characters. A reply is welcome, pong, an ack, or an error carrying the requestId of the message that caused it. A frame refused at envelope level, before its requestId can be read (a malformed envelope, duplicate keys), answers an error with traceId alone. A push carries no requestId, because nothing asked for it. That absence is what tells order_updated, trade_updated, mint_updated, burn_updated and cash_movement apart from replies.

Three ids that look alike

The two traceIds share a name and nothing else.

Times

Amounts

Every amount is a decimal string, never a JSON number, in both directions: "quantity": "10.5", not 10.5. A JSON number is a double, and fractional quantities do not survive one intact. Compare amounts as decimals, never as strings. The broker sets the number of decimal places, and it is not preserved: a limitPrice of "1.00" can come back as "1", a quantity of "1" as "1.000000", and two fields in one frame can carry different scales. Parse with a decimal type (Decimal in Python, a decimal library in JavaScript). What you send is limited in decimal places: