All posts
API Testing

API Negative Testing: 20 Test Cases Beyond the Happy Path

A concrete negative testing matrix for malformed input, boundaries, authentication, authorization, and unintended side effects.

API Negative Testing: 20 Test Cases Beyond the Happy Path illustration
API Test Lab9 min read

API negative testing sends invalid, incomplete, or unauthorized requests and checks that the API fails predictably without exposing data or performing unintended work. Run these cases against an owned demo API or an isolated test environment. The expected response must come from the API contract: HTTP defines status semantics, but it does not prescribe every validation rule or error body.

Use an owned demo endpoint

Assume a test service documents `POST /v1/orders` with JSON fields `customer_id` (string), `quantity` (integer from 1 to 20), and `sku` (string), and `GET /v1/orders/{id}` requires an authenticated test user. The host below is reserved for examples; replace it only with a service you own or may test.

POST /v1/orders HTTP/1.1
Host: api.example.test
Content-Type: application/json
Authorization: Bearer TEST_TOKEN

{"customer_id":"cust_demo","sku":"sku_basic","quantity":1}

For every failed create, query the test database or a safe listing endpoint afterward and confirm no order was created unless the contract explicitly defines partial acceptance.

Twenty negative cases

#InputExpected behaviorReason
1Omit `customer_id`Validation error per contract; no orderRequired field enforcement
2Set `customer_id` to `null`Reject or handle only if nullable by schemaDistinguish null from missing
3Set `quantity` to `"one"`Reject type mismatchPrevent coercion surprises
4Set `quantity` to `1.5`Reject non-integer quantityEnforce numeric shape
5Send malformed JSON such as `{"sku":`Client error, commonly 400Parser failure should be controlled
6Set quantity to `0`Reject below minimumLower boundary
7Set quantity to `21`Reject above maximumUpper boundary
8Set quantity to a huge integerReject safely or report range validationOverflow and boundary handling
9Set `sku` to an empty stringReject if non-empty is requiredEmpty is not a useful identifier
10Set `sku` to an extremely long stringReject at documented length limitResource and storage limits
11Send a body larger than the documented request limitReject, commonly 413 where applicableBound memory and parser work
12Send valid JSON as `text/plain`Reject or explicitly support it per contractContent type handling
13Send unsupported `Content-Type: application/xml`Reject, commonly 415Unsupported media type
14Omit the `Content-Type` headerReject or apply documented defaultAvoid ambiguous parsing
15Omit the Authorization headerAuthentication failure, commonly 401Verify credentials are required
16Send an invalid or expired test tokenAuthentication failure per contractReject unusable credentials
17Use a valid user token with no order-write permissionDeny per policy, commonly 403Authorization is separate from authentication
18Read another test user's order IDDeny or conceal existence per contractPrevent object-level access leaks
19Send an unsupported HTTP method to the routeReject, commonly 405 with `Allow` where definedMethod behavior is explicit
20Repeat a malformed create after a simulated client timeoutStill no unintended duplicate orderFailure and retry safety

These status examples are conventions, not universal promises for every API. For example, an API may return 422 for schema validation, or 404 rather than 403 to hide a resource. RFC 9110 defines meanings for statuses such as 401, 403, 405, 413, and 415; your API contract determines which applies to a particular failure.

Send a few cases with curl

Missing field:

curl -i https://api.example.test/v1/orders \
  -H 'Authorization: Bearer TEST_TOKEN' \
  -H 'Content-Type: application/json' \
  --data '{"sku":"sku_basic","quantity":1}'

Wrong type:

curl -i https://api.example.test/v1/orders \
  -H 'Authorization: Bearer TEST_TOKEN' \
  -H 'Content-Type: application/json' \
  --data '{"customer_id":"cust_demo","sku":"sku_basic","quantity":"one"}'

Unauthorized resource access:

curl -i https://api.example.test/v1/orders/order_owned_by_other_test_user \
  -H 'Authorization: Bearer USER_A_TEST_TOKEN'

Use only disposable records and test credentials. Do not probe IDs or payload limits on a third-party service without written authorization.

Assert failure behavior, not just a status

For each case, verify the error schema, content type, safe message, and any request or trace ID. Check that stack traces, SQL details, secrets, and protected fields are absent. Then check state: no order, payment, email, inventory reservation, or downstream job should exist unless the contract says the operation was accepted. A 4xx response does not prove that no side effect occurred.

If a failure may happen after partial processing, use an idempotency key or a cleanup path for the fixture. Keep mutation tests isolated from production and make repeated execution safe.

Release checklist

  • [ ] Map each required field, type, range, and content type to at least one negative case.
  • [ ] Include missing, null, malformed, boundary, and oversized values.
  • [ ] Test missing, invalid, expired, and under-scoped credentials.
  • [ ] Test access to another user's resource using controlled test identities.
  • [ ] Assert error body and headers against the documented schema.
  • [ ] Verify no unintended writes, messages, charges, or jobs occurred.
  • [ ] Confirm logs redact credentials and sensitive payload values.
  • [ ] Repeat cases safely and record the contract version tested.

See how to test REST APIs, 401 vs 403 errors, and API authentication testing for request and access-control foundations.

References

Use API Test Lab to send your documented negative requests and inspect responses while keeping the target environment clearly identified.

Share

Start testing your APIs

Try API Test Lab free. No credit card required.

Start free

More from the blog

Read 3 related articles from our latest posts.