What mockly is
A free fake REST API for frontends and prototypes. Create a project, drop JSON into a collection, and get full CRUD endpoints with filtering, sorting, pagination and relations. By default there are no keys and no headers — mocks are served over a public link; enable authorization when you need private resources.
https://api.m0ckly.site/m/:publicId/:collection
publicId identifies the project and is shown on its page. collection is the collection name.
Your first request
- Create a project and a collection — products, for example.
- Paste an array of JSON objects. The id field is filled in for you.
- Call the endpoint from your code.
const res = await fetch('https://api.m0ckly.site/m/acme/products?limit=2') const products = await res.json()
[ { "id": 1, "title": "Keyboard", "price": 90 }, { "id": 2, "title": "Mouse", "price": 40 } ]
How it is all arranged
An account holds projects, a project holds collections, a collection holds records. Registering creates a project named default for you, so there is something to work with straight away.
https://api.m0ckly.site/m/4f8c1e0a9b3d7c25/productsEvery project gets its own publicId — 16 hex characters generated on creation and shown on the project page. It is the only thing that identifies the project in a mock URL, and renaming the project does not change it.
Project and collection names are 1 to 64 characters. A name is unique inside its scope: two projects on one account cannot share a name, and neither can two collections inside one project.
Deleting a project deletes its collections along with every record in them, and deleting a collection deletes its records. There is no undo. To take a project offline without losing data, turn it off instead.
Finding out what is in a project
The project root lists its collections and whether each one is on. Handy for a client that discovers the schema instead of hardcoding it.
GET /m/acme { "collections": [ { "name": "products", "enabled": true }, { "name": "orders", "enabled": false } ] }
Disabled collections are listed too, marked with enabled: false — requests to them answer 403. A disabled project responds 403 here as well.
Working with records
The full set of methods on a collection. Request and response bodies are JSON.
The id is generated by the server; sending one in a POST body is ignored. PUT replaces the data outright, PATCH merges the given fields into what is already there.
Filtering, search and sorting
These work on the list endpoint and combine in any order.
GET /m/acme/products ?sortBy=price&order=asc &price_gte=20&page=1&limit=10
The names page, limit, sortBy, order, q and _relations are reserved — they will not filter fields of the same name. The _gte and _lte ranges only apply to numeric values; anything else is skipped.
A plain ?title=mouse now matches any title containing "mouse", ignoring case. Use * for prefixes or suffixes (?title=mouse*), and numbers still compare exactly (?price=100).
Paginated output
By default the list endpoint returns a plain array. Pass page or limit and the response is wrapped in an envelope with metadata. If limit is not passed, the page size is 10 — passing page alone also falls back to 10 rather than the page size configured on the collection.
{ "items": [ … ], "meta": { "total_items": 50, "total_pages": 5, "current_page": 1, "per_page": 10 } }
To always get the envelope, turn on Pagination in the collection settings. The same place sets the default page size and drops the total_pages field if you do not need it.
Embedding related records
The _relations parameter embeds a related object straight into the record. List several relations separated by commas.
GET /m/acme/orders?_relations=user { "id": 1, "userId": 7, "user": { "id": 7, "name": "Ann" } }
Relations follow a naming convention: _relations=user looks for a userId field on the record and pulls the matching row from the users collection. If the collection is missing or the reference is dangling, the field comes back as null.
The same parameter works the other way round. Name a collection outright — _relations=orders on a record from users — and you get every order pointing back through userId, as an array. A parent with no children gets an empty array. When both readings are possible, the singular one wins.
GET /m/acme/users/7?_relations=orders { "id": 7, "name": "Ann", "orders": [{ "id": 1, "userId": 7 }] }
Forced responses and disabling
A forced response makes the collection answer every request with a fixed status and an arbitrary body — handy for exercising error handling in the frontend. Any status from 100 to 599 will do. With no body set, you get an object holding the status and its text.
A forced response replaces the normal handler: it applies to every enabled method, and filters, pagination and relations are not evaluated at all. Access checks still run first — a disabled project or collection answers 403, a private resource without a token 401, and a disabled method 405. The records stay untouched — clear the status and the collection answers normally again.
Accepted methods are toggled per collection: read (GET), create (POST), update (PATCH, PUT) and delete (DELETE) independently. A disabled method answers 405 Method Not Allowed; the dashboard keeps full access.
A disabled project or collection responds with 403. Nothing is lost — switch it back on and the data is there.
What the quotas are
The numbers are generous enough for prototyping and are not configurable.
Going over the collection limit answers 409, as does a duplicate project or collection name. A collection holds up to 500 records — POST and imports beyond that answer 409 too.
What comes back
Errors carry a JSON body of the shape: { "error": "..." }
The mock API is public
By default the mock endpoints have no authentication. There is no token, no header, no origin check — CORS is open to every site. Anyone who has the link can read the records, create new ones, edit them and delete them.
So treat a collection as public data. Do not put real personal data, keys, tokens or anything copied out of production in there. The publicId is not a secret: it travels in the URL and lands in browser history, logs and anything you paste it into.
If a link has leaked, turn the project off — the endpoints go 403 straight away while the data stays put. Private resources help you mock a login flow, but they are still mock-grade protection: the data behind them deserves no more trust than the rest.