A JSON API is easiest to use when every endpoint follows the same conventions, so a developer who has learned one endpoint can predict how the rest behave. The conventions below are widely used and avoid the most common sources of client bugs. What matters most is choosing a convention and applying it everywhere.
Use either camelCase (createdAt, common in JavaScript ecosystems) or snake_case (created_at, common in Python and Ruby APIs) and never mix them. Mixed styles force clients to remember each field individually.
Also:
items, orders) and singular names for single values.isActive, hasChildren, canEdit.quantity beats qty.These mean different things, and clients often treat them differently:
"middleName": null means the field exists and has no value.middleName key can mean "not set", "not requested" or "not available in this version".Choose a rule and document it. A common approach is to always include every field defined for a resource, using null for empty values, so the response shape is predictable. For partial updates (PATCH), missing means "leave unchanged" and null means "clear the value".
"2026-03-15T14:30:00Z". Avoid Unix timestamps whose unit (seconds or milliseconds?) clients must guess, and avoid locale formats like 03/04/2026.{"amount": 1999, "currency": "USD"}, or a decimal string like "19.99". Floating-point numbers can't represent many decimal values exactly."pending", "shipped"), never integers whose meaning lives in documentation.Any endpoint that returns a list will eventually return too much. Paginate from the start:
json{ "items": [ {"id": "o_101", "status": "shipped"}, {"id": "o_102", "status": "pending"} ], "nextCursor": "eyJpZCI6Im9fMTAyIn0", "hasMore": true }
Cursor-based pagination stays correct when records are added or removed between requests. Offset-based pagination (?page=3&limit=50) is simpler but can skip or repeat items while data changes. Always cap limit on the server.
Wrapping lists in an object rather than returning a bare array also lets you add nextCursor, totals or other metadata later without breaking clients.
Return the correct HTTP status code and the same error envelope from every endpoint, with a stable machine-readable code. See API error JSON payload patterns for examples.
/v2/orders) or a header, and keep old versions running long enough for clients to migrate.{"customer": {"id": ...}} rather than sometimes an ID and sometimes an object.Content-Type: application/json; charset=utf-8 and compress responses with gzip or Brotli.Validate incoming request bodies against a schema and reject invalid input with a clear error. Validating your own responses in tests catches accidental breaking changes. See JSON Schema basics.
Send requests to your API with curl or your API testing tool, and paste responses into the JSON Formatter to check naming, null handling and date formats across endpoints. Comparing responses from two versions is a quick way to spot accidental breaking changes.