โ† All guides

A free Platzi Fake Store API alternative โ€” same CRUD, but the database is yours

Credit first: the Platzi Fake Store API (api.escuelajs.co) is one of the most real fake APIs on the internet. Built by Platzi for their courses, it's a genuine relational backend: REST and GraphQL over the same data, JWT auth with working access and refresh tokens, a file-upload endpoint, filters (?title=, ?price_min=&price_max=, ?categoryId=) โ€” and, unlike JSONPlaceholder or FakeStoreAPI, writes actually persist. All of it keyless and free. That's why it's in so many React and e-commerce tutorials.

The catch is the flip side of that realness: it's one shared, world-writable database for the whole internet. Everything below was verified hands-on with curl on September 4, 2026:

  1. Your writes are everyone's โ€” and everyone's are yours. We POSTed a product and could immediately GET it back on the public list, no key, no account โ€” which means every other tutorial-follower on Earth sees it, can rename it, or can DELETE /products/1 and 404 your demo. Minutes after a fresh reseed, product 1's updatedAt had already been changed by someone. If a course screenshot shows different data than your screen, this is why.
  2. The dataset resets without warning. When we tested, every category and product carried the same creationAt timestamp from less than fifteen minutes earlier โ€” the whole database had just been rebuilt. Anything you create is ephemeral, on a schedule you don't control.
  3. Updates 500 unless you resend images. A PUT /products/:id with the docs' own example body ({"title":โ€ฆ,"price":โ€ฆ}) answers {"statusCode":500,"message":"Internal server error"}. Include an images array and the same request succeeds.
  4. Missing records answer 400, not 404 โ€” with a raw ORM dump. GET /products/99999 returns HTTP 400 and a TypeORM EntityNotFoundError body (internal query included). Any if (res.status === 404) handling in your app misses it.
  5. Anything posted to /users is public โ€” including the password field. GET /users lists every account anyone has created, passwords in plain text. Fine for fake data; never type anything real into it.

The same store, yours alone, in two curls

Rebuild the products/categories shape as your own isolated project โ€” every command below ran against production before this page was published. No signup:

P=$(curl -s -X POST https://mockbird.mockbird.workers.dev/api/projects \
  -H 'content-type: application/json' -d '{"name":"my-store","blank":true}')
ID=$(echo "$P" | grep -o '"id": *"[^"]*"' | head -1 | cut -d'"' -f4)
KEY=$(echo "$P" | grep -o '"adminKey": *"[^"]*"' | cut -d'"' -f4)

curl -s -X POST "https://mockbird.mockbird.workers.dev/api/projects/$ID/resources" \
  -H "x-admin-key: $KEY" -H 'content-type: application/json' -d '{
  "name":"categories","seed":20,"fields":[
    {"name":"name","type":"category"},{"name":"image","type":"image"}]}'

curl -s -X POST "https://mockbird.mockbird.workers.dev/api/projects/$ID/resources" \
  -H "x-admin-key: $KEY" -H 'content-type: application/json' -d '{
  "name":"products","seed":20,"fields":[
    {"name":"title","type":"title"},{"name":"price","type":"price"},
    {"name":"description","type":"paragraph"},{"name":"image","type":"image"},
    {"name":"categoryId","type":"refId"}]}'

(The categoryId naming is what powers the nested routes and joins below. Prefer clicking? One-click e-commerce preset gives you products/orders/customers/reviews instantly.)

Use it โ€” their greatest hits, isolated

curl 'https://mockbird.mockbird.workers.dev/m/<ID>/products?page=1&limit=10'      # their offset/limit, 1-based
curl 'https://mockbird.mockbird.workers.dev/m/<ID>/products?price_gte=100&price_lte=500'   # their price_min/price_max
curl 'https://mockbird.mockbird.workers.dev/m/<ID>/products?title_like=chair'      # their ?title= substring filter
curl 'https://mockbird.mockbird.workers.dev/m/<ID>/products?categoryId=3&_expand=category'
curl 'https://mockbird.mockbird.workers.dev/m/<ID>/categories/3/products'          # their /categories/:id/products
curl -X POST 'https://mockbird.mockbird.workers.dev/m/<ID>/products' \
  -H 'content-type: application/json' \
  -d '{"title":"Handmade Chair","price":149.5,"description":"solid oak","categoryId":3}'
# โ†’ {"id":21} โ€” persists, and ONLY in your project. Nobody else can touch it.
curl -X PATCH 'https://mockbird.mockbird.workers.dev/m/<ID>/products/21' \
  -H 'content-type: application/json' -d '{"price":99.5}'
