API Testing Practice: Free REST API with Auth and 141 Scenarios

Practise API testing on a live REST API: hardcoded GET data, temporary objects you can create, update and delete, and four authentication types, with 141 ready-made test scenarios.

Advertisement

Free practice REST API · no sign-up · CORS enabled

Practise API testing on a real REST API

Pick an endpoint, press Send request and compare your response with the expected one. GET data is hardcoded, objects you create disappear on their own, and four auth types are ready to test.

Base URLhttps://sqatools.in/wp-json/sqa-api/v1
GET https://sqatools.in/wp-json/sqa-api/v1/users/1
200 OK
{
  "data": {
    "id": 1,
    "name": "Asha Verma",
    "username": "asha",
    "email": "asha@example.com",
    "role": "admin",
    "city": "Pune",
    "age": 34,
    "active": true,
    "created_at": "2025-01-15T09:30:00Z"
  }
}
  1. Pick an endpoint from the list below
  2. Press Send request; auth is added for you
  3. Compare your response with the expected one

Practice only: anything you create is visible to other learners until it expires. Never send real names, emails, passwords or other personal data.

Endpoints

Open endpoints. Hardcoded GET data never changes, so the same request always returns the same response.

Full endpoint reference (26 routes) and error format
MethodPathAuthWhat it does
GET/healthnoneService status and server time
GET/usersnoneUsers list: page, per_page, role, city, active, q, sort, order
GET/users/{id}noneOne user (Accept: application/xml for XML)
GET/users/{id}/ordersnoneOrders of one user (nested resource)
GET/productsnoneProducts: category, in_stock, min_price, max_price, sort, order
GET/products/{id}noneOne product with ETag (send If-None-Match for 304)
GET/ordersnoneOrders: status, user_id
GET/orders/{id}noneOne order with nested items, summary and shipping
ANY/status/{code}noneResponds with any status code from 200 to 599
GET/delay/{seconds}noneWaits 0-10 seconds before responding
ANY/echononeEchoes method, query, headers and body
ANY/redirectnoneRedirects to /echo (status=301, 302, 303, 307 or 308)
GET/rate-limitnone5 requests per minute, then 429 with Retry-After
POST/validate/usernoneValidates a user payload; 422 lists every field error
GET/schema/{name}noneJSON Schema: user, product, order, object, error, token
GETPOST/objectsnoneTemporary objects: list, create
GETPUTPATCHDELETE/objects/{id}noneTemporary object: read, replace or create, update, delete
GET/basic/profilebasicProfile behind HTTP Basic auth
GETPOSTPUTPATCHDELETE/basic/objects[/{id}]basicTemporary objects behind Basic auth
GET/apikey/profileapikeyProfile behind an API key
GETPOSTPUTPATCHDELETE/apikey/objects[/{id}]apikeyTemporary objects behind an API key
POST/auth/loginnoneGet a Bearer JWT and refresh token
POST/auth/refreshnoneSwap a refresh token for new tokens
POST/auth/logoutbearerRevoke the access token
GET/auth/mebearerWho the token belongs to
GETPOSTPUTPATCHDELETE/token/objects[/{id}]bearerTemporary objects; viewer role may only read

Every error has the same shape, which makes it easy to assert:

{"error": {"status": 422, "code": "validation_failed", "message": "1 field(s) failed validation.",
           "details": [{"field": "age", "message": "age is required: a whole number from 18 to 100 (not a string)."}]}}

How temporary objects work

Create

POST /objects gives a server id and 201 with a Location header. PUT /objects/your-id creates or replaces with your own id.

Fields

name (required, 1–100 characters), data (any JSON up to 5 KB), ttl (10–1800 seconds, default 600). Other fields give 422.

Expiry

Each object disappears after its ttl; then GET returns 404. DELETE returns 204, a second DELETE 404.

Versions

Every change adds 1 to version. Send the ETag in If-Match (else 412) or If-None-Match (304).

141 API testing scenarios

A ready-made test plan: functional, negative, boundary, auth, roles, headers, caching, performance and rate-limit cases. Press Try to run one in the console below (setup such as creating an object or waiting for expiry runs for you), or Run all to check them all.

Custom request consoleBuild any request yourself, or press Try on a scenario.
…/sqa-api/v1
Add auth:

The response appears here.

  1. Read hardcoded data (GET)
  2. Pagination, filtering, sorting and search
  3. HTTP methods, status codes and redirects
  4. Headers, content types and caching
  5. Request body validation (negative testing)
  6. Temporary objects: create, read, update, delete
  7. Basic authentication
  8. API key authentication
  9. Token (Bearer JWT) authentication
  10. Authorization (roles and permissions)
  11. Performance, timeouts and rate limits

