ChaosQA · Guides

REST API test cases: a checklist with examples

Updated October 30, 2026

An API has no form in front of it to stop bad input, so you test it with requests a polite client would never send, and you read the whole response: the status code and the headers count as much as the body. This checklist works through one small endpoint for booking meeting rooms, but most of it carries over to any JSON API.

The example endpoint

POST /bookings takes {"room", "date", "start", "end", "people"} and creates a booking. Its documented rules: people is a whole number from 1 to 10, the date is from today up to 60 days ahead, times are on the hour or half past between 09:00 and 18:00, and bookings of one room must not overlap. Every request carries a bearer token, and each user sees only their own bookings. Swap in the numbers from your own API's reference.

Status codes and headers on the happy path

Start with requests that should work, and check more than "it returned 2xx".

RequestExpectedWhat to look at
POST /bookings, valid body201 CreatedA Location header; then send a GET to that exact URL and expect 200
GET /bookings/{id}200The fields you sent come back unchanged, plus the server's own (id, owner, created_at)
PATCH /bookings/{id}, one field200Only that field changed
DELETE /bookings/{id}204An empty body; a GET afterwards gets 404
The same DELETE againUsually 404Whatever the reference says, and the same answer as for an id that never existed
PUT /bookings (a method the endpoint lacks)405An Allow header that lists the methods that do work

Following the Location header is worth the extra request. A typo in how the server builds that URL (a singular instead of a plural, a missing prefix) passes every test that only reads the body.

Validation boundaries

Each rule has values just inside and just outside it. Expect the inside value to be accepted and the outside one to get a 4xx with an error that names the field.

FieldValues to sendExpected
people1 and 10Accepted
people0, 11, -1Rejected
people"3" (a string), 2.5, null, the field left outRejected, unless the reference says strings are converted
dateToday and today + 60 daysAccepted
dateYesterday, today + 61 daysRejected
dateA day that does not exist inside the window, such as November 31Rejected: the format is right, the day is not
start / end09:00–10:00, 17:00–18:00Accepted
start / end08:30 start, 18:30 end, 10:15 startRejected
start / endend equal to start, end before startRejected

Opening hours have two edges. A server that checks only the start against closing time will take a booking that starts at 17:30 and ends at 19:30, so send one that starts inside the hours and ends outside them. Impossible dates need care too: a regular expression for YYYY-MM-DD accepts November 31, and only a real calendar check rejects it. Pick the impossible date inside the 60-day window, or the server may reject it as too far ahead and the calendar check never runs.

Broken and unexpected requests

Overlapping bookings

Business rules that compare a new record with existing ones break in more ways than single-field checks. Take an existing booking for room r1 from 10:00 to 11:00 and try these, each in the same room and on the same date:

New bookingExpectedWhy it is worth a test
09:00–10:00AcceptedBack to back, ends when the other starts
11:00–12:00AcceptedBack to back, starts when the other ends
10:30–11:30409 ConflictStarts inside the existing booking
09:30–10:30409 ConflictStarts before it and runs into it
10:00–10:30409 ConflictLies inside it
09:00–12:00409 ConflictCovers it completely
10:00–11:00 in another roomAcceptedThe check must be per room

Two bookings overlap when the new start is before the old end and the new end is after the old start. Writing <= instead of < rejects back-to-back bookings. Checking only whether the new start falls inside an old booking misses the "starts before" and "covers" rows, which is why the table has both.

Then repeat the rule on the other paths. A PATCH that moves a booking onto a taken slot should get the same 409, and a PATCH that only extends a booking into its own time should not conflict with itself. After a DELETE, the freed slot should be bookable again at once; a server that marks bookings as deleted but forgets to skip them in the overlap check will keep the slot blocked. If there is a limit per user, such as three bookings a day, make the third and then the fourth.

Two users, one API

You need two accounts or tokens for this part. Create a booking as user A and note its id, then switch to user B's token:

A server that checks that you are logged in, but not that the record is yours, has what the OWASP API Security Top 10 calls broken object level authorization, first on its list. Try it on every endpoint that takes an id, because each one runs its own query and can miss the owner check on its own.

Lists and pagination

Create five bookings and walk the list with a small page size, such as ?limit=2&page=1, then pages 2 and 3. Every booking should appear exactly once across the pages, in the documented order, and the last page should hold one item. An off-by-one in the offset shows up as an item repeated at the start of page 2 or skipped between pages. Also send page=0, a limit one above the documented maximum, and a filter that matches nothing (expect an empty list with a total of 0, not a 404).

Parallel requests

A server that first checks for a clash and then inserts can let two requests through if they arrive together. Send the same booking twice at once:

DATE=2026-12-01   # any date inside the allowed window
for i in 1 2; do
  curl -s -o /dev/null -w "%{http_code}\n" -X POST https://api.example.com/bookings \
    -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
    -d "{\"room\":\"r1\",\"date\":\"$DATE\",\"start\":\"14:00\",\"end\":\"15:00\",\"people\":3}" &
done; wait

Expected: one 201 and one 409. Two 201s mean a double booking. Run it a few times, since a race does not show up on every attempt. The double submit guide covers the same problem from the side of a form.

Try it on a live API. RoomBox is a practice booking API with two users and a console on the page. Bugs of the kinds above are planted on its server, a different set in each session.
Open the practice API

More guides: double submit · what the server trusts · all guides