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.
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
| API | URL | Best for |
|---|---|---|
| Restful Booker | https://restful-booker.herokuapp.com/apidoc/index.html | CRUD operations, auth tokens |
| ReqRes | https://reqres.in/ | User management, pagination |
| httpbin | http://httpbin.org/ | HTTP method testing, headers |
| JSON Placeholder | https://jsonplaceholder.typicode.com/ | Posts, users, todos |
| Swagger Petstore | https://petstore.swagger.io/ | OpenAPI spec-based testing |
| FakeRESTAPI | https://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
TYPESCRIPT1import { 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:
BASH1# 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):
- apipheny.io/free-api — comprehensive list
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
TYPESCRIPT1// 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
TYPESCRIPT1// 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:
YAML1# 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_pagesin response - Request the last page → verify fewer results than
per_page - Request page 999 → verify empty
dataarray, 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