If Your API Needs a Long Explanation It Is Probably Too Complex

by Arif Ikhsanudin, Backend Developer

The explanation as a diagnostic

Before you write a paragraph of documentation for an endpoint, stop and read what you are about to write. If you are explaining why a field has different semantics depending on request context, the field is probably two different fields. If you are explaining the correct sequence of calls required to accomplish a single task, that task is probably one endpoint. If you are documenting exceptions to the general behavior, the general behavior probably needs rethinking.

Documentation should clarify, not compensate. An API endpoint that requires a tutorial is an API endpoint that has leaked its implementation into its interface.

Symptoms of accidental complexity

Context-dependent field semantics: A request field that means different things based on other fields in the same request:

{
  "type": "subscription",
  "amount": 100,
  "interval": "monthly"  // only valid if type is subscription; ignored otherwise
}

The consumer must know the rule. When they forget and set interval on a one-time charge, it is silently ignored. The fix is two separate endpoints or two separate request schemas — POST /charges and POST /subscriptions.

Side effects encoded in a single endpoint: A POST /orders that creates the order, charges the payment method, sends a confirmation email, updates inventory, and notifies a warehouse system — all in one synchronous call. When any one of these steps fails, the client receives an error without knowing which step failed or what state things are in.

Complex side effects belong in an event-driven model where the initial response confirms acceptance, and each downstream step is a separate observable event.

Implicit state machine: An endpoint whose behavior depends on the current state of the resource being operated on, without explicitly modeling the state machine:

"You can call PATCH /subscriptions/{id} with status: 'paused' only if the subscription is currently active. If it is already paused, you get a 409. If it is cancelled, you get a 422. If it is in trial, you get a 400 unless you also provide resume_date."

The consumer must memorize this. The fix is to make the state machine explicit — model the allowed transitions, return clear errors that name the current state and the transition attempted, and document the state machine as a diagram rather than prose.

The right level of abstraction

One indicator of appropriate API design: the vocabulary in your API matches the vocabulary in your domain, not your database schema.

If your users think in terms of "subscriptions" and "plans" and "billing cycles," but your API exposes "recurring_payment_schedules" and "product_tier_assignments," the consumer has to translate between two vocabularies constantly. That translation lives in the consuming code and in every developer's head.

Name things the way your users think about them. POST /subscriptions is better than POST /recurring-payment-schedule-configurations even if the latter is more precisely accurate to the underlying data model.

The endpoint count as a design signal

More endpoints is not better. An API with 200 endpoints for a domain that should have 30 has usually modeled its internal service decomposition rather than its external use cases.

Audit which endpoints actually get called. In practice, most APIs have a long tail of endpoints that account for very little traffic. These are candidates for consolidation or deprecation.

A useful question for every endpoint: what single task does this enable? If the answer is "it depends" or requires a conjunction ("it does X and also Y"), the endpoint is probably doing too much.

When simplification requires breaking changes

Sometimes you cannot simplify without a version bump. A response field that currently serves two purposes cannot be split into two fields without clients updating their parsing logic.

In these cases:

  1. Design the simpler version in v2 from the start, before building v2 features.
  2. The migration from v1 is the opportunity to pay down the complexity debt.
  3. Document the complexity in v1 clearly and document the simplification in the v2 migration guide — "if you were working around X in v1, you no longer need to."

Complexity deferred to documentation is still complexity. The document is evidence that the design needs attention — use it as input to the next design iteration, not as a permanent substitute for a simpler interface.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Writing Efficient JPA Queries — Fetch Strategies, Projections, and Native Queries

JPA abstracts SQL but does not eliminate the need to think about it. The fetch strategy, the columns selected, and the SQL generated determine whether your queries are fast or slow at scale. Here is how to control each layer.

Read more

How Singapore Scaleups Are Cutting Backend Overhead the Smart Way

You raised your Series A. You tripled your engineering team. Somehow, your backend ships slower than it did when there were four of you.

Read more

How to Negotiate Without Making the Client Feel Like They Lost

Good negotiation in contracting is not about winning — it is about reaching terms that both parties can feel good about, which makes the actual work go better.

Read more

The Contract Clause That Saves You From Scope Creep

Most contractor scope problems are not caused by bad clients — they are caused by contracts that did not anticipate scope changing. One clause handles most of it.

Read more