Designing API Request Timeouts: The Server-Side Contract Customers Build Retry Logic Against
Request timeouts are typically thought of as a client-side concern. The server-side timeout is the contract customers build retry logic against, and getting it wrong produces compounding bugs across customer integrations.
Request timeouts are typically thought of as a client-side concern. The customer's HTTP client sets a timeout, the request is abandoned if the server takes too long, the customer retries. From the server's perspective, this looks like a partially-completed request that may or may not need to be cleaned up depending on the operation.
The reality is that the server-side timeout is the contract customers build retry logic against, and getting it wrong produces compounding bugs across customer integrations. A server that takes 90 seconds to respond when its documented maximum is 30 seconds is breaking the contract regardless of whether it eventually returns a successful response. A server with no documented timeout produces customer retry storms during incidents that an explicit timeout would prevent.
What the server-side timeout actually controls
The server-side timeout has three components, each of which has to be set explicitly because the framework defaults are usually wrong for the use case. The connection timeout is the maximum time the server will hold an idle connection waiting for the next request. The request timeout is the maximum time the server will spend processing a single request. The response timeout is the maximum time the server will hold a response open before forcing closure.
The request timeout is the one that matters most for the customer contract. It is the upper bound on how long the customer's HTTP client should expect to wait for any response from your API. A customer client with a 30-second timeout against a server with no enforced limit will sometimes time out client-side without the server having any indication that the request was abandoned, and the server-side work may continue or may not depending on framework behavior.
The right server-side timeout for B2B SaaS
The right server-side timeout for B2B SaaS APIs is 30 seconds for synchronous endpoints. This is long enough to handle expensive queries, external service calls, and reasonable retry-with-backoff patterns inside the request, and short enough that customer-side timeouts can be set conservatively below 60 seconds without risking false timeouts during normal operation.
The 30-second number is industry-converged. Stripe enforces 30 seconds. GitHub enforces 10 seconds for synchronous API requests and longer for asynchronous endpoints. AWS API Gateway defaults to 30 seconds and enforces a hard ceiling at 29 seconds. The convergence is not accidental: 30 seconds is the longest customers will reasonably wait for an interactive request and the shortest that handles slow downstream services without false timeouts.
The exceptions are explicit async endpoints (file uploads, bulk operations, long-running computations) where the contract is 202 Accepted with a job ID and polling. For these endpoints, the request timeout is shorter (the request just enqueues work) and the response timeout for the job-status endpoint is the same 30 seconds as everything else.
What customers do with the contract
Customers build retry logic against your documented timeout. A customer that knows your timeout is 30 seconds sets their client-side timeout at 35 seconds (some safety margin) and treats anything slower as a transient failure to retry. A customer that does not know your timeout sets their client-side timeout at a guess, which is sometimes much shorter and produces false retries during normal slow responses.
The contract has to be documented and enforced consistently. If your documented timeout is 30 seconds but you sometimes take 60 seconds, customers will eventually adjust their timeouts to 70 seconds and your effective contract becomes 60 seconds with extra customer-side waiting. The retry behavior degrades for everyone.
The header surface for communicating timeout state is small. The Retry-After header on 503 responses tells customers when to retry after a server-side timeout. The X-Request-Timeout header (non-standard but increasingly common) tells customers what timeout the server enforces on the current request. Neither is universally honored, and documentation is the more reliable channel.
What the timeout should not interrupt
The timeout has to interrupt request processing in a way that respects in-flight work. A request that has already initiated an external side effect (charged a credit card, sent a webhook, scheduled a background job) should not be interrupted in a way that leaves the side effect half-completed. The right pattern is to make the side effect idempotent and to let the request complete cleanup even if the client has disconnected, then return the final state on the next idempotent retry.
The timeout also should not interrupt requests that have completed their work and are in the response-write phase. A 30-second timeout for processing plus 1 second for response transmission is the right shape; if the response is slow because the network is slow, the timeout should not cut it off mid-response.
What does not work
No documented timeout is the most common mistake. Customers cannot build correct retry logic against an unknown contract, and your effective timeout becomes the longest your server has ever taken. The fix is to document the timeout and enforce it.
Different timeouts for different endpoints without clear documentation is the second mistake. If /v1/large-export has a 5-minute timeout and /v1/list has a 30-second timeout, customers building generic retry middleware cannot use a single client-side timeout that works for both. The fix is either to unify the timeouts or to document each endpoint's specific timeout.
Silent timeout extension is the third mistake. A server that quietly handles requests longer than its documented timeout, possibly because the operation team raised the limit during an incident and forgot to update it, breaks the customer contract without communicating the change. The fix is to treat the timeout as part of the API contract subject to versioning and deprecation discipline.
The deeper observation
The server-side timeout is one of the API contract elements that customers cannot see directly but that shapes every retry decision they make. Getting it right at the framework configuration level pays back in proportion to how many customers build retry logic. Getting it wrong produces compounding bugs that surface as customer-side incidents that look unrelated to your API behavior.
The right discipline is to set the timeout at framework configuration, enforce it through middleware that hard-cuts requests at the limit, document it as part of the API contract, and treat changes to it with the same deprecation rigor as schema changes. The customer cannot see the timeout directly, but every customer's retry behavior depends on it.
Read more essays and technical writing at anethoth.com — a notebook on databases, distributed systems, biology, and the engineering that holds the world together.