Understanding JSON APIs

Published 2026-04-12 · 10 min read

"JSON API" means different things depending on who you ask. Sometimes it's shorthand for "any HTTP API that speaks JSON". Sometimes it refers to the formal JSON:API specification. This article covers both senses, plus the conventions that make JSON-over-HTTP APIs pleasant to consume.

The basics: JSON over HTTP

Most modern web APIs return JSON. The client sends an HTTP request; the server responds with a JSON body and a Content-Type: application/jsonheader. That's it. Everything else — authentication, pagination, error format, versioning — is convention layered on top.

# Request
GET /api/users/42 HTTP/1.1
Host: example.com
Accept: application/json

# Response
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 42,
  "name": "Ada Lovelace",
  "email": "ada@example.com"
}

Calling a JSON API

Every modern language has a one-liner for fetching JSON. In JavaScript:

const res = await fetch("https://api.example.com/users/42");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const user = await res.json();

In Python with httpx or requests:

import httpx
user = httpx.get("https://api.example.com/users/42").json()

Common conventions

Pagination

Two patterns dominate. Offset/limit (?page=2&perPage=20) is simple and supports random access. Cursor-based (?cursor=abc123) is more stable under writes and scales better. Your response typically includes metadata next to the data:

{
  "data": [...],
  "page": 2,
  "perPage": 20,
  "total": 137
}

Error format

A good error response gives the client a machine-readable code plus a human-readable message:

{
  "error": {
    "code": "user_not_found",
    "message": "No user with id 42",
    "details": { "id": 42 }
  }
}

Combine this with meaningful HTTP status codes (404 for missing resources, 400 for bad input, 401 for unauthenticated, 403 for forbidden, 500 for server bugs) and clients can handle failures cleanly.

Field naming

Pick one convention and stick with it. camelCase matches JavaScript naturally; snake_case reads better in Python and SQL. Mixing the two is the worst option because clients end up with mapping layers on both sides.

Dates

Always use ISO-8601 in UTC: "2026-04-12T10:30:00Z". Unix timestamps are smaller but lose readability; local times are a recipe for bugs.

The JSON:API spec

The formal JSON:API spec is a stricter convention for building APIs that reduces bikeshedding by prescribing exact response shapes. It's verbose but very consistent — worth considering for large APIs with many independently developed clients. For smaller projects, plain JSON with a handful of conventions is usually enough.

Versioning

The two common approaches are URL-based (/v1/users) and header-based (Accept: application/vnd.example.v1+json). URL-based is simpler and easier to debug; header-based keeps URLs stable. Pick one and document it.

Debugging JSON API responses

When you're trying to understand an unfamiliar API, curl the endpoint and pipe the output into the JSON Formatter to see the shape clearly. For complex payloads, the tree viewerlets you collapse sections you don't care about. And once you understand the shape, generate TypeScript types with our JSON to TypeScript converter so your client code stays type-safe.

Well-designed JSON APIs feel like a conversation: predictable, readable, and easy to evolve. Most of that comes from choosing a few conventions early and being rigorous about sticking to them.

More from the blog