P27 min read

API smoke checks functional QA should own

You do not need to become an SDET to protect integrations. A small set of API smoke checks anchored to user journeys catches a class of surprises before UI testing starts.

AI draftHuman oraclePASS / FAILobservables only

A surprising amount of UI testing time goes on discovering that an API is down. The tester opens the app, the list is empty, the spinner never stops, and some time later a developer confirms that the bookings service did not deploy properly. Nothing was learned about the product.

Functional testers often leave API testing to developers and SDETs on the grounds that it is code. I think a small part of it belongs to us. API smoke checks are a handful of requests that show the integrations behind the critical journeys are alive and behaving on this build, and a functional tester is the right owner because we know which journey each one holds up.

What an API smoke test is for

Functional QA owns one question here: if this API misbehaves, which user journey breaks? That mapping turns a technical check into a business-relevant one. “The token endpoint returns 500” is an engineering fact. “Nobody can sign in on this build” is a reason to stop testing and tell people.

A smoke check is shallow on purpose. It asks whether the service is deployed, reachable, configured for this environment and returning something the UI can use. It runs in a minute or two and tells me whether the build deserves an afternoon of journey testing or a message to the developers.

API callJourney that stopsWhat I do when it is red
AuthenticateEvery journeyStop. The build is not testable
Read the data a journey starts fromAnything that begins with a list or a searchHold those journeys and test what does not depend on them
Create or update the main entityThe journey that earns revenueOne defect, and the journey waits for the fix
Unhappy path returns a server errorRecovering from a mistakeRaise it. Journey testing continues

A green collection says the journey is possible on this build. Whether a person can complete it is still a question for a human on the real surface.

Which API checks to include

I keep the collection tiny: authenticate, then create, read and update the entities the UI depends on, plus one unhappy path that should fail gracefully. For a single journey that is usually about half a dozen requests.

I start from the journey, not from the API documentation, which lists everything. I watch what the product actually calls: the network tab in the browser for web, Charles Proxy for a mobile app. Swagger then gives me the shape of each request. The calls the journey cannot finish without are the candidates.

API smoke collection for a booking journey (illustrative)
  • 1. Sign in as the smoke user. Expect 200 and a token.
  • 2. List parking zones for the test city. Expect 200 and at least one zone with a tariff.
  • 3. Create a booking in that zone. Expect 201 and a booking id.
  • 4. Read the booking back by id. Expect the zone, vehicle and end time that were sent.
  • 5. Extend it by 30 minutes. Expect 200 and, on a fresh read, the new end time.
  • 6. Create a booking with no vehicle. Expect 400 or 422 and an error the app can display.
  • 7. Cancel the booking from step 3. Expect 200 or 204.

What to assert in each API check

A status code alone is a weak oracle. A 200 with an empty list, or a 201 whose body has no id, passes a status check and breaks the screen. For each request I assert three things at most: the status, the few fields the UI reads, and for anything written, a read-back showing it was stored. The unhappy path gets the same care: the expected 4xx and a message the app can display.

AI helps with the typing. I use Cursor or ChatGPT to draft the Bruno or Postman scaffolding: requests, variables and a first set of assertions. The oracles and the data are mine to confirm, for the reasons in AI in QA without fake confidence.

When and where to run API smoke checks

Run the smokes on the same builds you test in the UI, on the same environment, before the UI session starts and again after each deploy to it. A green mobile app on a broken API is still a broken product, and a green API on a different build says nothing about the one in your hand.

Bruno has its own command-line runner and Postman has Newman, so the same checks can also sit in the pipeline after a deploy.

Three details decide whether the collection survives. It has its own user and data, so it does not depend on what someone else left in a shared environment. It cleans up what it creates. And base URLs and credentials live in environment variables, never in the saved requests, so one collection runs against every environment and no secret ends up in the repository.

How to report a failed API smoke check

When a smoke fails, I write the defect in user language and link the trace. The title names who cannot do what, and on which build. Underneath go the request, the response, the timestamp, the environment and the correlation id if the response carries one. Engineering gets reproducibility and Product gets impact, which is the split I describe in Defects Product thanks you for.

I raise one defect, however many screens fail because of it, and say plainly whether the build is still testable.

The objection: API testing is the developers’ job

Much of it is, and I would not duplicate the unit and integration tests developers own. But those typically run in the pipeline against a freshly built service with its neighbours mocked. The smoke runs against the deployed environment, with its real configuration and whatever the other teams deployed overnight. A wrong base URL, an expired certificate, a missing configuration value, a permission never granted here: a test that runs before deployment cannot see any of them.

What goes wrong on our side is growth. Every incident tempts you to add a request, until the smoke is a suite that takes too long to run before a session and fails for reasons nobody investigates. I prune on one rule: a check stays only if I can name the journey that stops when it fails. Deeper API coverage is a different artefact with a different owner.

None of this needs an SDET. If you can read a request in the network tab and say what the screen needs from the response, you can own seven requests.

The goal is fast signal on the integrations your journeys cannot live without, not a large API suite. With it in place, UI testing starts on builds worth testing, an environment fault is reported as one clear defect in the first few minutes, and the hours that used to go on watching a spinner go on the product.

Questions I get asked

What is an API smoke test?

A small set of API requests run against a deployed build to confirm that the services a user journey depends on are up, reachable and returning usable responses. It is shallow by design: sign in, create, read and update the main entities, and one error case. Its job is to show quickly whether the build is worth deeper testing, not to cover the API.

How many API smoke tests should a collection have?

As few as will tell you the critical journeys are possible on this build. For one journey that is usually about half a dozen requests. If the collection takes more than a couple of minutes or contains checks nobody can tie to a journey, it has become a regression suite and should be pruned or handed to whoever owns deeper API coverage.

Do functional testers need to code to test APIs?

Very little. You need to read HTTP: methods, status codes, headers and JSON bodies. Tools such as Bruno and Postman handle sending the requests, and the assertions are a few short lines you can learn from examples. The harder and more valuable skill is knowing which fields the screen relies on and what a correct response means for the user.

Filed under API checks, automation and AI in QA. Terms: API smoke check, Smoke testing.