API Rate Limit Policy
Design the rate-limit policy a public API publishes to its consumers - the metering model per paradigm (REST request counting vs GraphQL cost points), tier and quota-vs-burst numbers, multi-tenant fairness, rate-limit headers (legacy X-RateLimit-* vs IETF RateLimit fields), 429 and Retry-After behavior, enterprise and partner overrides, and change-notice rules. Use whenever the user mentions rate limits, quotas, throttling tiers, 429 responses, noisy neighbors, or limit-increase requests - even if they never say "rate-limit policy". Policy layer only, not gateway configuration. Do NOT use for the 429 error envelope - use samber/developer-platform-skills@api-error-design instead.
- Skill ID
- samber/developer-platform-skills/api-rate-limit-policy
- Publisher
- samber
- Repository
- developer-platform-skills
- Installs
- 324
- Files
- 6
- License
- MIT
- Synced
- Oct 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
samber/developer-platform-skills/api-rate-limit-policyInstalls these files- SKILL.md
- evals/evals.json
- references/graphql-cost-metering.md
- references/header-families.md
- references/overrides-and-change-notice.md
- references/vendor-limit-models.md
What this skill tells the agent
API Rate Limit Policy
You are an API rate-limit policy designer. Design the limits a public API publishes to its consumers - the metering model, the tier and burst numbers, the fairness rules, the headers, the throttle response, the override path, and how changes land - so an integrator can predict, observe, and adapt to throttling instead of discovering each ceiling by tripping it. Which gateway or middleware enforces the limit is out of scope; what the limit promises and how it is communicated is the whole scope.
Zuplo's one-line purpose statement is the mission: rate limiting sets "a policy of fair access to API resources and prevent[s] any single user or application from consuming excessive resources and impacting the experience of others." And GeekyAnts' framing is why this is policy work, not plumbing: "designing a rate limiter is fundamentally a strategic decision about fairness, scalability, and user experience."
Memory (advised): When memory lives in a file, consider using developer-platform-context.md; if a different memory system is in use, rely on that instead. The file is an advisory reference, not a mandatory requirement. Separate task info in different sections. Remove finished tasks. Add a date to a task; no date for general project context. Some interview responses may differ between 2 tasks.
Clarifying questions
Ask these before designing anything; each answer feeds a numbered step. Batch them - this is a tactical design task, not a strategy interview.
- Paradigm: REST-only, GraphQL-only, or both? (Request counting and cost points are incompatible metering models; step 1 picks per surface.)
- Greenfield, or limits already enforced? If existing: request the currently enforced numbers and the currently documented numbers - drift between the two is the first finding.
- What consumer tiers exist or are planned (free / self-serve paid / enterprise-partner), and are enterprise customers already asking for higher limits?
- Abuse pressure: is the API scraped or hit adversarially, or is traffic mostly well-behaved integrations? (Promotes the sliding-window rung and a secondary guard in step 1.)
- Has one customer's traffic ever degraded others' latency? (Raises the priority of step 3's fairness layers.)
- Is the API served from more than one region? A limit enforced independently per region multiplies a caller's real global throughput by the region count - cited as "not theoretical, it's a real exploit vector" - so the published limit must state its scope.
- What can the edge/gateway already emit? (An edge that produces IETF structured fields cheaply re-ranks the header menu in step 4; a gateway that can't count cost points constrains step 1.)
- By when must the published policy land, is this a one-off fix (unblock one enterprise negotiation) or a compounding contract the platform operates for years, and what is the effort ceiling - engineering hours for limiter work, an on-call rotation to hold fairness layers, appetite for a consumer-visible change?
Question 8 exists because the algorithm menu (step 1) and the header menu (step 4) diverge sharply on time-to-effect, durability, and effort; neither ranking can be picked without it. Each answer moves a different rung:
- A hard date promotes whatever the current gateway already enforces, and the legacy header trio.
- A compounding mandate promotes the sliding window and the both-families rung.
- A low effort ceiling deletes the fairness layers of step 3 from this pass rather than parking them at the bottom, with "the first noisy-neighbour incident" as their unblocking condition.
Consumer tiers
The consumer tier is the axis that changes this design, and it is not a mere segmentation: the tier ladder is the policy artifact this skill produces.
- Anonymous/free callers - keyed per IP or per free key; the tightest numbers, the first shed under load. They learn their limits from headers alone.
- Self-serve paid integrators - keyed per API key or org; published exact numbers they can capacity-plan against. They need a documented table.
- Enterprise and partners - published process instead of published numbers; overrides keyed to the authenticated principal (step 6). They need a named override path with lead times.
Workflow
- Pick the metering model per paradigm - and the algorithm, which is what the number promises.
- Design tiers: quota and burst as two numbers, keyed deliberately.
- Layer fairness and tenant isolation.
- Choose the header family.
- Design the throttle response: 429 and Retry-After.
- Define the enterprise/partner override path.
- Write the change-notice policy.
Each step has a section below, in order.
1. Pick the metering model
Two incompatible models exist, split by paradigm - never blend them:
- REST: count requests. GitHub REST is a flat 5,000 req/hr; Shopify REST is a 40-request bucket leaking 2/s. Simple, universally understood, blind to per-request cost.
- GraphQL: price the query in cost points. A one-scalar query and a 100-connection query differ enormously in server cost; the limit is a budget of points per window, with a published cost formula (GitHub: connection
first/last÷ 100, minimum 1; Shopify: scalar 0, object 1, mutation 10, pre-charge then refund). You own the pricing and budget policy; structural guards (depth ceilings, persisted queries) are schema design owned bysamber/developer-platform-skills@public-graphql-api-design. See references/graphql-cost-metering.md. - When both surfaces exist, publish both models separately and state whether they share anything (GitHub: separate budgets, but one shared 100-concurrent-request secondary cap).
- Name the metering unit even when it is neither: Twilio meters concurrency - in-flight requests, not requests-per-window - a fundamentally different unit a caller must plan differently for.
The algorithm underneath is a policy choice too, because it defines what the published number promises (burst behavior, boundary behavior). Four options, ranked:
- efficiency:
token bucket > fixed window > sliding window > leaky bucket - effort:
sliding window > token bucket == leaky bucket > fixed window - value (public developer API):
token bucket > sliding window > leaky bucket > fixed window
- Default rung: token bucket - bucket depth is the burst, refill rate is the sustained quota, so step 2's two numbers fall out of the algorithm for free. It rewards well-behaved bursty clients, it is Stripe's and GitHub's choice, and convergent vendor guidance (Stripe, Google Cloud, AWS API Gateway) calls it "the standard choice for most web services… start here unless you have a specific reason not to." The token-bucket == leaky-bucket effort tie is real: both maintain one bucket per key; they differ in intent, not implementation weight.
- Step down to fixed window only for internal or low-stakes limits where the documented flaw - up to 2× the limit at the window boundary - is harmless (Sentry accepts exactly this trade for simplicity). Its second flaw is the stampede: throttled clients synchronize their retries at the reset boundary, a failure mode the IETF draft itself acknowledges.
- Promote to sliding window under adversarial pressure (question 4). This is the starved option: boundary-proof and fairest, with the most precise
Retry-After, but the highest compute cost - it loses every efficiency round, and scraping/abuse pressure is what promotes it anyway. - Choose leaky bucket when a burst is a threat, not a feature - a fragile downstream or fan-out delivery. Shopify, a payments-adjacent platform, still chose it because flash-sale webhook fan-out dominated: "Each app has access to a bucket… Each second, a marble is removed."
More from samber
Use this skill in a project
Open any RiverX project, search the Skills panel for samber/developer-platform-skills/api-rate-limit-policy, and install it in one click.
