Define resources around stable concepts
Choose resource identities that reflect the business model. An invoice, its approval history, and an export job have different lifecycles and should not become one overloaded response. Keep identifiers stable while allowing display names and descriptive attributes to change. Document who owns each resource lifecycle.
Use HTTP methods according to their semantics. A read should not trigger a business mutation. PUT and DELETE have idempotent intended effects as defined by HTTP, while a POST operation needs its own duplicate handling strategy when retries can occur. Specify accepted content types, size limits, and supported query parameters rather than allowing undefined parser behavior.
Handle concurrency explicitly
Use conditional requests when a write must apply to a known resource version. A strong ETag and If-Match condition can prevent a user from overwriting a concurrent change. HTTP defines strong comparison for If-Match; a failed condition normally produces HTTP 412. An API requiring a missing precondition can use HTTP 428. Evaluate the condition against the current representation at the write boundary.
For long running operations, return a documented job resource or status location and distinguish acceptance from completion. Consumers need to know whether they should poll, subscribe, cancel, or await a callback. A successful acceptance response should never imply that an external action has already finished.
PATCH /invoices/inv_1042 HTTP/1.1
Host: api.example.com
Content-Type: application/json
If-Match: "invoice-version-7"
{ "reviewNote": "Contract terms checked" }Make error responses stable and actionable
RFC 9457 defines problem details for HTTP APIs. Use a stable problem type and structured extensions for machine behavior, while a clear human detail explains the specific occurrence. Clients should not parse prose to decide whether to retry or highlight a field.
Keep the HTTP status aligned with the actual response and avoid leaking internal queries, stack traces, credentials, or another tenant's resource existence. Include a safe correlation reference for support. Define validation errors, authentication failures, permission denials, conflicts, rate limits, and temporary service failures as different cases with distinct recovery behavior.
Document and test the API contract
An OpenAPI description can document operations, schemas, parameters, and security requirements. Validate it in delivery workflows and test that the implementation agrees with it. A generated specification is helpful only when examples, required fields, and error responses reflect actual behavior.
Build consumer scenarios covering empty results, maximum payloads, invalid filters, interrupted requests, expired credentials, and conditional write conflicts. Verify authorization on every resource lookup and action. Compatibility review should include semantic changes such as a status redefinition, because unchanged JSON structure can still break a consumer's business logic.