Skip to main content

API testing

Stateful API Sandbox vs Mock Server: Why Your Mocks Keep Lying

Mock servers and stateful sandboxes solve different problems. Most teams pick the wrong one — and it shows up in production.

Apr 10, 2026FetchSandbox Engineering

A mock server and a stateful API sandbox are not the same thing.

They look the same on the surface. They both stand in for a real API. They both let you test without hitting production. They both claim to make integration work easier. And in week one, they both feel great.

The difference shows up around week three, when you start finding bugs that the mock cannot reproduce because the mock has no concept of what just happened.

What a mock server actually does

A mock server is a glorified configuration file. You tell it: when you see a GET on this path, return that response. When you see a POST with this body shape, return that other response. The mapping is static. The server is stateless. It does not remember the previous request.

This is fine for a lot of things. A mock is great when:

  • You need to unblock frontend work that is waiting on a backend endpoint
  • You want to isolate a unit test from a network dependency
  • You need to assert that your code calls the right URL with the right headers
  • You want to prove that your code handles a specific known response correctly

For these jobs, a mock is the right tool. Tools like WireMock, Postman mock servers, Prism, Beeceptor, and Mockoon all do this well.

The trouble starts when you ask the mock to be an integration test.

Where mocks start lying

Consider this completely innocent test:

  1. POST a customer
  2. POST a subscription that references the customer
  3. GET the subscription back and assert the customer is on it

On a real API, that test exercises three real things: the create succeeded, the relationship persisted, and the read materialized the relationship. If any of those fails in production, you have a real bug.

On a mock server, the same test proves nothing.

The mock cannot tell you whether the customer you posted in step 1 actually exists in step 3, because the mock has no memory. It returned a hardcoded customer object in step 1 and a hardcoded subscription object in step 3. The fact that they happen to look consistent is a property of how you configured the mock — not a property of the API you are integrating with.

This is the part nobody warns you about.

Your mock-based test will pass for months. Then it will pass right before production. Then production will fail because the real API enforces a constraint that your mock did not, or because the real API mutates state in a way your mock did not, or because the real API returns the new entity in a list endpoint that your mock did not update.

What a stateful API sandbox does differently

A stateful API sandbox keeps state between requests. When you POST a resource, it stores the resource. The next GET returns it. The next list endpoint includes it. The next PATCH updates it. State machines enforce valid transitions. Webhook events fire on state changes.

In other words, the sandbox behaves like the real API behaves, not like a frozen snapshot of one specific request.

That sounds obvious in writing. In practice, almost no testing tools actually do it. Most “sandboxes” are just mock servers with marketing copy.

The test that separates the two

Run this against your current testing setup:

# 1. Create a thing
POST /payments → 201, returns { id: "pay_xyz", status: "pending" }

# 2. Read it back
GET /payments/pay_xyz → 200, returns { id: "pay_xyz", status: "pending" }

# 3. Mutate it
POST /payments/pay_xyz/capture → 200, returns { id: "pay_xyz", status: "captured" }

# 4. Read it back AGAIN
GET /payments/pay_xyz → 200, what does status say?

On a stateful sandbox, the answer to step 4 is captured. On a mock, the answer to step 4 is whatever you happened to configure for that route — usually still pending, because there is no link between the capture call and the get call.

If your testing tool fails this test, it is a mock server, not a sandbox. That is fine. Just know what you have.

A side-by-side comparison

CapabilityMock serverStateful API sandbox
Returns canned responsesYesYes
Persists state across requestsNoYes
Enforces state transitionsNoYes
Fires webhook events on state changesNo (or hardcoded)Yes
Same wire format as real APIOnly for configured pathsAll paths from the spec
Useful for unit testsYesYes
Useful for integration testsLimitedYes
Useful for webhook handler testsNo (no real events)Yes (real events on real transitions)
Useful for “does my flow actually work” testsNoYes

How the popular tools compare

This is a rough map of what the major API testing tools actually are:

  • Postman mock servers — mock. Path-to-response mapping configured per workspace.
  • WireMock — mock. Industry standard for stub-based HTTP testing. Stateful only via custom extensions.
  • Prism (Stoplight) — mock. Generates responses from an OpenAPI spec but does not persist state.
  • Beeceptor — mock. Browser-based mock server with templating.
  • Mockoon — mock. Local desktop mock server.
  • Provider sandboxes (Stripe test mode, Paddle sandbox, Plaid sandbox, etc.) — partial sandboxes. Stateful, but shared, rate-limited, and require provider accounts.
  • FetchSandbox — stateful sandbox. Per-session isolation, full state machines, real webhook events on every transition, generated from the provider's OpenAPI spec.

We've written about each of these tradeoffs in our comparison pages — see vs Postman mock servers, vs WireMock, vs Prism, vs Beeceptor, and vs Mockoon.

When to use a mock anyway

Mocks have a real role and you should keep using them where they fit. Use a mock when:

  • You are testing a single function's behavior in isolation
  • You want a deterministic response without any state coupling
  • You are stubbing a third-party dependency that has no public spec
  • Your test only cares that an HTTP call happens with specific headers

That last category alone covers a huge portion of unit tests. Mocks are still the right answer for them.

When to use a stateful sandbox instead

Use a stateful sandbox when:

  • You are testing a flow that creates and then reads or updates the same resource
  • You are testing webhook handlers
  • You are testing idempotency, retry, or out-of-order delivery
  • You are testing in CI and want isolation from teammates
  • You are onboarding a new engineer and don't want to give them production secrets
  • You are simulating a multi-step business process: subscription lifecycle, order fulfillment, ad campaign creation, knowledge curation

The shorthand: if your test cares about what happens after a request, you need a sandbox, not a mock.

We wrote a longer piece on exactly this distinction: why API integrations break after the first successful request.

The thing nobody talks about: drift

Both mocks and sandboxes have one shared enemy: drift. Your stub said the API returned created_at. The real API now returns createdAt. Your stub said the response was an object. The real API now wraps it in { data: ... }. Your stub knew about 14 fields. The real API has 27.

Mocks drift faster because they are hand-maintained. Every change to the real API is a manual change to the stub. Most teams discover drift in production.

Sandboxes that are generated from the OpenAPI spec drift slower because the spec is the source of truth. When the spec updates, the sandbox updates with it. The drift moves from “weeks of backlog” to “the next deploy.”

That is the entire reason we built FetchSandbox the way we did. Every spec we onboard is the official OpenAPI spec from the provider. When Stripe ships a new endpoint, the sandbox knows about it on the next pull. No manual stub updates.

The honest summary

If you only remember three things from this post:

  1. Mocks are great for unit tests. Stateful sandboxes are great for integration tests. Use both.
  2. If your testing tool cannot pass the “create then read, mutate then read” test, it is a mock, not a sandbox. Know what you have.
  3. Drift is the silent killer. Tools generated from a spec drift slower than tools maintained by hand.

If you want to see what a stateful, OpenAPI-driven sandbox actually feels like, the FetchSandbox catalog has 41 providers ready to go. Pick one and try the create-read-mutate-read test on it. You will know in 30 seconds whether you're looking at a mock or a sandbox.