Stress Testing for RESTful API Endpoints Under Heavy Load

Stress test REST endpoints past expected load: ramp to 1,000 users in ten steps, read p95 and errors per endpoint, find the breaking point. Config and k6.


Push each REST endpoint until it breaks, on purpose

A load test checks that an API holds the traffic you expect. A stress test keeps going until it does not, and the value is in what breaks first: a connection pool, a rate limiter, a downstream service, or the process itself. This template ramps well past a normal peak in ten steps, reads response time and errors per endpoint at each step, and hands you the ceiling as a number.

Configuration

SettingValueWhy
Virtual users1,000, no think timeTen times a typical API’s steady concurrency; the point is to exceed capacity.
Duration15 minutesFive minutes of ramp, ten at the top so timeouts and retries have time to compound.
Ramp-up300 s in 10 steps100 users every 30 seconds; the step where errors appear is the answer.
Requests3 to 5 endpoints: cheap read, expensive read, one writeDifferent cost per endpoint means they fail at different levels; that order is the finding.
HeadersAuthorization, Content-Type, and a correlation idSend what real clients send; auth adds validation cost.
Think timeNoneAPI clients do not pause; a stress test should not either.

Run this templateOpens the cloud test form with these values filled in. Free plan runs it at the free user limit; sign in or create a free account first.

The button prefills users, duration and ramp-up. Add the endpoints with headers (a header preset for the token), set think time to zero, and start. Run it against staging first; at the top of the ramp it will take things down.

What to read in the results

  • Error onset per endpoint. Filter by request and find the step where each endpoint’s error rate leaves zero. The expensive read usually goes first; if the cheap read goes first, the limit is in front of the API (gateway, limiter, proxy).
  • p95 versus throughput. Throughput flattens before errors start. The step where requests per second stop rising while p95 keeps climbing is the real capacity; errors come one or two steps later.
  • Status codes in the Errors tab. 429 is a limiter; 502 and 504 are an upstream or a proxy timing out; connection errors are the process or the load balancer refusing sockets. Each points at a different fix.

Pass/fail thresholds for this template

ThresholdTargetWhat a breach means
p95 response time< 500 msThe API is queueing at this level; note the level.
Error rate< 1%The breaking point; the run is meant to reach it, so treat a FAIL as the measurement.
Throughput> 3x expected peakYou have less headroom than you thought.

For a stress test the thresholds document the ceiling rather than gate a deploy: rerun after fixes and read the Trend tab to see it move.

The same scenario as a k6 script

As a k6 script with no sleep and a mixed endpoint set. Replace the endpoints and the token with yours.

import http from 'k6/http';
import { check } from 'k6';

const steps = [];
for (let i = 1; i <= 10; i++) steps.push({ duration: '30s', target: i * 100 });
steps.push({ duration: '10m', target: 1000 });

export const options = {
  stages: steps,
  thresholds: { http_req_duration: ['p(95)<500'], http_req_failed: ['rate<0.01'] },
};

const BASE = 'https://api.example.com';
const H = { headers: { Authorization: `Bearer ${__ENV.LF_TOKEN}`, 'Content-Type': 'application/json' } };

export default function () {
  check(http.get(`${BASE}/health`, H), { 'health 200': (r) => r.status === 200 });
  check(http.get(`${BASE}/orders?limit=50&expand=items`, H), { 'orders 200': (r) => r.status === 200 });
  if (Math.random() < 0.2) check(http.post(`${BASE}/orders`, JSON.stringify({ sku: 'A1', qty: 1 }), H), { 'create 201': (r) => r.status === 201 });
}

When to run it

  • Before publishing rate limits or SLAs so the numbers you promise are numbers you measured.
  • After any change to pools, timeouts or retries retries in particular can turn a slow endpoint into an outage.
  • Quarterly the ceiling drifts as data grows.

FAQ on REST API stress testing

What is the difference from the load test template?

Intent. A load test confirms expected traffic passes; a stress test exceeds it deliberately to find the ceiling and the failure mode. Same tool, different target and no think time.

Will this hurt production?

Yes at the top of the ramp; that is the design. Run it on staging, or on production only with a lower target and someone watching who can stop it.

Errors appear at 300 users but p95 was fine at 200. Is the ceiling 200 or 300?

Between them. Rerun with a finer ramp (for example 50 users per step from 200 to 400) to narrow it, or read the throughput plateau, which usually sits a step before the errors.

How do I test with many different API keys?

Use the k6 script: load the keys with SharedArray from a CSV and pick one per virtual user, so each user presents its own key and per-key rate limits behave like production. The cloud test form sends one header set for all users.

How fast is your website?

Elevate its speed and SEO seamlessly with our Free Speed Test.

Outgrown your testing tools?

Load test websites and APIs from 25+ cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.Start for free
jmeter cloud load testing tool

Free Website Speed Test

Analyze your website's load speed and improve its performance with our free page speed checker.

×