Read hardcoded data (GET) (17)

#ScenarioRequestExpected
1Health check returns ok
Smoke test: the service is up.
GET /health200
2List all users
Default list with pagination metadata and headers.
GET /users200
3Get a single user by id
Verify exact field values.
GET /users/1200
4User that does not exist
Negative test: resource not found.
GET /users/999404
5Non-numeric user id
Path parameter type validation.
GET /users/abc400
6Zero as user id
Boundary value for an id.
GET /users/0400
7Nested resource: orders of a user
Parent/child resources.
GET /users/1/orders200
8Order with nested items and totals
Check nested objects, arrays and calculated values.
GET /orders/5001200
9Product has an ETag header
Response header assertions.
GET /products/101200
10Filter products by category
Query parameter filtering.
GET /products?category=books200
11Filter products by price range
Combined range filters.
GET /products?min_price=1000&max_price=5000200
12Invalid price range (min > max)
Cross-field validation of query parameters.
GET /products?min_price=5000&max_price=100400
13Unknown category value
Enum validation.
GET /products?category=toys400
14Filter orders by status
Filter on a status field.
GET /orders?status=delivered200
15JSON Schema for a user
Fetch a schema for contract testing.
GET /schema/user200
16Unknown schema name
Negative test on a lookup.
GET /schema/invoice404
17List every endpoint
API discovery (JSON escapes / as \/).
GET /endpoints200

Pagination, filtering, sorting and search (17)

#ScenarioRequestExpected
18Second page of users
Page 2 starts at the 6th record.
GET /users?page=2&per_page=5200
19Last page has the remaining records
Last-page boundary.
GET /users?page=3&per_page=5200
20Page beyond the last page
Out-of-range page returns an empty list, not an error.
GET /users?page=10200
21per_page above the maximum (51)
Upper boundary of page size.
GET /users?per_page=51400
22per_page at the maximum (50)
Boundary value that must pass.
GET /users?per_page=50200
23Page number zero
Lower boundary of page.
GET /users?page=0400
24Link header points to the next page
Hypermedia pagination headers.
GET /users?per_page=5200
25Filter users by role
Single filter.
GET /users?role=admin200
26City filter is case-insensitive
Case handling in filters.
GET /users?city=pune200
27Boolean filter active=false
Boolean query parameters.
GET /users?active=false200
28Invalid boolean value
Boolean validation.
GET /users?active=maybe400
29Combine two filters
AND logic between filters.
GET /users?role=admin&city=Chennai200
30Search by text
Free-text search.
GET /users?q=gupta200
31Search with no match
Empty result set.
GET /users?q=zzz200
32Sort by age descending
Sorting order.
GET /users?sort=age&order=desc&per_page=1200
33Sort by an unknown field
Whitelisted sort fields.
GET /users?sort=salary400
34Invalid sort order
Enum validation for order.
GET /users?order=up400

HTTP methods, status codes and redirects (18)

#ScenarioRequestExpected
35POST on a read-only resource
405 with an Allow header.
POST /users405
36DELETE on a read-only resource
Unsupported method.
DELETE /products/101405
37HEAD returns headers only
HEAD has the same headers as GET and no body.
HEAD /users/1200
38OPTIONS lists allowed methods
Pre-flight / discovery.
OPTIONS /users200
39Status code 201
Client handles 201 Created.
GET /status/201201
40Status code 400
Client handles 400 Bad Request.
GET /status/400400
41Status code 401
Client handles 401 Unauthorized.
GET /status/401401
42Status code 403
Client handles 403 Forbidden.
GET /status/403403
43Status code 404
Client handles 404 Not Found.
GET /status/404404
44Status code 409
Client handles 409 Conflict.
GET /status/409409
45Status code 500
Client handles 500 Internal Server Error.
GET /status/500500
46Status 503 with Retry-After
Back-off header on service unavailable.
GET /status/503503
47Status 204 has an empty body
No Content.
GET /status/204204
48Invalid status code
Validation of a path parameter.
GET /status/700400
49Redirect without following it
Assert the redirect itself.
GET /redirect302
50Follow a redirect
Client follows to the final response.
GET /redirect200
51307 keeps the POST method
307/308 preserve method and body.
POST /redirect?status=307200
52303 changes POST to GET
303 See Other always switches to GET.
POST /redirect?status=303200

Headers, content types and caching (7)

