API Design Mistakes I Made So You Don't Have To

Designing an API feels easy when you're the only one using it. You know what every field means, you know which endpoint to call first, and you know that status: 2 means "pending" because you wrote it at midnight. Then someone else integrates with it, and you discover you've built a puzzle.
Here are mistakes I've made, in roughly the order I made them.
1. Returning 200 OK for everything
HTTP/1.1 200 OK
{"success": false, "error": "user not found"}

Clients, proxies, monitoring and retry logic all read HTTP status codes. Use them: 404 for missing things, 400 or 422 for bad input, 401/403 for auth, 409 for conflicts, 429 for rate limits, 500 only for actual server failures.
2. Errors that say nothing
{"error": "invalid request"} is a riddle. A useful error says what, where and how to fix it:
{
"error": {
"code": "validation_failed",
"message": "email is not a valid address",
"field": "email"
}
}
The code is for programs; the message is for humans. Never make a program parse an English sentence to decide what happened.
3. Inconsistent naming
userId in one endpoint, user_id in another, uid in a third, and customer in the docs. Pick one style (snake_case or camelCase) and one word for each concept, and stick to them. Consistency is the cheapest documentation there is.
4. No pagination
GET /orders returning every order works great with 50 orders in development. It works less great with 3 million orders in production. Paginate from day one, preferably with cursors:
GET /orders?limit=50
→ { "data": [...], "next_cursor": "eyJpZCI6MTA1MH0" }
GET /orders?limit=50&cursor=eyJpZCI6MTA1MH0
Offset pagination (?page=3) is simpler but gets slow and skips items when data changes between requests.
5. Breaking changes without versioning
Renaming a field felt like a small cleanup. It broke three mobile apps that couldn't be updated for a week because of app store review. Additive changes (new optional fields, new endpoints) are safe. Removing or renaming things needs a new version, a deprecation period and a polite email.
6. Dates in local time
"created": "03/04/2025 5:00" — is that March or April? In which time zone? Use ISO 8601 in UTC: "2025-04-03T17:00:00Z". Every language can parse it, and nobody has to guess.
7. Money as floats
0.1 + 0.2 is 0.30000000000000004 in most languages. Represent money as integers in the smallest unit (cents) or as decimal strings, and always include the currency.
The rule behind all of these
An API is a user interface for programmers. Be predictable, be explicit and be kind to the person integrating at 11 PM who just wants to know why their request failed. They will remember your API either as "pleasant" or with a word I can't print here.