Exchange API large integer identifiers should be preserved as exact strings at application boundaries, with a lossless decoding path when the exchange sends unquoted JSON numbers. JavaScript Number cannot distinguish every integer above 9,007,199,254,740,991. Rounding an order or fill ID can join unrelated records, break reconciliation or target the wrong lookup; converting the rounded value to a string does not repair it.
An identifier answers “which record?” Its digits are not a price, position size or value to round. The practical task is to keep the same identity from the exchange response through the ledger and into a later request.
Two different IDs can become one key
JavaScript's maximum safe integer is 2^53 − 1, or 9007199254740991. Larger integers are not all distinguishable as Number values. The ECMAScript safe-integer definition explicitly gives the collision between 9007199254740992 and 9007199254740993.
Consider this hypothetical adapter fixture. These are invented record IDs chosen to expose a representation boundary, not observed exchange orders.
| Original ID text | Preserved string | After Number conversion, then String |
|---|---|---|
9007199254740991 | 9007199254740991 | 9007199254740991 |
9007199254740992 | 9007199254740992 | 9007199254740992 |
9007199254740993 | 9007199254740993 | 9007199254740992 |
9007199254740994 | 9007199254740994 | 9007199254740994 |
Four original identities become three numeric keys. A map keyed by the converted Number can overwrite the second record with the third, or a deduplication step can suppress one as a repeat. Some larger integers remain exactly representable; that does not make this range safe for arbitrary identifiers.
This short JavaScript check isolates the problem:
const a =
"9007199254740992";
const b =
"9007199254740993";
a === b
// false
Number(a) === Number(b)
// true
An integer check alone is insufficient: the rounded value still has no fractional part. Number.isSafeInteger can reject an unsafe Number, but it cannot reconstruct its original token. If an SDK has already returned only the rounded value, quarantine that record and retrieve an exact representation rather than guessing the final digit.
Read the wire type before choosing the parser
Exchange schemas differ. Binance's USDⓈ-M Futures Query Order documentation defines orderId as an integer with int64 format in its request and response. Bybit's V5 open-and-closed-order response defines orderId as a string. These are endpoint-specific contracts; neither establishes the current size of every ID or a universal exchange format. See the Binance Query Order schema and Bybit order response fields.
For a quoted string field, keep the decoded string. Avoid Number, parseInt, unary plus and spreadsheet numeric inference. For an unquoted numeric ID, arrange to preserve its numeric token exactly during decoding. A parser that supports lossless integers or schema-directed token capture can return a string before ordinary Number conversion destroys information.
Standard JSON.parse creates Number values for JSON numbers. A reviver that receives only the rounded value and runs BigInt(value) is too late. Current ECMAScript also specifies a reviver context with source, which can expose the original primitive token. A schema-aware handler can use that text where the deployed runtime supports it; verify support and the actual HTTP client's parsing path. The ECMAScript JSON parsing algorithm defines this distinction.
Do not repair arbitrary JSON by applying a global digit-matching regular expression. It can alter digits inside quoted strings, mistake quantities for IDs, or mishandle nested fields and escapes. Decide which documented fields are identifiers, then validate their permitted grammar and range.
For WebSocket data, this boundary follows message framing and any required decompression. The WebSocket compression guide covers obtaining the correct payload text; successfully decoding that text still leaves numeric identity preservation to the parser.
Keep storage and comparison exact
Use an explicit internal identifier type whose underlying value is a string. Preserve case and significant characters for opaque IDs. A digit-only string is still an identifier: remove leading zeros only when the provider's contract explicitly defines a numeric identity and the normalization rule is deliberate. Do not trim or rewrite unexpected input into a plausible ID.
Exact text does not establish uniqueness by itself. Keep the venue, environment, account and any product or instrument scope the endpoint requires. The trade-ID versus order-ID guide explains record meaning and namespace; this article addresses whether the identifier survives transport intact.
Normalize both sides to the validated internal type before equality checks. Strict string equality preserves the distinction in the fixture. Coercive equality can reintroduce numeric conversion. Likewise, sorting opaque IDs lexicographically is different from numeric order, and an increasing-looking ID is not proof of event time. Use documented sequence semantics for ordering and the monotonic versus wall-clock guide for duration and timestamp decisions.
An exact database integer column can store an ID within its supported range, yet a database driver can still lose it when materializing a JavaScript Number. Check the returned type after queries, queue delivery, cache retrieval and exports. A correct column definition is only one boundary in the chain.
BigInt is an option, not a transport contract
BigInt can represent an integer exactly when constructed from its intact decimal string. Constructing it from an already rounded Number preserves that rounded value instead. It also does not preserve an opaque identifier's leading zeros, punctuation or spelling.
Choose BigInt only where integer operations are justified by the field's contract. Most record identity work needs equality and lookup, for which an exact string is sufficient. Do not calculate the next ID by adding one unless the endpoint explicitly requires that continuation rule; the pagination guide covers continuation evidence separately.
Before serialization, decide the required wire representation. Plain JSON.stringify throws for an unhandled BigInt; it does not automatically emit a portable large integer. The ECMAScript serialization algorithm specifies that behavior. For your own JSON interfaces, the I-JSON interoperability guidance recommends strings for exact numbers beyond ordinary binary64 precision.
An exchange request must still match its schema. Keep exact digit text for query parameters; if a JSON body requires an unquoted integer, use a serializer that can emit the validated exact token. Do not turn it into a Number merely to satisfy a convenient SDK method, or change a required numeric field to a quoted string without checking acceptance.
A round-trip worksheet for an adapter
Run the same fixture through every boundary that production records traverse. Capture types as well as displayed values: a console or dashboard can conceal where conversion occurred.
| Check | Evidence to retain | Passing outcome |
|---|---|---|
Decode adjacent IDs ending in 992 and 993 from the fixture | Original response text and decoded field types | Two distinct exact internal strings |
| Persist, read, enqueue and consume both | Values and types at each boundary | Neither identity changes or disappears |
| Replay one exact ID twice | Scoped keys and record count | One identity is recognized as repeated |
| Export and reimport | Raw exported field and import settings | No rounding or scientific-notation substitution |
| Build a later lookup | Final serialized request field | Exact original ID under the required wire type |
| Receive an unsafe Number without original text | Validation result and recovery action | Stop uncertain identity matching; do not guess |
The fixtures establish representation behavior, not complete order history or successful cancellation. A preserved ID can still refer to the wrong record type or namespace, and a request with the correct ID can fail. Preserve those outcomes separately.
Price and quantity arithmetic has a different objective: preserving a numerical amount while respecting increments and rounding rules. Use the decimal-precision guide for that work. For identifiers, the decisive evidence is simpler: the original identity and the final lookup identity must remain the same across every conversion.
Prepared with AI assistance from official exchange and language documentation reviewed on 23 October 2026. The collision fixture was checked locally in JavaScript. This is an adapter-design explanation; no live exchange request or KLINEO implementation test was performed.
