Skip to content

Connection security

Exchange API IDs: preserve every digit

Two different exchange identifiers can collapse into the same JavaScript Number. Trace exact ID text through parsing, persistence and later lookups.

Two parallel ivory tile chains pass through a black rectangular gate, with lime tiles marking one chain against a black surface.
Illustration for connection security; examples in this article are educational.

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 textPreserved stringAfter Number conversion, then String
900719925474099190071992547409919007199254740991
900719925474099290071992547409929007199254740992
900719925474099390071992547409939007199254740992
900719925474099490071992547409949007199254740994

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.

CheckEvidence to retainPassing outcome
Decode adjacent IDs ending in 992 and 993 from the fixtureOriginal response text and decoded field typesTwo distinct exact internal strings
Persist, read, enqueue and consume bothValues and types at each boundaryNeither identity changes or disappears
Replay one exact ID twiceScoped keys and record countOne identity is recognized as repeated
Export and reimportRaw exported field and import settingsNo rounding or scientific-notation substitution
Build a later lookupFinal serialized request fieldExact original ID under the required wire type
Receive an unsafe Number without original textValidation result and recovery actionStop 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.

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.