Define the resource and customer job first

A single request count across an entire API is a poor substitute for understanding the work each request starts. One catalogue lookup may use a cache, while one report request may scan a database and generate a file. OWASP identifies unrestricted resource consumption as an API risk and recommends limits on interaction frequency, payload size and other resources, tuned to business needs. Begin with the customer job: is a partner checking stock during checkout, importing a catalogue overnight, or creating an order that must never be lost? Name the operation, expected request pattern and consequence of delay. Then list the constrained resources: CPU, database connections, worker slots, downstream paid calls, storage or bandwidth. This produces a reason to limit a particular route. A firm can protect an expensive export more tightly than a lightweight read while still allowing urgent order acknowledgements. The actual thresholds require local traffic and capacity evidence; no universal requests-per-minute number follows from the standard or from an article.

Choose whose budget is being consumed

A limit needs an identity. For an authenticated partner API, a partner or application credential is often a useful primary key, but credentials can be shared by several installations and a single business may hold multiple keys. A limit solely by IP address can group unrelated customers behind a network address or miss clients that distribute traffic. Decide whether the budget belongs to the organisation, application, user, operation, destination account or some combination, and document how credential rotation affects it. Do not allow a partner to multiply its entitlement simply by requesting more keys unless that is an intentional commercial policy. At the same time, protect unauthenticated endpoints with controls appropriate to their abuse risk. Keep authorisation separate: a request that fits within a rate limit is not thereby allowed to read another customer’s data. Define whether rejected authentication attempts count toward a protective budget, and ensure one bad actor cannot consume a shared allowance needed by legitimate users.

Limit cost as well as frequency

A client can stay below a per-minute request ceiling and still exhaust a system by asking for huge pages, deeply nested queries or many concurrent expensive tasks. OWASP’s API guidance explicitly includes payload and parameter limits, and its examples show why simple request counting can miss batched work. Set bounds for page size, upload size, report range, batch item count and concurrent jobs where those dimensions apply. Measure queue time and resource use by endpoint rather than assuming requests are equal. Prefer a small set of predictable service tiers that partners can understand. A business may grant a planned bulk-import window, but that should be an explicit allowance with monitoring, not a silent bypass of every safety limit. Document which work is synchronous and which returns a job identifier for later collection. If downstream suppliers bill per call, include their cost exposure in the budget. The limit policy should state what is rejected, what is queued and what is accepted for later processing.

Make a rejection understandable and recoverable

RFC 6585 defines HTTP 429 for a user that has sent too many requests in a given amount of time; it says the response should explain the condition and may include Retry-After. RFC 9110 defines Retry-After as either a delay in seconds or an HTTP date. Use 429 when the request has genuinely crossed the relevant policy and return a safe, stable error body identifying the applicable operation or budget. Where the server can estimate a useful wait, provide Retry-After; do not invent a precise reopening time when a concurrent-job limit depends on unpredictable work. State whether the rejected request was processed, especially for writes. A client cannot safely retry an order creation if it is unclear whether the first attempt committed. Rate-limit errors must not leak another tenant’s traffic, account identifiers or secret configuration. Keep the response contract consistent across the gateway and application so clients do not need to guess whether a JSON error, HTML page or connection close means the same thing.

Plan the client’s behaviour before enforcement

A well-behaved client should stop rapid retries after 429, observe a valid Retry-After value when present, and use bounded backoff with some variation when many clients might wake together. A retry policy needs a maximum wait, a maximum number of attempts and a way to alert a human or resume later. Never treat every failed write as safe to repeat; design the write operation’s idempotency and outcome lookup separately. For a stock read, serving slightly older cached data may be acceptable only if the business has approved that trade-off and the screen labels it honestly. For a critical order, a queued state or operator follow-up may be better than dropping work. Explain these paths in partner documentation and test them with a sample client. Client controls should avoid turning a short rate limit into a prolonged outage through synchronized retry storms. They also need to handle a lost response differently from an explicit 429, because a lost response does not prove the server declined the operation.

Use a worked partner scenario

Imagine a retailer exposing stock lookup and report export endpoints to one fulfilment partner. During a promotion, lookup traffic rises sharply; at the same time the partner starts several large historical exports. Rather than impose one shared ceiling that blocks checkout lookups, the retailer gives the expensive export operation a smaller concurrency budget and a bounded date range, while assigning lookup its own measured capacity budget. When export capacity is occupied, a new request receives the documented rejection or queue response, with a job reference if accepted for later work. The partner’s client waits according to the contract and continues its other allowed operations. Staff monitor rejected requests and actual resource pressure, then revisit thresholds with the partner if normal work is repeatedly delayed. This is a design example, not a claim about an observed retailer or a recommended numeric limit. It illustrates why the decision should be tied to the operation, its cost and the customer consequence of waiting.

Introduce the policy with evidence

Gather a representative period of request volume, burst shape, latency, error rate, tenant mix and resource consumption before setting initial thresholds. Include ordinary peaks and known batch windows; averages hide the moments that matter. Map each request to the authenticated owner and route while keeping logs proportionate and avoiding sensitive payloads. In a testing or observation phase, calculate which legitimate requests a proposed policy would reject, then adjust for documented business needs. Tell partners the policy, error shape and planned enforcement date through existing contract channels. Start with alerting, move to a limited enforcement cohort if the architecture permits, and watch both capacity and partner outcomes. An emergency circuit breaker may need a separate, stricter rule than the normal commercial allowance. Record who can alter thresholds, for how long and why. Otherwise a one-off exception can become an invisible permanent weakness or an unfair benefit to one client.

Test boundaries and failure recovery

A useful acceptance test exercises just below and just above each limit, across two partners, two operations and a credential rotation. Check that one partner cannot consume another’s allowance, a batch cannot evade cost bounds, and concurrent requests do not all pass because counters are updated too late. Verify 429 response status, safe body, Retry-After syntax when supplied and documented client behaviour. Simulate a lost response on a write and confirm the client can discover the outcome without creating duplicate business records. Simulate a gateway restart or distributed counter failure and define the intended fail-open or fail-closed behaviour for each risk level; the right choice may differ by operation. After deployment, review both rejection rates and resource saturation. A low rejection count with an exhausted database is not success, while many rejected normal requests may mean the policy is too tight. The goal is a sustainable customer workflow, supported by observable evidence and a documented way to correct the limit.

Before accepting the change

  • Document the owner and operation for every budget.
  • Verify 429 and any Retry-After value against the client contract.
  • Test a lost write response separately from an explicit rate rejection.

Sources & further reading