TL;DR: API rate limiting caps how many requests one user, IP, or key can send in a window. It stops credential stuffing, scraping, and surprise bills on routes that call paid APIs. Add it to login, password reset, and every paid route first. Most stacks need one small library and an afternoon. Then prove it works with a burst test — or check one endpoint now with our free API rate limit checker.

Here is the uncomfortable part. If an AI tool built your app, your endpoints almost certainly have no limits at all. Nothing stops a bot from trying 10,000 passwords against your login route tonight. Nothing caps a script that hammers the route that calls your AI model, on your bill.

This guide keeps it practical. What rate limiting stops. Where to add it. The exact setup for each common stack. And how to test it the way an attacker would.

QuestionAnswer
What does it stop?
Credential stuffing, scraping, and runaway API bills.
Where first?
Login, signup, password reset, and every paid API route.
Do AI builders add it?
Almost never. It is not a feature a user sees.
How hard is the fix?
One library per stack. An afternoon of work.
How do I test it?
Send a 50-request burst. Expect 429s early. Or use our free checker.
What does a check cost?
The scan is $0. The full audit report is $499, one time.

What API rate limiting stops

The mechanism is small. You pick a key — an IP, a user ID, or an API key. You pick a window, say ten requests per minute. Past the cap, the server answers 429 Too Many Requests instead of doing the work. That is all it is.

What it stops is much bigger than the mechanism.

One honest limit: rate limiting stops abuse by volume. It does not fix a broken auth check, an exposed key in your bundle, or an open database rule. Those need their own fixes.

Where to add it first

Not every route needs the same cap. Three groups are non-negotiable.

Logged-in traffic needs limits too. A stolen session token can be replayed just like an anonymous request. So apply limits per user and per token, not only at the front door.

The setup, stack by stack

You do not need a custom service for this. Every common stack has a library or a platform switch that does the job in an afternoon.

StackToolShape of the fix
Node / Expressexpress-rate-limitMiddleware per route. Tight window on auth, looser on the rest.
Next.js / Vercel@upstash/ratelimitEdge middleware keyed by IP or user ID. Runs before your code.
Python / FastAPIslowapiA decorator on each route. Keyed by IP or user.
SupabaseEdge Function + counterCount hits per user per window in a table. Reject past the cap.
CloudflareRate limiting rulesThrottle at the edge, before requests ever reach your server.

Node / Express

npm install express-rate-limit

const rateLimit = require("express-rate-limit");

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  limit: 10,                 // 10 tries per window
  standardHeaders: true,
});

app.use("/api/login", authLimiter);
app.use("/api/reset-password", authLimiter);

Next.js on Vercel

import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "1 m"),
});

export async function middleware(req) {
  const ip = req.headers.get("x-forwarded-for") ?? "unknown";
  const { success } = await ratelimit.limit(ip);
  if (!success) {
    return new Response("Too many requests", { status: 429 });
  }
}

Python / FastAPI

pip install slowapi

from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)

@app.post("/login")
@limiter.limit("10/minute")
def login(request: Request):
    ...

On Supabase, put the check inside an Edge Function: read a counter row for the user and the current window, reject with a 429 past the cap, and let a scheduled job clear old rows. And whatever the stack, a Cloudflare rule in front costs nothing and throttles floods before they touch your server.

The pattern never changes. Pick a key. Pick a window. Return 429 past the cap. Simple — but only if someone wires it in.

How to test it with a burst

Do not trust the middleware because you added it. Test it the way an attacker would.

  1. Pick one guarded endpoint. Start with login.
  2. Fire 50 requests in about 10 seconds. k6 makes this a one-file job.
  3. Watch the responses. You should see 429 long before request 50.
  4. Check that a different user or IP still gets through. Limits should block the flood, not the customer.
  5. Repeat for password reset and every paid API route.
// burst.js — run with: k6 run burst.js
import http from "k6/http";

export const options = {
  vus: 20,          // 20 virtual users
  duration: "10s",  // one short burst
};

export default function () {
  http.post("https://yourapp.com/api/login", {
    email: "test@example.com",
    password: "wrong",
  });
}

This is exactly how our scanner checks your app. We run a short concurrent load against your live URL, and when nothing throttles, the k6 engine reports it word for word:

Scanner finding · reliability

"No rate limiting detected under concurrent load."k6Scanner.js:170. One of the most common findings across the 100 AI-built apps we scanned.

No time to script it? Point our free API rate limit checker at one endpoint. It runs the burst for you and tells you if the route ever throttled.

Why AI-built apps ship without it

Tools like Lovable, Bolt, Cursor, and v0 aim at one thing: a working feature, fast. Rate limiting is not a feature a user sees. So nobody prompts for it, and the AI does not add it on its own.

The numbers back this up. Symbiotic Security scanned 1,072 AI-built apps and found 98% had at least one flaw, and 16% had critical issues. CMU's SusVibes study found 61% of AI-written code carried at least one security flaw. Our own average across 100 scanned apps sits at 42/100. The tools are good. The defaults are not — the same story our vibe coding security guide tells for every platform.

And missing limits rarely travel alone. The same builds tend to skip Row Level Security — the exact default behind CVE-2025-48757, which exposed 170+ AI-built apps — and ship without security headers. If your app failed the burst test, check those next. Our free RLS checker covers the database side.

One compliance note

An endpoint that lets anyone scrape user data at full speed is hard to defend as an "appropriate technical measure" under GDPR. And if your product has an AI feature and EU users, the EU AI Act's transparency duties (Article 50) apply from August 2, 2026, with fines up to €15 million or 3% of turnover for that tier. Unthrottled AI endpoints make both problems worse. Our Compliance Wing checks the full list.

What a check costs

The free scan is $0. It tests your live URL — rate limits under load, exposed keys, database rules, headers, monitoring — and returns a Launch Readiness Score out of 100 in about a minute. The full Launch Readiness Audit is $499 one time: a branded report, every finding ranked with time estimates, a benchmark against 200+ audited apps, and a senior review of each item. Ongoing monitoring starts at $149/mo. Start with the scan. It tells you if you need anything more.

FAQ

What is API rate limiting?

API rate limiting caps how many requests one user, IP, or key can send in a set window. Anything past the cap gets a 429 response. It is the simplest control that stops abuse by volume.

What does rate limiting stop?

Three things founders feel first: credential stuffing on login, scrapers pulling your data, and runaway bills on routes that call paid APIs. It does not fix broken auth or open database rules. Those need their own checks.

Where should I add rate limits first?

Login, signup, and password reset come first. Then any route that calls a paid API, sends email or SMS, or writes to your database. Public read routes can wait.

Do Lovable, Bolt, or Cursor add rate limiting for me?

No. AI builders ship the feature a user sees, and throttling is not one of those. Across 100 AI-built apps we scanned, the average readiness score was 42/100, and missing rate limits were one of the most common reasons.

How do I test my rate limits?

Fire a short burst at one endpoint. Use k6 or a simple loop to send 50 requests in 10 seconds. You should see 429 responses long before the burst ends. If every request lands, you have no limit.

Can a free scan catch missing rate limiting?

Yes. Our free scan tests your live URL under a short concurrent load and flags routes that never throttle. It takes about 60 seconds and needs no code access.

Does your login route throttle? Find out now.

Test one endpoint with the free rate limit checker, or scan your whole app. No code access. About 60 seconds.

Check an endpoint free

Rate limiting is one line item, but it is a good proxy for the rest of your build. If it is missing, the headers, the database rules, and the monitoring probably got the same treatment. Run the free scan and get the whole list at once.