Test Data — entry 009 of 19

JSONPlaceholder

Verified Jul 2026

JSONPlaceholder is one of the longest-running free fake REST APIs, serving a fixed set of 100 posts, 500 comments, 10 users, 100 albums, 5,000 photos, and 200 todos as JSON. Every standard verb works against each resource, including nested routes like /posts/1/comments, though POST/PUT/PATCH/DELETE only simulate a write and return a fake response without persisting any change. Its data and IDs never change, which is exactly why it's the default backend in countless framework tutorials and testing guides.

JSONPlaceholder is a free, keyless fake REST API serving a fixed, never-changing dataset — 100 posts, 500 comments, 10 users, 100 albums, 5,000 photos, 200 todos — with every standard verb wired up against each resource, including nested routes like /posts/1/comments. A live GET this run confirmed both http:// and https:// resolve the same host directly with no redirect either way, and every response (200 or 404) carries an undocumented x-ratelimit-limit: 1000 / x-ratelimit-remaining / x-ratelimit-reset header trio that appears nowhere in the project's own docs.

mock-datatestingprototypingrest-api
AuthenticationNone requiredCall it straight away — no key, no signup.
HTTPSSupportedTraffic is encrypted in transit.
CORSEnabledCallable directly from browser JavaScript.
PricingFreeNo paid tier — free for the documented use case.
FormatsJSONResponses can be requested as JSON.

GreatAPIs Score

Score88out of 100
Authentication25/25No authentication required
Pricing20/20Free to use
Docs14/20Documentation URL provided
Formats9/15Single response format
Freshness20/20Verified within 6 months

Embed this badge

Scored 88 on greatapis.com
<a href="https://greatapis.com/api/jsonplaceholder-test-data/"><img src="https://greatapis.com/badge/jsonplaceholder-test-data.svg" alt="Scored 88 on greatapis.com"></a>

Auth quickstart

  1. No API key, header, or signup required for any route. This run's undocumented x-ratelimit-limit header consistently reads 1000, but the paired x-ratelimit-reset value is not stable across probes — the window it implies varies from one request to the next and between edge servers, so it can't be read as a dependable 'N requests per minute' figure. Treat the counter as headroom to watch, not a number to plan around.
Stored keyNo key stored

Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.

Get a single post

GEThttps://jsonplaceholder.typicode.com/posts/1

200 application/json; charset=utf-8

{"userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}

Try it

Developer reference

Base URLhttps://jsonplaceholder.typicode.com
Key endpoints
  • GET/posts/{id}
  • GET/posts/{id}/comments
  • GET/users

Gotchas & limits

  • A not-found ID is HTTP 404 with a literal {} body (content-length: 2), not an empty array or a 200 with null: a live GET /posts/999 this run returned exactly that — branch on status code, never on an empty-looking body, since there's no array shape here to check.
  • A non-numeric ID also 404s the same way rather than erroring: a live GET /posts/abc this run returned the identical {} at 404 — the API never validates the ID's type, it just fails the lookup.
  • CORS echoes the request's Origin back verbatim instead of sending a wildcard: a live GET with Origin: https://greatapis.com this run returned access-control-allow-origin: https://greatapis.com on that exact value, while the same GET sent with no Origin header comes back with no access-control-allow-origin at all — though access-control-allow-credentials: true and vary: Origin are still present either way, so it's that one header that's conditional, not CORS support in general. Verified on cache-busted requests (cf-cache-status: MISS) so the edge cache isn't masking the difference.
  • POST /posts returns HTTP 201 with a fake id: 101 that is never actually persisted: a live POST this run got back {"title":"foo","body":"bar","userId":1,"id":101}, but an immediate follow-up GET /posts/101 still 404s with the same literal {} — treat every write as a simulation, not real state.
  • An OPTIONS preflight against /posts/1 (sent with Origin + Access-Control-Request-Method: GET) returns 204 with access-control-allow-methods: GET,HEAD,PUT,PATCH,POST,DELETE and the same echoed-origin header, confirming a real browser cross-origin call would succeed end to end.

Availability

Uptime100%
Median latency31 ms
Last checkUp · 200 · Sep 2026

2 checks since Sep 2026. A person runs this check by hand, not an automated monitor.