#ScenarioRequestExpected
53Ask for XML with the Accept header
Content negotiation.
GET /users/1200
54Unsupported Accept type
406 Not Acceptable.
GET /users/1406
55Custom request header is received
Verify headers and query reach the server.
GET /echo?source=test200
56Form-encoded body
Non-JSON bodies.
POST /echo200
57JSON body is echoed back
Round-trip a JSON payload.
PUT /echo200
58Conditional GET returns 304
ETag caching saves bandwidth.
GET /products/101304
59Responses are not cached
Cache-Control header check.
GET /health200

Request body validation (negative testing) (18)

#ScenarioRequestExpected
60Valid payload passes
Happy path.
POST /validate/user200
61Empty object: every required field fails
All errors are reported at once.
POST /validate/user422
62Wrong data type (age as text)
Type checking.
POST /validate/user422
63Boundary: age 17
Boundary value analysis (18 to 100).
POST /validate/user422
64Boundary: age 18
Boundary value analysis (18 to 100).
POST /validate/user200
65Boundary: age 100
Boundary value analysis (18 to 100).
POST /validate/user200
66Boundary: age 101
Boundary value analysis (18 to 100).
POST /validate/user422
67Invalid email format
Format validation.
POST /validate/user422
68Value outside the enum
Enum validation.
POST /validate/user422
69Unknown extra field
Strict schema rejects extra fields.
POST /validate/user422
70Name too short (1 character)
Minimum length.
POST /validate/user422
71Name too long (51 characters)
Maximum length.
POST /validate/user422
72Invalid phone number
Pattern validation.
POST /validate/user422
73Malformed JSON
Syntax errors give 400, not 500.
POST /validate/user400
74Wrong Content-Type
415 Unsupported Media Type.
POST /validate/user415
75Empty body
Missing payload.
POST /validate/user400
76JSON array instead of an object
Top-level type check.
POST /validate/user400
77Payload larger than 10 KB
413 Payload Too Large.
POST /objects413

Temporary objects: create, read, update, delete (24)

#ScenarioRequestExpected
78Create an object (POST)
201 Created with a Location header.
POST /objects201
79Create without the required name
Required field.
POST /objects422
80ttl below the minimum (5 seconds)
Boundary: minimum 10 seconds.
POST /objects422
81ttl above the maximum (2000 seconds)
Boundary: maximum 1800 seconds.
POST /objects422
82Client cannot choose the id on POST
Server-generated ids.
POST /objects422
83Read the created object
GET after POST.
GET /objects/{id}200
84List objects
The new object appears in the list.
GET /objects200
85Replace with PUT
Full update increments the version.
PUT /objects/{id}200
86Create with PUT and your own id
PUT to a new id creates it (upsert).
PUT /objects/my-{rand}201
87PUT without the required name
PUT needs the full representation.
PUT /objects/{id}422
88Body id differs from URL id
Consistency check.
PUT /objects/{id}422
89Partial update with PATCH
PATCH merges into existing data.
PATCH /objects/{id}200
90PATCH removes a key set to null
JSON merge patch semantics.
PATCH /objects/{id}200
91PATCH with an empty object
Nothing to update.
PATCH /objects/{id}422
92PATCH an object that does not exist
Update a missing resource.
PATCH /objects/missing-{rand}404
93Delete an object
204 No Content.
DELETE /objects/{id}204
94Read a deleted object
The object is gone after DELETE.
GET /objects/{id}404
95Delete the same object twice
Second DELETE returns 404.
DELETE /objects/{id}404
96Id too short
Path parameter format.
GET /objects/ab400
97Optimistic locking: stale If-Match
Prevent lost updates.
PUT /objects/{id}412
98Optimistic locking: current If-Match
Matching version is accepted.
PUT /objects/{id}200
99Conditional GET on an object
304 when unchanged.
GET /objects/{id}304
100Object vanishes after its ttl
Data expiry: created with ttl 10, read after 12 seconds.
GET /objects/{id}404
101Text with SQL and HTML is stored as plain text
Injection strings are data, never executed.
POST /objects201

Basic authentication (8)

#ScenarioRequestExpected
102Valid username and password
Authorization: Basic base64(user:pass).
GET /basic/profile basic200
103No credentials
401 with a WWW-Authenticate challenge.
GET /basic/profile401
104Wrong password
Invalid credentials.
GET /basic/profile basic_wrong401
105Malformed Basic header
Header that is not base64.
GET /basic/profile401
106Create an object with Basic auth
Write behind Basic auth.
POST /basic/objects basic201
107Create without credentials
Writes are protected too.
POST /basic/objects401
108Read an object with Basic auth
Read behind Basic auth.
GET /basic/objects/{id} basic200
109Collections are separate
An object created in /objects is not in /basic/objects.
GET /basic/objects/{id} basic404

