Designing an interface you can live with
Consistency before beauty
The same naming convention on every route, the same response structure, the same date format, the same error structure. Ten consistent routes are easier than five brilliant ones and five different.
Return a stable structure: a wrapper object with data and metadata, so you can add fields without breaking.
Decisions that come back to you
Pagination. Decide in advance — by offset or by cursor — and support it in every list. Lists without pagination always grow beyond expectation.
Filtering and sorting. Defined and documented, not a free field where each consumer invents rules.
Identifiers. Stable, not sequential, and not exposing business information in their count.
Errors are part of the contract
A correct status code, a fixed error identifier you can branch logic on, a readable message, and a request identifier for investigation. An interface that returns free text that differs on each error forces the consumer to check strings.
Going deeper
Document the interface from the code itself so the docs don't age, and provide a test environment with dummy data. And before publishing: have someone who didn't write the interface implement a full scenario against it — every question they ask is a design flaw, not a gap in their understanding.