Numbers: where precision goes
JSON numbers are doubles in practice, and that quietly breaks ids and money.
The 53-bit limit
JSON does not specify a size for numbers, but almost every parser reads them into a 64-bit float. That holds integers exactly only up to 2^53 − 1, which is 9007199254740991.
A 19-digit id — a Twitter/X id, a Snowflake id, a bigint primary key — is larger than that. It parses without error and comes back changed, usually in the last digit or two. There is no exception and no warning; the id is simply wrong, and it will match nothing on the other side.
The fix is to send such ids as strings. Almost every API that learned this lesson does, which is why ids so often appear quoted in responses that otherwise use numbers.
Money is not a float
0.1 + 0.2 is 0.30000000000000004 in any language using binary floating point, because a tenth cannot be written exactly in binary any more than a third can in decimal. This is not a bug to be worked around with rounding; it is how the type works.
Money should be an integer count of the smallest unit — paise, cents — or a string parsed into a decimal type. Storing ₹19.99 as a float and adding a thousand of them gives an answer that is wrong by an amount somebody will eventually notice.
JSON itself is fine with the digits: "19.99" as a string, or 1999 as paise, both survive the trip intact. The loss happens in the parser, so the decision has to be made by the format you choose, not by the code that reads it.
Worked examples
An id that survives being parsed
/{"id": "9007199254740993", "amount_paise": 1999}/Against:
Both would be wrong as bare numbersAs a number the id comes back as …92, and the amount as 19.99 accumulates error over a thousand additions.
Check yourself
Practice questions written for this lesson — not past exam papers.
Practise every question in this subject
Why do large ids arrive as strings in many APIs?
How should a money amount travel in JSON?