The API Design Decisions That Will Haunt You in 18 Months
Most API design mistakes don't hurt on day one — they hurt eighteen months later, when you have real external consumers and every 'fix' is now a breaking change. Here are the decisions we see teams regret most, almost always too late to cheaply undo.
Returning bare arrays instead of enveloped responses
`GET /users` returning a raw JSON array seems clean until you need to add pagination metadata, a total count, or a cursor — and now every client parsing a top-level array breaks. Envelope your list responses from day one: `{ data: [...], meta: { total, cursor } }` costs nothing early and saves a breaking version bump later.
No API versioning strategy at all
'We'll version it when we need to' means you'll be retrofitting version headers or URL prefixes onto live traffic with real consumers who didn't sign up for a migration. Decide your versioning approach — URL path, header, or content negotiation — before your first external consumer, even if v1 is the only version that will ever exist.
Leaking database schema directly into response shapes
Serializing your ORM models directly is fast to build and creates a permanent coupling between your database schema and your public contract. A column rename that should take ten minutes now requires a deprecation cycle because it's technically a breaking API change.
Inconsistent error shapes across endpoints
If `/orders` returns `{ error: "message" }` and `/users` returns `{ errors: [{ code, detail }] }`, every client integration has to special-case error handling per endpoint. Pick one error envelope shape — ideally following an existing convention like RFC 7807 — and enforce it at the framework level so individual endpoints can't drift.
Synchronous endpoints for what should be async operations
Long-running operations (report generation, bulk imports, video processing) forced into a synchronous request/response cycle eventually hit timeout walls as data volume grows. Model these as async from the start — return a job ID and a status endpoint — even if the first implementation just does the work inline before responding.
No rate-limit headers or documented limits
Silently throttling or rejecting requests without `X-RateLimit-*` headers means every integrator finds your limits by hitting them in production, usually during their busiest traffic period. Publish limits and surface them in headers from the first external release.
The common thread: almost none of these cost meaningfully more time to do right the first time. They cost real time — and real client goodwill — to fix after the API has external consumers depending on the shape you shipped. If you're scoping a new API, our Web, API & Mobile Dev team can review the contract before it ships, not after.
Ready to build something exceptional?
Tell us about your project — we'll respond within 24 hours.