← Blog ·

REST API JSON Best Practices: Naming, Errors, Pagination & Versioning

Why these decisions matter

Once your API is in production, every shape choice becomes load-bearing. Clients depend on field names, error formats and pagination semantics. Changing them is a breaking change. Get them right early.

Naming conventions

Use camelCase for keys. It's the most common convention in JSON ecosystems and matches JavaScript naturally. snake_case is also fine if your backend is Python or Ruby — just be consistent across the whole API.

{
  "userId": 42,
  "createdAt": "2026-04-22T10:30:00Z",
  "isActive": true
}

Always use ISO 8601 for dates

"createdAt": "2026-04-22T10:30:00Z"

Never invent custom formats. Never send Unix timestamps unless you have a specific reason — they're harder to debug.

Use strings for large IDs

JSON numbers are IEEE-754 doubles. IDs over 2^53 lose precision. Database row IDs, snowflake IDs and similar should always be strings:

{ "id": "9007199254740993" }

A consistent error envelope

Every error response should have the same shape so clients can write one handler:

{
  "error": {
    "code": "user_not_found",
    "message": "No user exists with id 42.",
    "details": { "id": 42 },
    "requestId": "req_abc123"
  }
}
  • code is machine-readable and stable across releases
  • message is human-readable
  • requestId lets users quote it when they email support
  • details is structured context for debugging

Pagination patterns

Cursor-based (recommended for most APIs):

{
  "data": [],
  "pageInfo": { "endCursor": "eyJpZCI6MTAwfQ==", "hasNextPage": true }
}

Offset-based (simpler, but slow on large tables):

{
  "data": [],
  "page": 3,
  "pageSize": 50,
  "total": 12345
}

Cursor pagination scales; offset pagination doesn't.

Versioning

Three common strategies — pick one and stick with it:

  1. URL versioning/v1/users, /v2/users — most explicit
  2. Header versioningAccept: application/vnd.myapi.v2+json — keeps URLs clean
  3. No versioning, evolve carefully — only add fields, never remove or change semantics. Works for small private APIs.

Field stability rules

  • Adding a new field is non-breaking — clients should ignore unknown fields
  • Removing a field is breaking
  • Changing a field's type is breaking
  • Changing a field's semantics is breaking (and worse, silent)

Document these rules and enforce them in code review.

Null vs missing

Be intentional. null means "we know there's no value." A missing field means "we don't have data" or "this isn't applicable." Pick one convention per field and document it.

Don't reinvent: study Stripe or use JSON:API

If you're stuck designing from scratch, study Stripe's API — it's the gold standard. Or adopt the JSON:API spec for a fully-specified format.

Test your responses

Format and validate your sample responses with JSONNeat and the validator to catch shape regressions before clients do.


Try the tools: JSON Formatter · Validator · Minifier