API testing tools: matching the tool to the kind of test
Exploratory testing, automated suites, contract testing, load testing and production checks need different tools. Which to use for each, and the tests most teams are missing.
On this page
Teams comparing API testing tools usually have one tool doing three jobs badly. A collection of saved requests used for exploration, pressed into service as a regression suite, and then asked to prove the API can handle load.
Those are three different activities with three different tools, and the mismatch is why API testing so often feels like maintenance rather than confidence. This page separates them, and names the category most teams are missing entirely.
What we'll cover
Five kinds of API test
Exploratory. A person poking at an endpoint to understand it. Interactive, throwaway, and the most common starting point.
Functional regression. An automated suite proving the API still does what it did. Runs in CI, blocks a bad merge.
Contract. Proving that a consumer and a provider still agree about the shape of their interaction, without running both together.
Load. Establishing what happens under volume and where it breaks.
Production checks. Continuously verifying the live API from outside, which catches what pre-deployment testing cannot.
Most teams do the first two, skip the third, do the fourth once before a launch and never again, and confuse the fifth with monitoring. The gaps are predictable and each has a specific cost.
Exploratory testing
Understanding an API, reproducing a bug, checking a response shape by hand.
The obvious options: Postman, Insomnia, Bruno, Hoppscotch, and curl or HTTPie for anyone who prefers a terminal. Bruno is worth knowing about for teams who want collections stored as files in the repository rather than in a vendor's cloud, which makes them reviewable like code.
What actually matters here: speed of iteration and how easily you can share a request with a colleague. Everything else is preference.
The trap: letting the exploratory collection become the test suite. Saved requests accumulate, somebody adds assertions, and eventually a collection of three hundred requests is being run in CI by a tool designed for interactive use. It is slow, it is hard to review, the assertions are inconsistent, and nobody can say what it actually covers.
The healthier boundary: exploratory collections are disposable. When something is worth keeping, it moves into the automated suite deliberately, with proper assertions.
Automated functional suites
The regression tests that run on every change.
Written in code, in the repository. Whatever test framework your language already uses, calling the API directly. This is the right answer for most teams and it is less exciting than buying a tool.
Why code rather than a visual tool: it reviews in a pull request, it versions with the API it tests, it runs anywhere, it can share setup and fixtures with your other tests, and nobody needs a licence.
What to assert, in order of value: the status code, the response shape, the specific values that matter, and the side effects. Most suites stop at the first two, which catches less than people assume.
The tests worth having, which most suites lack: the error paths. A suite that proves every endpoint works when given correct input is proving the easy half. What happens with a missing field, a malformed body, an expired token, an identifier that does not exist, or a value at the boundary is where APIs actually misbehave.
Keep them independent. Tests that depend on running in order, or on state left by an earlier test, fail mysteriously and get disabled.
Contract testing, the one people skip
The category most teams do not have and most teams need once they have more than one service.
The problem it solves: service A calls service B. Integration tests running both together are slow, flaky, and awkward to set up. Testing them separately means neither notices when B changes a field name that A depends on, until production.
How it works: the consumer declares what it expects — these fields, these types — and the provider verifies it still satisfies that expectation. Neither runs the other. Pact is the established option; schema-based approaches using OpenAPI comparisons cover a lighter version of the same idea.
The lighter version worth doing even if you skip the tooling: keep an OpenAPI specification, and add a CI check that fails when a change to it is breaking. Removing a field, making an optional field required, narrowing a type. That is a fraction of the setup of full contract testing and catches the most common cause of integration failures.
When you need it: more than one team, or more than one service, or any external consumer. Below that threshold it is ceremony; above it, it is what prevents an entire category of incident.
Load and performance
Establishing what happens under volume, and the category most often done once and then forgotten.
The tools: k6 for tests written in JavaScript and version-controlled, Locust for Python, Gatling and JMeter at the heavier end.
The distinction worth making: load testing asks whether it holds at expected volume; stress testing asks where it breaks. Both are useful and they answer different questions, and teams frequently run the first while believing they have learned the second.
What to measure: percentiles rather than averages, error rate under load, and what happens after the load stops. That last one is neglected and revealing — a service that recovers slowly has a queue somewhere, and you want to know that before a real traffic spike teaches you.
The realistic advice: run it before a launch and before any change to the data layer, rather than continuously. Continuous load testing is expensive and mostly re-proves what you already know. The exception is a smoke-level performance check in CI that catches an obvious regression.
The common mistake: load testing against an environment that does not resemble production. A test against a database with a thousand rows tells you nothing about behaviour against ten million.
Testing in production
Distinct from monitoring, and the category with the best return for the least effort.
What it is: running real requests against the live API on a schedule, with real authentication, asserting on the content of the response rather than the status code.
Why it catches what the other four cannot: it exercises the real configuration, real data, real network path, real certificates and real dependencies. A suite passing in CI proves the code is correct; this proves the deployed system works.
What to check: your most important flows end to end, a handful rather than everything, with assertions on actual content. A check asserting status === 200 is not testing, it is pinging.
The one nobody builds: a check for absence. An endpoint that normally serves a thousand requests an hour and now serves nine has a problem that no error-rate check will catch, because the nine are succeeding.
The connective tissue around all this — routing a failure to whoever owns the service, enriching it with what deployed recently, opening a ticket when it is not urgent enough to interrupt anyone — is ordinary automation rather than testing. On CodeWords you describe what should happen when a check fails and Cody, the automation builder, builds it, connects it to your monitoring and chat tools, and deploys it. Automations connect to more than 3,000 integrations. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
What a complete setup looks like
For a team with a production API and no dedicated QA function.
Exploratory: whichever client the team likes, with collections treated as disposable rather than as a suite.
Functional: tests in code, in the repository, running in CI, covering the happy path and the error paths, with the error paths taken as seriously as the happy ones.
Contract: an OpenAPI specification with a CI check for breaking changes. Full contract testing once you have multiple services or external consumers.
Load: before launches and before data-layer changes, against an environment resembling production.
Production: a handful of synthetic checks on your most important flows, with content assertions, plus an absence check on your busiest endpoint.
That covers the five categories and none of it requires a dedicated testing platform. The gap worth closing first, for most teams, is the error paths in the functional suite, because it is the cheapest and it catches the most.
The error-path tests worth writing first
Named specifically, because "test the error paths" is easy to agree with and hard to act on.
The missing required field. Send the request without it. You should get a clear 400 naming the field, not a 500 and a stack trace.
The wrong type. A string where a number belongs. This is where validation frequently turns out to be thinner than assumed.
The identifier that does not exist. Should be a 404 rather than a 500, and should not leak whether the record exists for a different account.
The expired or missing token. A 401 that distinguishes clearly from a 403, because clients need to know whether to refresh or to give up.
The value at the boundary. Zero, negative, the maximum, one past the maximum. Boundary behaviour is where quantity and pricing bugs live.
The record belonging to somebody else. The most important test on this list. Authenticated as one account, request another account's resource. This should fail, and it is the test least likely to exist.
Six tests per endpoint sounds like a lot until you notice they are nearly identical across endpoints and can share a helper. A day spent writing them for your most sensitive endpoints is the highest-return testing work available to most teams.
Frequently asked questions
Is Postman enough on its own?
For exploratory work, yes, and it is excellent at it. For a regression suite it is workable and generally worse than tests in code, which review in pull requests and version with the API. Using it for load testing is a mismatch.
Should API tests live with the API code?
Yes, wherever possible. They version together, so a change to the API and its tests arrives in one reviewable change, and nobody needs access to a separate tool to understand what is covered.
How much API test coverage is enough?
Coverage percentage is a poor measure here. More useful: every endpoint has at least one error-path test, every documented behaviour has an assertion, and the flows that would cost you money if broken have production checks. Those three are achievable and meaningful.
Do I need contract testing?
Not with a single service and a single consumer you control. Yes with multiple services, multiple teams, or external consumers. The lighter version — an OpenAPI spec plus a breaking-change check in CI — is worth doing well before the full version.
How often should I run load tests?
Before launches and before changes to the data layer, rather than continuously. A light performance check in CI catches obvious regressions; full load testing is expensive and mostly re-proves what you know.
What is the difference between production testing and monitoring?
Monitoring observes the traffic you already have. Production testing generates traffic to verify specific behaviour, which means it catches problems on paths nobody is currently using. They are complementary, and most teams have the first and believe it covers the second.
What is the single most valuable test most teams are missing?
An error-path test on the endpoints that handle money or customer data. Suites that only prove correct input produces correct output leave the entire failure surface untested, and that is where production incidents actually come from.