Test Automation

Best Free API Testing Demo Sites

A curated list of the best free API testing demo endpoints for practicing REST API automation with Postman, REST Assured, and more.

I
InnovateBits
InnovateBits

Learning API testing requires practicing against real endpoints. Here's a curated list of free APIs that are specifically designed for testing purposes.

Why use dedicated test APIs?

  • No rate limits that matter — practice as much as you want
  • Known data — predictable responses you can assert against
  • Safe to experiment — create, update, delete without consequences
  • Good documentation — understand what to expect

The essential list

APIURLBest for
Restful Bookerhttps://restful-booker.herokuapp.com/apidoc/index.htmlCRUD operations, auth tokens
ReqReshttps://reqres.in/User management, pagination
httpbinhttp://httpbin.org/HTTP method testing, headers
JSON Placeholderhttps://jsonplaceholder.typicode.com/Posts, users, todos
Swagger Petstorehttps://petstore.swagger.io/OpenAPI spec-based testing
FakeRESTAPIhttps://fakerestapi.azurewebsites.net/Activities, authors, books

Deep dive: Restful Booker

This is my go-to for teaching API automation. It covers:

POST   /auth          → Get authentication token
GET    /bookings      → List all bookings
POST   /booking       → Create new booking
GET    /booking/{id}  → Get specific booking
PUT    /booking/{id}  → Full update (requires auth)
PATCH  /booking/{id}  → Partial update (requires auth)
DELETE /booking/{id}  → Delete booking (requires auth)

Playwright API test example

TYPESCRIPT
1import { test, expect, request } from '@playwright/test'; 2 3const BASE_URL = 'https://restful-booker.herokuapp.com'; 4 5test.describe('Booking API', () => { 6 let authToken: string; 7 let bookingId: number; 8 9 test.beforeAll(async () => { 10 const context = await request.newContext(); 11 const response = await context.post(`${BASE_URL}/auth`, { 12 data: { username: 'admin', password: 'password123' }, 13 }); 14 const body = await response.json(); 15 authToken = body.token; 16 }); 17 18 test('create a new booking', async ({ request }) => { 19 const response = await request.post(`${BASE_URL}/booking`, { 20 data: { 21 firstname: 'John', 22 lastname: 'Doe', 23 totalprice: 250, 24 depositpaid: true, 25 bookingdates: { 26 checkin: '2025-01-01', 27 checkout: '2025-01-07', 28 }, 29 additionalneeds: 'Breakfast', 30 }, 31 }); 32 33 expect(response.status()).toBe(200); 34 const booking = await response.json(); 35 bookingId = booking.bookingid; 36 37 expect(booking.booking.firstname).toBe('John'); 38 expect(booking.booking.totalprice).toBe(250); 39 }); 40 41 test('update booking requires authentication', async ({ request }) => { 42 const response = await request.patch(`${BASE_URL}/booking/${bookingId}`, { 43 headers: { Cookie: `token=${authToken}` }, 44 data: { firstname: 'Jane' }, 45 }); 46 47 expect(response.status()).toBe(200); 48 const updated = await response.json(); 49 expect(updated.firstname).toBe('Jane'); 50 }); 51});

JSON Placeholder for quick prototyping

Great for when you just need a quick endpoint:

BASH
1# Get all posts 2GET https://jsonplaceholder.typicode.com/posts 3 4# Get specific post 5GET https://jsonplaceholder.typicode.com/posts/1 6 7# Get user's posts 8GET https://jsonplaceholder.typicode.com/users/1/posts 9 10# Create a post (fake - doesn't persist) 11POST https://jsonplaceholder.typicode.com/posts 12Body: { "title": "foo", "body": "bar", "userId": 1 }

More API resources

For a broader collection of free public APIs (not just for testing):


Missing a good API testing resource? Let me know on LinkedIn!


Building a structured API test project against demo sites

Demo APIs are only useful if you use them to practice real project patterns, not just ad-hoc Postman requests. Here's how to structure a proper API test project.

Project structure

api-testing-practice/
├── tests/
│   ├── auth/
│   │   ├── token.test.ts
│   │   └── logout.test.ts
│   ├── bookings/
│   │   ├── create.test.ts
│   │   ├── retrieve.test.ts
│   │   ├── update.test.ts
│   │   └── delete.test.ts
│   └── smoke.test.ts
├── helpers/
│   ├── auth.ts
│   └── booking-factory.ts
├── jest.config.js
└── package.json

