← All articles · April 12, 2026 · fmt.hjlabs.in

JSON Formatting Best Practices for APIs (2026)

JSON looks simple — until you ship a public API and discover that "valid JSON" varies between languages, that 2^53 breaks numbers in JavaScript, and that ISO 8601 dates round-trip differently in Go vs Python. This is the 2026 reference for JSON formatting in production APIs.

Indentation: 2 spaces, no tabs

The unwritten standard in 2026 is 2-space indentation, LF line endings, no trailing whitespace. Reasons: smaller diffs, consistent rendering across editors, and tabs render inconsistently in browser-based viewers.

For machine-to-machine traffic, send minified (no whitespace). For developer-facing endpoints (e.g., docs, debug pages), pretty-print with 2 spaces. Use our JSON formatter to switch between modes.

Key ordering: stable, predictable

JSON objects are technically unordered, but every consumer treats key order as meaningful — diff tools, change detection, content hashes. Recommendations:

The 2^53 number problem

JSON numbers are 64-bit floats per the spec. JavaScript's Number can only represent integers exactly up to 2^53 (9,007,199,254,740,992). Any larger integer (Twitter snowflake IDs, Discord IDs, large primary keys) silently corrupts.

Solutions:

Twitter's API uses id_str alongside id for exactly this reason.

Date formats: ISO 8601 with timezone

Always send dates as 2026-04-12T07:30:00Z (UTC, ISO 8601). Avoid:

Use our Unix timestamp converter when you need to debug timestamps in the wild.

Null vs missing keys

Three valid representations of an absent value:

Pick one and stick with it. Null is the most semantically correct ("we know there's no value"), missing is the most compact ("we don't know"), empty string is usually wrong.

Booleans: lowercase only

JSON booleans are true and false, lowercase. Don't send "true" as a string. Don't send 1/0. Don't send "yes"/"no". Strict parsers will reject these.

Floating-point precision

Avoid sending 0.1 + 0.2 = 0.30000000000000004 in JSON. Round to the precision the consumer needs. For currency, use string representations ("123.45") or send integer cents (12345).

Arrays: empty vs missing

Always include the array key with [] if the field is "always-an-array but might be empty." This simplifies client logic — it can iterate without null-checking.

{ "items": [] }   // Good - always an array
{ }                // Bad - client must check existence first

Encoding: UTF-8, no BOM

Send JSON as UTF-8. Don't include a Byte Order Mark (BOM) — it breaks some parsers. Set Content-Type: application/json; charset=utf-8.

Wrapping the response

Two common patterns:

Pick one for your whole API. JSON:API style is verbose but pays off when you start adding pagination metadata.

Error responses: structured

Always return errors as JSON, not HTML or plain text:

{
  "error": {
    "code": "validation_failed",
    "message": "Email is invalid",
    "field": "email",
    "docs": "https://docs.api.com/errors#validation_failed"
  }
}

Validation: schema first

Define a JSON Schema (Draft 2020-12) for every endpoint. Tools: ajv, jsonschema, openapi. Use our JSON validator for ad-hoc checks during development.

The minimal-good-citizen response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "data": {
    "id": "01HQZ...",
    "created_at": "2026-04-12T07:30:00Z",
    "name": "Example",
    "is_active": true,
    "tags": []
  }
}

Tooling

Bottom line

2-space indent, ISO 8601 dates, string IDs for >2^53, lowercase booleans, structured errors. Define a schema. Validate every payload. The boring choices in JSON formatting save you from hours of debugging at 2am.

Try the free dev tools suite

15+ tools. 100% client-side. No signup. No tracking.

Browse all tools →

More from the blog