API key authentication (6)

#ScenarioRequestExpected
110Valid key in the X-API-Key header
Header-based API key.
GET /apikey/profile apikey200
111Valid key as a query parameter
Query-string key (less secure: it ends up in logs).
GET /apikey/profile?api_key=sqa-key-12345200
112Missing API key
401 when no key is sent.
GET /apikey/profile401
113Wrong API key
403 when the key is not valid.
GET /apikey/profile apikey_wrong403
114Key sent in the wrong header
The key must be in X-API-Key.
GET /apikey/profile401
115Create an object with an API key
Write behind an API key.
POST /apikey/objects apikey201

Token (Bearer JWT) authentication (15)

#ScenarioRequestExpected
116Log in and get a token
Token issue.
POST /auth/login200
117Log in with a wrong password
Failed login.
POST /auth/login401
118Log in without fields
Required fields.
POST /auth/login422
119Token lifetime below 5 seconds
Boundary on expires_in.
POST /auth/login422
120Call a protected endpoint with the token
Authorization: Bearer <token>.
GET /auth/me admin200
121No token
401 without a token.
GET /auth/me401
122Garbage token
Not a JWT.
GET /auth/me401
123Wrong scheme (Token instead of Bearer)
Scheme must be Bearer.
GET /auth/me401
124Tampered token signature
Changing any character breaks the signature.
GET /auth/me tampered401
125Expired token
Token issued with expires_in 5, used after 7 seconds.
GET /auth/me expired401
126Log out revokes the token
Server-side logout.
POST /auth/logout admin204
127Token used after logout
Revoked tokens are rejected.
GET /auth/me revoked401
128Refresh the token
Get new tokens without the password.
POST /auth/refresh200
129Reuse a refresh token
Refresh tokens rotate: each works once.
POST /auth/refresh401
130Refresh without a token
Required field.
POST /auth/refresh422

Authorization (roles and permissions) (6)

#ScenarioRequestExpected
131Viewer can read objects
Read permission.
GET /token/objects viewer200
132Viewer cannot create objects
403 = authenticated but not allowed.
POST /token/objects viewer403
133Admin can create objects
Write permission.
POST /token/objects admin201
134Viewer cannot delete
Role check on DELETE.
DELETE /token/objects/{id} viewer403
135Admin can delete
Owner role succeeds.
DELETE /token/objects/{id} admin204
136Viewer token says can_write false
Claims in the response.
GET /auth/me viewer200

Performance, timeouts and rate limits (5)

#ScenarioRequestExpected
137Response time under 3 seconds
Simple SLA assertion.
GET /users200
138Delayed response (2 seconds)
Measure latency.
GET /delay/2200
139Delay above the limit
Validation on the delay.
GET /delay/11400
140Client timeout
Your client should give up after 2 seconds.
GET /delay/5client timeout
141Rate limit: 6th call in a minute
429 Too Many Requests with Retry-After.
GET /rate-limit429

Code examples

Every example below runs as-is against this API.

# 1. Read hardcoded data (no auth)
curl -i https://sqatools.in/wp-json/sqa-api/v1/users/1

# 2. Create a temporary object that lives 120 seconds
curl -i -X POST https://sqatools.in/wp-json/sqa-api/v1/objects \
  -H "Content-Type: application/json" \
  -d '{"name": "My test object", "data": {"qty": 2}, "ttl": 120}'

# 3. Basic auth
curl -i -u sqa_user:sqa@123 https://sqatools.in/wp-json/sqa-api/v1/basic/profile

# 4. API key
curl -i -H "X-API-Key: sqa-key-12345" https://sqatools.in/wp-json/sqa-api/v1/apikey/profile

# 5. Bearer token: log in, then send the access_token
curl -s -X POST https://sqatools.in/wp-json/sqa-api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "admin@123"}'
curl -i -H "Authorization: Bearer <access_token>" https://sqatools.in/wp-json/sqa-api/v1/auth/me

Limits

  • 600 requests per minute per IP (then 429); /rate-limit allows 5 per minute on purpose.
  • Request bodies up to 10 KB (413 above that); data up to 5 KB.
  • Up to 300 live objects per collection; the oldest are removed first.
  • /delay/{seconds} waits at most 10 seconds. Responses are never cached.