# โ†’ partial update just works โ€” no images array required, no 500
curl 'https://mockbird.mockbird.workers.dev/m/<ID>/products/999'   # โ†’ a proper 404, not a 400 + ORM dump

GraphQL rides along on the same records (theirs is real too โ€” credit where due; ours adds mutations on the same data as REST):

curl -X POST 'https://mockbird.mockbird.workers.dev/m/<ID>/graphql' \
  -H 'content-type: application/json' \
  -d '{"query":"{ products(limit:2, sortBy:\"price\", order:\"desc\") { id title price category { name } } }"}'

And the JWT login flow their auth tutorials use works here without a shared user table โ€” any email/password pair answers a real signed JWT, and if you add a users resource, logins match those records (mock-auth guide). Passwords are never stored in responses, and your users aren't listed on a public URL.

Platzi Fake Store โ†’ Mockbird translation

On api.escuelajs.coOn Mockbird
GET /api/v1/products?offset=20&limit=10GET /m/<id>/products?page=3&limit=10 (page-based, 1-indexed)
?title=shirt (substring)?title_like=shirt โ€” same semantics
?price_min=100&price_max=500?price_gte=100&price_lte=500 (each also works alone)
?categoryId=1?categoryId=1 โ€” identical; add &_expand=category for the joined object
GET /categories/:id/productsGET /m/<id>/categories/:id/products โ€” identical nested route
Writes persist โ€” for everyone at oncewrites persist in your project only
PUT 500s without imagesPUT replaces, PATCH merges โ€” no required fields
Missing id โ†’ HTTP 400 + TypeORM error dumpproper 404 JSON
Shared JWT auth (users public, passwords listed)per-project mock JWT auth, password fields stripped
GraphQL at /graphqlGraphQL per project, queries + mutations
Error testing: none?mock_status=503, ?mock_delay=2000, chaos injection

Honest comparison

Platzi Fake Store APIMockbird
First requestkeyless curlkeyless curl
Writesreal โ€” into one database shared by every user on the internetreal โ€” into your own project
Data survivesuntil the next reset (unannounced; full reseed observed mid-test)persists; snapshots to save/restore states on purpose
Other people's interferenceanyone can rename/delete anything, including the seed dataimpossible โ€” isolated per project
Authreal JWT + refresh tokens (genuinely good for auth tutorials)mock JWT per project, any credentials, expiry configurable
Schemafixed: products / categories / users (+ file upload โ€” ours has no equivalent)any collections, any typed fields, custom routes
Product imagesplaceholder images in the seed data (placehold.co) as of Sep 2026picsum/dicebear-style generated URLs, or bring your own
Failure simulationโ€”status/delay/chaos per request
Exportsโ€”OpenAPI, Postman, TypeScript/Zod, db.json eject

Where Platzi's API wins, plainly: it's free, keyless, open about what it is, and its auth flow โ€” real access + refresh tokens against known seed users โ€” is the best free way to follow a JWT tutorial without standing anything up. Its file-upload endpoint has no Mockbird equivalent. If you're doing a read-only product grid and don't mind the occasional stranger-renamed product, it's fine. This page is for the moment your writes need to survive, your demo needs to not depend on the whole internet behaving, or your error-handling needs a real 404.

Try it with zero setup

curl 'https://mockbird.mockbird.workers.dev/m/demo/products?limit=2&sortBy=price&order=desc'
curl -X POST https://mockbird.mockbird.workers.dev/m/demo/products \
  -H 'content-type: application/json' -d '{"name":"Test product","price":9.99}'
# โ†’ it persists โ€” GET it back by the id you received.

This page is written by the Mockbird maker โ€” bias disclosed. Platzi Fake Store API facts verified hands-on with curl on September 4, 2026: the world-visible POST (we created a clearly-labeled test product and deleted it ourselves), the uniform creationAt timestamps minutes after a reseed, the PUT-without-images โ†’ 500 (and with โ†’ 200), the missing-id โ†’ HTTP 400 EntityNotFoundError body, the plaintext password fields on GET /users, the working john@mail.com/changeme JWT login, and the live GraphQL endpoint. We touched no one else's records. Their filters/params are from their documentation and confirmed live. Every Mockbird command on this page was run against production before publishing (scratch project deleted after). Anonymous projects have a per-IP daily creation cap; sign up (free) to keep projects permanently. Current status of this and 50+ other free dev APIs: /status.

Full API reference in the docs. More guides: FakeStoreAPI alternative ยท DummyJSON alternative ยท JSONPlaceholder alternative ยท GoRest alternative. Create your API โ†’

โšก Skip the terminal: this link creates a seeded store backend in one click โ€” products, orders, customers, reviews, live URL, no signup. Or import your own OpenAPI/db.json/CSV.