advanced·12 min read·Updated Oct 24, 2026

API Performance Testing Best Practices: Workloads, Payloads and Reports

Most load tests answer the wrong question precisely. Learn the practices that make performance results trustworthy, what payload does to latency, an open-source k6 baseline, and what a good report contains.

This is lesson 7.6 of API Testing in CI/CD, Regression and Performance. Lesson 7.5 checked that the API still does what it did. This one checks that it still does it fast enough when many clients call at once. Lesson 9.13 walks through the product's performance designer screen by screen; this lesson is about doing performance testing well, with any tool.

What are the API performance testing best practices?

API performance testing best practices come down to one idea: a load test is only as good as the question it asks. Decide the targets before you run anything, send traffic that looks like your real clients (their mix, their payloads, their pacing), judge percentiles on the steady part of the run, and make sure your own load generator isn't the bottleneck. Do that, and the result is a decision. Skip it, and you get a precise answer to the wrong question.

Ten practices that make results trustworthy

  1. Write the targets first. "p95 under 300 ms and errors at or below 1 percent at 200 requests a second" is a test. "See how fast it is" is not.
  2. Pick the question, then the test kind. Load asks whether it holds at expected traffic; stress, where it breaks; spike, whether it survives a burst and recovers; soak, whether it degrades over hours.
  3. Model the workload, not one endpoint. Real clients browse more than they buy. A mix such as 80 percent reads and 20 percent writes finds contention a single-endpoint test never will.
  4. Use realistic payloads and data. Vary IDs and bodies; a test that reads the same cached record a million times measures the cache.
  5. Add think time. Real users pause between calls. Without pacing, 50 virtual users behave like 500.
  6. Choose the right load model. Fixed users wait for each answer, so a slowing API quietly gets fewer requests. A fixed arrival rate keeps sending, which is what a spike or stress test needs.
  7. Judge the steady stage only. Exclude the ramp-up and ramp-down; they mix warm-up effects into your percentiles.
  8. Read percentiles, never averages alone. An average of 120 ms can hide a p99 of 4 seconds. Report p50, p95 and p99.
  9. Check correctness under load. A fast 200 with an empty body is a failure. Keep some assertions on the response while the load runs.
  10. Watch the generator. If the machine sending load runs out of CPU, latency rises on its side, not the API's. Treat that run as inconclusive.

And one practice about the environment: test something production-like that you own. Never point a load test at someone else's system, and that includes the shared public sandbox beyond a few gentle users.

What is payload in API testing?

The payload is the data in the body of a request or a response. In POST /api/v1/products, the payload is the JSON of the new product; in a search, it's the list that comes back.

POST/api/v1/products
A request payload: the JSON body the API must parse, validate and store.
curl -X POST 'https://demo.totalshiftleft.ai/api/v1/products' \
  -H 'Content-Type: application/json' \
  -d '{"name":"USB-C Hub","price":34.5,"stock":20,"category":"electronics"}'

Payload size changes the numbers in three places: the network, the parsing and validation, and the database write or read behind it. The order below embeds its user and its product, so its response is about two and a half times the size of the bare order:

GET/api/v1/orders/dddddddd-dddd-dddd-dddd-dddddddddddd?expand=user,product
A bigger response payload: the order with its user and product embedded.
curl -X GET 'https://demo.totalshiftleft.ai/api/v1/orders/dddddddd-dddd-dddd-dddd-dddddddddddd?expand=user,product'

So a performance test should use the payloads your clients really send and request. If mobile clients ask for ?expand=user,product on every order, test that, not the slim version. If uploads range from 1 KB to 5 MB, test both ends. A useful pattern is a data set of real-shaped bodies the test reads from, row by row, rather than one hard-coded body.

API load testing open source: a k6 baseline

Open-source tools are a good way to set a baseline you can rerun anywhere. k6, JMeter, Gatling, Locust and Artillery all load test HTTP APIs. Here is a gentle k6 script for the sandbox: five users, a short hold, and the same two targets you would give any tool.

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

export const options = {
  stages: [
    { duration: '20s', target: 5 },  // ramp up
    { duration: '1m', target: 5 },   // hold
    { duration: '10s', target: 0 },  // ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<800'],
    http_req_failed: ['rate<0.01'],
  },
};

export default function () {
  const res = http.get('https://demo.totalshiftleft.ai/api/v1/products');
  check(res, { 'status is 200': (r) => r.status === 200 });
  sleep(1); // think time
}

Run it with k6 run baseline.js. Two things to notice. k6 evaluates these thresholds over the whole run, ramps included, unless you scope them with tags. And the script is a second copy of your test: the URL, the check and any auth live here as well as in your functional suite, and the two drift apart over time.

An API performance testing report sample

A report should let someone who wasn't there make a decision. Here is the shape of one, with illustrative figures of the kind a gentle run against the public sandbox produces; yours will differ:

SectionSample content
VerdictPass: both targets met during the 60-second hold
Targetsp95 latency under 800 ms; error rate 1 percent or less, during the hold
Load delivered5 virtual users; about 5 requests a second; no requests left unsent
Latency (hold only)p50 30 ms · p95 40 ms · p99 60 ms · max 120 ms
Errors0 of about 300 requests
ChecksStatus 200 on every request; body checks on a sample
ConfigurationEnvironment, test kind, stages, think time, data set, tool version

Two habits make a report comparable. Pin a baseline run and compare each new run with it, and don't call a small difference a regression without a test for noise: per-interval latency varies from run to run even when nothing changed.

In Shift-Left API: the Performance testing add-on

In Shift-Left API, performance testing is the Performance testing add-on, a paid add-on with three packages: Starter (100 virtual users, 15-minute runs, no load agents), Team (500 users, 60 minutes, 2 agents) and Scale (2,000 users per load generator, 12-hour runs, any number of agents). The 15-day trial includes it with the Scale limits. A performance test is built from the tests you already have, so there is no second script: the request, its auth profile, its checks and its environment come from the functional test.

  1. Load. In Performance, click New performance test and pick Load. Add your read test for GET /api/v1/products as the step, set five expected users and a 60-second hold, and keep the default targets: p95 under 800 ms and errors at 1 percent or less, during the hold.
  2. Dry run. Click Run a dry run. It builds the exact run and sends nothing: each step with its check, the estimated duration and the number of requests.
  3. Run and read. Save and run. The report leads with a verdict (Pass, Fail or Inconclusive), then the figures behind it. Only the hold is judged.
  4. Spike. Make a second test of kind Spike from the same step. It holds a low arrival rate, bursts to twice the base rate for a minute, then drops back. Its analysis reads the p95 before the spike, the worst p95 and error rate during it, and how long the API took to recover.
  5. Compare. Pin a run as the baseline. Later runs are compared with it using a statistical test on the per-interval p95, plus a minimum 5 percent move, so noise isn't reported as a regression.

The rules from the best-practice list are built in: percentiles come from merged histograms and are never averaged, a run with 1 percent or more of its requests never sent cannot pass, and a saturated load generator makes the verdict Inconclusive rather than blaming your API. Reports export as HTML, JSON, JUnit and CSV.

Know the limits before you plan. The engine sends HTTP/1.1, not HTTP/2. It load-tests REST, SOAP, GraphQL and JSON-RPC tests, not WebSocket-RPC, MCP or streaming endpoints. Extra load comes from load agents you run yourself, on Windows or macOS, not from cloud regions. There is no ready-made CI step for load runs: a pipeline starts one through the REST API with an API key and reads its JUnit file. And a production environment stays locked unless an administrator allows load on it and the person starting the run types its name. The API load testing page has the full feature list.

Try it yourself

On a trial, add a read test for GET /api/v1/products from the sandbox spec. In Performance, create a Load test with that test as its only step, five expected users and a 60-second hold, and click Run a dry run. Check what it would send before you send it.

Recap

  • API performance testing best practices: targets first, a realistic workload and pacing, the steady stage judged on percentiles, and a generator you've checked.
  • What is payload in API testing: the body data each call carries; test with the payload sizes your clients really use.
  • An API performance testing report sample leads with a verdict, then targets, delivered load, percentiles and errors; API load testing open source tools like k6 make a good, portable baseline.

For metrics, test types and a k6 and JMeter worked example, read API performance testing: how to load test an API. Next, in lesson 7.7, you keep watching the API after release.

Hands-on lab

Try it: With a trial, which includes the Performance testing add-on, add a read test for GET /api/v1/products, create a Load performance test with it as the only step, five expected users and a 60-second hold, then run a dry run.

Enter your email to open the lab steps. One unlock opens every lab in the learning center.

No spam. Protected by reCAPTCHA — Google Privacy & Terms.

Frequently asked questions

What is payload in API testing?+

The payload is the data carried in the body of a request or a response, such as the JSON of a new product or the list a search returns. In performance testing it matters because larger payloads take longer to send, parse and serialise, so a load test with tiny bodies can report latency your real clients will never see.

What should an API performance testing report sample include?+

A verdict first, then the targets it was judged against, the load that was actually delivered, latency percentiles (p50, p95, p99) for the steady stage, the error rate with the errors grouped by cause, and the test's configuration so someone can run it again. Averages alone are not enough.

Which API load testing open source tools are worth knowing?+

k6 (tests in JavaScript), Apache JMeter (a GUI and XML test plans), Gatling (Scala, Java or Kotlin), Locust (Python) and Artillery (YAML plus JavaScript) are the common ones. All can load test HTTP APIs; they differ in how you write tests and how they report.

Related lessons

Read more on the blog