laqi · contract-first API mocks
local by default · no account · JSON in your repo
Build the frontend.
Before the backend is ready.
- 01Agree on the API contract.
- 02laqi serves it immediately.
- 03 Build against realistic responses. successemptyslow401500
- 04Switch to the real backend by changing one base URL.
why it works
The team was ready. The API wasn’t.
Agree on the contract. Build everything else in parallel.
Define the API contract once. laqi serves it immediately while the backend builds the real implementation.
born on a frontend team running 2–3 sprints ahead of its backend
before Implementation becomes the dependency. The frontend can’t integrate until the backend exists.
frontend
Ready to build
backend
Still in development
after One contract. Two teams moving at once. laqi serves the agreed API today. The backend implements the same contract independently.
The contract is plain TypeScript — the one language both teams share. laqi turns it into a working API today; the backend implements it.
frontend + backend agree on it together
export interface Todo {
id: string;
title: string;
done: boolean;
} plain TypeScript · common language
laqi reads the contract
and simulates every endpoint
frontend
Builds today
laqi
Serves the contract
backend
Builds it for real
switch when
it’s ready
change base URL
+ run the same tests
real API
Contract implemented
No integration rewrite. Just point to the real API.
-
before implementation
Agree on the contract
Frontend and backend define the routes, types and states together.
-
while building
Build in parallel
laqi serves the contract now. The backend implements the same contract for real.
-
when ready
Switch, then verify
Change the base URL and run the same flows against the real API.
The real gain was never the mock server.
It was removing a dependency from delivery.
what the frontend track gets 01 a contract 02 types & data 03 every state 04 the reason why 05 a real device
01 / 05 contract · plain JSON
Agree the API once.
Then both sides build against it.
Routes are defined once. Each named response is a state that matters. The file lives in git — the frontend serves it with laqi today, the backend implements the same interface.
the shift
The contract becomes the dependency — not the backend implementation.
named responseslives in gitimport OpenAPI
{ "GET /todos": { route · defined once "default": "ok", "responses": { named states "ok": { "body": [{ "id": 1 }] }, "empty": { "body": [] }, "slow": { "delay": 2400 }, "error": { "status": 500 } ← a state that matters } } } frontend
laqi start → served now
backend
implements the same routes
02 / 05 model · from types to responses
Start from your types.
laqi writes the responses.
Paste a TypeScript interface, point at a schema already in your project, or drop in sample JSON. laqi generates realistic data that fits it — and goes the other way too, giving you types for any response.
why it matters
The mock and the frontend’s types can’t drift apart — they come from the same model.
from a modelfrom JSONfrom a schema in the projectcopy types
your model
1 export interface Order {
2 id: string;
3 total: number;
4 status: 'paid' | 'pending';
5 createdAt: Date;
6 }
generated · ok 200
1 {
2 "id": "ord_8f2a41",
3 "total": 148.5,
4 "status": "paid",
5 "createdAt": "2026-08-24T14:32:07Z"
6 }
03 / 05 flip · every edge case, on demand
What if it fails?
Find out before the backend can tell you.
Test the states you usually have to wait for — or can never get on purpose. Pick one, and your app’s next ordinary request gets it. Nothing restarts, and your app does not know the difference.
the point
The error path stops being the one nobody ever sees until a user does.
500 error 401 unauthorized 422 validation empty list slow · 3soffline scenario
04 / 05 watch · resolution, explained
Every request tells you why.
No guessing which rule won.
Each line shows what came back and what chose it — a header on one request, a state you picked in the panel, the active scenario, or what the file says. Requests that matched no route show up too. That one is usually the bug.
same answer, three places
The panel, the terminal and the x-laqi-resolved header
always say the same thing.
header state scenario default
just files
Your mock API is just files. Yours to keep.
They live alongside your code. Keep them local for yourself, or commit them when the team should share them — clone the repo and everyone gets the same contract, data and scenarios. laqi reads and writes the files you already own; it never becomes the source of truth.
- Plain files in your project. Keep them local or commit them.
- Git-native when you want it. Review, diff, branch, clone.
- No hosted project. No account, no cloud workspace, no remote database.
- Runtime state is disposable. Your contract and data are what persist.
▾ laqi/ · your mock API
▢ api.json
▢ scenarios.json
▸ src/
laqi/api.json · "POST /todos"
+ "validation": { "status": 422, "body": {…} },
− "error": { "status": 500 }
local
Keep it local
git
Commit when it becomes team knowledge
team
Everyone gets the same mock API
disposable
selected responsetemporary flipslocal overridespanel state
never committed
the name
A runner, ahead of the road.
The chasqui was a relay runner of the Inca road network, carrying messages between waystations across the Andes.
laqi plays the same role for your team. It carries the agreed API contract before the real backend implementation exists.
laqi carries the contract before the real API arrives.
roots
Quechua — llulla, false · chasqui, messenger
say it out loud: it sounds like “lucky”
Stop waiting for the backend.
Start with the contract.
or run it without installing · then laqi init, five questions,
every one skippable with enter
Plain JSON in your repo · runs on your machine · --share
exposes only mock responses, never the control plane.