Restful Booker full CRUD test suite

TYPESCRIPT
1// tests/bookings/create.test.ts 2import request from 'supertest' 3import { getAuthToken } from '../../helpers/auth' 4import { createBookingPayload } from '../../helpers/booking-factory' 5 6const BASE_URL = 'https://restful-booker.herokuapp.com' 7 8describe('POST /booking — Create booking', () => { 9 it('creates a booking with valid data and returns 200', async () => { 10 const payload = createBookingPayload({ 11 firstname: 'Alice', 12 lastname: 'Chen', 13 totalprice: 150, 14 depositpaid: true, 15 checkin: '2025-12-01', 16 checkout: '2025-12-05', 17 }) 18 19 const res = await request(BASE_URL) 20 .post('/booking') 21 .set('Content-Type', 'application/json') 22 .set('Accept', 'application/json') 23 .send(payload) 24 .expect(200) 25 26 expect(res.body.bookingid).toBeDefined() 27 expect(res.body.booking.firstname).toBe('Alice') 28 expect(res.body.booking.totalprice).toBe(150) 29 }) 30 31 it('creates booking and verifies it can be retrieved by ID', async () => { 32 const payload = createBookingPayload() 33 const createRes = await request(BASE_URL) 34 .post('/booking') 35 .send(payload) 36 .expect(200) 37 38 const bookingId = createRes.body.bookingid 39 40 const getRes = await request(BASE_URL) 41 .get(`/booking/${bookingId}`) 42 .set('Accept', 'application/json') 43 .expect(200) 44 45 expect(getRes.body.firstname).toBe(payload.firstname) 46 }) 47})

Auth helper for token-protected endpoints

TYPESCRIPT
1// helpers/auth.ts 2import request from 'supertest' 3 4let cachedToken: string | null = null 5 6export async function getAuthToken(): Promise<string> { 7 if (cachedToken) return cachedToken 8 9 const res = await request('https://restful-booker.herokuapp.com') 10 .post('/auth') 11 .send({ username: 'admin', password: 'password123' }) 12 .expect(200) 13 14 cachedToken = res.body.token 15 return cachedToken 16} 17 18// Reset between test suites if needed 19export function clearTokenCache() { 20 cachedToken = null 21}

Running against multiple demo APIs in one pipeline

A real API test suite often covers multiple services. Demo APIs let you practice this pattern safely:

YAML
1# azure-pipelines.yml 2stages: 3 - stage: APITests 4 jobs: 5 - job: RestfulBooker 6 displayName: Restful Booker CRUD Tests 7 steps: 8 - script: npm ci 9 - script: npx jest tests/bookings/ --testPathPattern="create|update|delete" 10 env: 11 API_BASE_URL: https://restful-booker.herokuapp.com 12 - task: PublishTestResults@2 13 inputs: 14 testResultsFormat: JUnit 15 testResultsFiles: test-results/api-results.xml 16 condition: always() 17 18 - job: ReqResUsers 19 displayName: ReqRes User API Tests 20 steps: 21 - script: npm ci 22 - script: npx jest tests/users/ 23 env: 24 API_BASE_URL: https://reqres.in/api 25 - task: PublishTestResults@2 26 inputs: 27 testResultsFormat: JUnit 28 testResultsFiles: test-results/user-results.xml 29 condition: always()

Key API testing scenarios to practice

Work through these scenarios on the demo APIs to build competence you can apply to real projects:

Authentication flows (Restful Booker):

  • Obtain a token with valid credentials
  • Attempt to delete a booking without a token (expect 403)
  • Attempt to delete with an invalid token (expect 403)
  • Obtain a fresh token and verify it works

CRUD lifecycle (JSON Placeholder):

  • Create a resource → verify 201 and Location header
  • Retrieve it by ID → verify data matches
  • Update it (PATCH) → verify only changed fields updated
  • Delete it → verify 200
  • Attempt to retrieve after delete → verify 404

Pagination (ReqRes):

  • Request page 1 → verify page, total, total_pages in response
  • Request the last page → verify fewer results than per_page
  • Request page 999 → verify empty data array, not an error

Error handling (httpbin):

  • Request /status/400 → verify your client handles 400 correctly
  • Request /status/500 → verify retry logic triggers
  • Request /delay/10 → verify timeout handling at < 10 seconds
Tags
#api-automation#demo#rest#postman