Counterfact logo

Not just a
mock server.

Point Counterfact at an OpenAPI spec and get a live, stateful API in seconds — with TypeScript safety, hot reload, shared state, and a programmable REPL.

terminal
$ npx counterfact@latest
  https://petstore3.swagger.io/…/openapi.json api
Reading OpenAPI spec…
Generating routes/ and types/ …
✓ 17 route files written
✓ Server → http://localhost:3100
✓ Swagger UI → /counterfact/swagger/
⬣>
What you get

Everything a mock server
should have been.

Static canned responses aren't enough. No shared state. No failure injection. No control mid-run. Counterfact is an API simulator without those limits.

Contract-driven generation

TypeScript handlers and typed interfaces for every endpoint, derived from your OpenAPI spec. Drift is impossible — your editor tells you before the server does.

Hot reload, no restart

Save a route file and the server picks it up instantly. Your in-memory state survives every reload — no lost context, no interruptions.

Programmable REPL

A live JavaScript prompt wired directly to your running server. Inspect state, inject failures, toggle proxy routes — while the server handles real traffic.

Shared state across routes

Drop a _.context.ts in any directory to share typed in-memory state. POST, GET, DELETE — all routes see the same data.

Hybrid proxy mode

Forward some routes to a real backend while mocking everything else. Toggle individual paths live from the REPL as the real API comes online.

Deterministic resets

Restart and the system returns to a known state. Deterministic when you need repeatability. Programmable when you need realism. Optional persistence via TypeScript.

How it works

From spec to live
server in one
command.

  • Read your OpenAPI spec

    Point Counterfact at a local file or URL. It reads your entire document — endpoints, schemas, error conditions, everything.

  • Generate typed TypeScript handlers

    A routes/ directory with one .ts per endpoint, plus full typed interfaces in types/. Existing route files are never overwritten.

  • Server starts immediately

    Every endpoint is live, returning random schema-valid data by default. Swagger UI opens automatically so you can explore immediately.

  • Program the behavior you need

    Replace .random() with .json(), add state, wire up logic. Save — the server reloads instantly, state preserved.

  • Control everything from the REPL

    Inspect state, inject failures, fire requests, toggle proxy routes — all from a live prompt, no file edits required.

api/routes/pet/{petId}.ts
import type { HTTP_GET, HTTP_DELETE }
  from "../../types/paths/pet/{petId}.types.js";

export const GET: HTTP_GET = ($) => {
  const pet = $.context.get($.path.petId);

  if (!pet) {
    return $.response[404].text(
      `Pet ${$.path.petId} not found`
    );
  }

  return $.response[200].json(pet);
};

export const DELETE: HTTP_DELETE = ($) => {
  $.context.remove($.path.petId);
  return $.response[200];
};
api/routes/_.context.ts
import type { Pet }
  from "../types/components/pet.types.js";

export class Context {
  private pets = new Map<number, Pet>();
  private nextId = 1;

  add(pet: Omit<Pet, "id">): Pet {
    const id = this.nextId++;
    const rec = { ...pet, id };
    this.pets.set(id, rec);
    return rec;
  }

  get(id: number) { return this.pets.get(id); }
  list()         { return [...this.pets.values()]; }
  remove(id: number) { this.pets.delete(id); }
}
counterfact REPL
⬣>context.list()
[ { id: 1, name: 'Fluffy', status: 'available' } ]
⬣>context.add({ name: 'Rex', photoUrls: [], status: 'pending' })
{ id: 2, name: 'Rex', … }
⬣>client.get("/pet/2")
{ status: 200, body: { id: 2, name: 'Rex', … } }
⬣>.proxy on /payments
✓ /payments/* → https://api.example.com
⬣>context.pets.clear()
✓ Cleared. GET /pet → []
⬣>
The REPL

DevTools
for your API.

A live JavaScript prompt wired directly to your running server. The REPL exposes a context object and a client — inspect state, modify data, and fire requests all at once.

Want to test what happens when the database is empty? Clear it. Need to simulate a 500? Set it up. Proxy half the API to a real backend? One command.

Restart and everything returns to its initial state. Deterministic when you need repeatability. Programmable when you need realism.

Who it's for

Real enough to be useful.
Fake enough to be usable.

Frontend developer

Stop waiting on the backend.

Your team has an OpenAPI spec. The backend is two sprints out. Run Counterfact and build against a live, typed, stateful API today. No mocks to maintain. No drift.

Test engineer

Reproducible state, every time.

Set up exactly the state you need from the REPL. Run your test. Restart for a clean slate. No database fixtures, no teardown scripts, no flakiness.

AI agent / automation

A stable API substrate.

Agentic workflows need deterministic, scriptable APIs. Counterfact is restartable, stateless by default, and fully controllable — built for automated pipelines.

How it compares

Beyond static mocks.

Most tools stop at response recording. Counterfact gives you a programmable simulation.

Capability Counterfact Prism WireMock MSW
OpenAPI-driven generation
TypeScript type safety partial
Shared state across routes manual manual
Hot reload (no restart)
Live REPL
Proxy to real backend
Deterministic reset on restart config
Programmable failure simulation config manual
Get started

Try it in one command.

No install. No configuration. Point it at any OpenAPI spec and go.


npx counterfact@latest https://petstore3.swagger.io/api/v3/openapi.json api

Read the getting started guide