← Back to Blog
Engineering··8 min read

API Design Mistakes That Will Haunt You Forever

HN Reference: HN discussion on API versioning hell and the Stripe API as a gold standard (Nov 2023)

APIs are forever. Once customers integrate with your API, changing it becomes exponentially harder. Here are the design mistakes we see startups make that haunt them for years.

Mistake 1: Inconsistent Naming

One endpoint uses user_id, another uses userId, another uses user. This seems minor until you have 50 endpoints and every integration is a guessing game.

The fix: Pick a convention and enforce it from day one.

  • REST: snake_case for JSON keys (Stripe-style)
  • GraphQL: camelCase (community convention)
  • Never mix. Use a linter.

Mistake 2: No Pagination from Day One

"We only have 100 records, why paginate?" Because in 6 months you'll have 100,000 and your API will timeout.

The fix: Every list endpoint gets cursor-based pagination from the start:

GET /api/items?cursor=abc123&limit=20

Don't use offset pagination. It breaks when records are inserted/deleted between requests.

Mistake 3: Leaking Your Database Schema

Your API response is just your database rows as JSON. Congratulations, you've coupled your API to your internal schema. Now you can never refactor your database without breaking integrations.

The fix: Always have a transformation layer. Your API shapes should be deliberate, not incidental.

Mistake 4: No Rate Limiting

"Let's add rate limiting later." Later never comes until a customer's buggy script DDoS's your service.

The fix: Rate limit from day one. Even generous limits (1000 req/min) prevent accidental abuse. Return proper 429 responses with Retry-After headers.

Mistake 5: Unclear Error Responses

{ "error": "Something went wrong" }

This is not an error response. This is a cry for help.

The fix: Every error response should include:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "email field is required",
    "field": "email",
    "request_id": "req_abc123"
  }
}

Machine-readable error codes, human-readable messages, and a request ID for debugging.

Mistake 6: No Versioning Strategy

You'll change your API. The question is whether you break existing integrations when you do.

The fix: URL versioning is simplest:

/api/v1/users
/api/v2/users

Support at least the previous version for 12 months after deprecation. Give customers time to migrate.

Mistake 7: Synchronous Everything

Every API call is synchronous. Your customer waits 30 seconds for a report to generate, and if they refresh the page, it starts over.

The fix: For anything taking more than 2 seconds, use async patterns:

  1. Return a 202 Accepted with a job ID
  2. Provide a status endpoint
  3. Optionally, use webhooks for completion notification

The Stripe Standard

If you want to see API design done right, study the Stripe API. Consistent naming, clear errors, excellent versioning, comprehensive documentation. It's not an accident that developers love integrating with Stripe.

Your API is your product's interface to other products. Design it like your business depends on it — because it does.

API DesignEngineeringBest PracticesSaaS