API Mocking
Overview
A mock is two files on disk: config.yaml (name, port, list of scenarios)
and default.js — a plain Node HTTP server, and the mock itself, not a
wrapper around one. Because it's just code, generating, inspecting, running,
and calling a mock are all local and work for a logged-out guest. Only
sharing it — pushing it to the cloud and deploying a durable URL — needs
postman login.
Local and cloud aren't a choice made once at generate time. Every mock
starts as a local folder; mock push promotes any existing local folder to
the cloud later, whether or not -w was passed at generate. Reach for cloud
only when something other than you needs to hit this mock over the network —
a teammate, a CI job elsewhere, a webhook sender. A purely local mock
answering a postman request on your machine never needs it.
Process
- Generate.
postman mock generate -n NAME --port Nwith no source scaffolds a complete sample cart mock — the fastest way to a server that already answers, useful whenever the point is exercising mock behavior rather than a specific API's shape. Pass a real source —postman mock generate SOURCE -n NAME --port N, whereSOURCEis a collection folder or anopenapi.yaml— when the endpoints need to mirror an actual API. Either form writesconfig.yaml+default.jsintopostman/mocks/NAME/. Adding-w <workspaceId>also creates the mock in that workspace on top of writing the local files — it doesn't replace the local write, and it requires being logged in. - Run it.
postman mock run ./postman/mocks/NAMEstartsMock server started at http://localhost:PORT. If the port inconfig.yamlis taken and--portwasn't passed explicitly, it falls back to a free OS-assigned port instead of erroring — read the real port off that line rather than assuming the configured one. Naming--portexplicitly makes a taken port a hardPort already in useerror instead. - Call it. Plain
postman request localhost:PORT/routereturns the default scenario's response. Two headers change that per-request, with no restart needed:x-mock-scenario: <name>selects a different scenario (the valid names live inconfig.yaml—mock getonly ever shows the default one), andx-mock-response-code: <code>returns that status instead. A wrong route and a wrong scenario name both come back asEndpoint not defined— indistinguishable from the message alone. There's no hot reload: adefault.jsedit does nothing until you Ctrl+C the running server andmock runit again. - Push it, if it needs to leave your machine.
postman mock push ./postman/mocks/NAMEis safe to re-run —Createdthe first time,Updatedafter. It returns a cloud ID that is a new identifier, not theidalready sitting inconfig.yaml— see The three identifiers below. It also modifies.postman/resources.yaml; commit that change. - Deploy it, for a URL that outlives your terminal.
postman mock deploy CLOUD_ID -s SLUG -y --auto-deployprintshttps://SLUG.mock.<team-domain>.postman.dev. Deployed private by default — callers need an API key — add--publiconly when the mock should be reachable by anyone with the URL.-yalone accepts private/auto-deploy-off; without--auto-deploy, a laterpushdoesn't change what's actually being served until youdeployagain. - See who's calling it.
postman mock get CLOUD_ID --jsonreturns.mockServerId; feed that intopostman mock log MOCK_SERVER_ID --jsonfor call entries. An empty log means the URL genuinely hasn't been hit — a rejected caller still shows up, recorded with its failing status code. - Tear down.
postman mock delete ./path --yes(local) orpostman mock delete CLOUD_ID --yes(cloud) — both refuse while the thing is still alive, so stop the local run or bring the deployment down first. Cloud delete doesn't touch.postman/resources.yaml; drop that line by hand afterward or the repo keeps claiming a mock that's gone.
To point real request/assertion runs at a mock instead of hand-editing
base-URL variables, see the api-testing skill's --use-mock/--mock
flags on collection run.
The three identifiers
config.yaml's local id, the cloud ID push returns, and the
mockServerId from get CLOUD_ID --json are three different values, in the
order they become available. Only the second and third are lookups —
push is a creation, not a promotion, so passing the config.yaml id to any
cloud command is passing the wrong key, not a stale one.
Critical Rules
- Every gated cloud command fails the same way:
Authentication required. Run postman login or provide --api-key, exit 1, nothing half-done. Whether a command is gated is decided by what you pass it, not the verb —mock get/mock runtake either a local path (ungated) or a cloud ID (gated);mock listis gated only when called with no path. pushis what moves an existing local mock to the cloud —-watgeneratetime is optional, not a fork you must choose up front. A mock built as a guest can be pushed and deployed later with no rework.--publicondeployis the one action here with real exposure — it stands up a server anyone with the URL can hit, with no API key. The default (private) is the safe one; confirm intent before adding it.- Don't reuse the
config.yamlid for a cloud command, and don't invent amock generateflag for regenerating in place. The reference for this CLI documents editingdefault.jsand restarting as the way to change a running mock's behavior — no in-place "update from source" verb is documented. Runpostman mock generate -hbefore assuming one exists rather than guessing a flag name. -w/--workspaceonly exists ongenerate,list,push, anddeploy.get,run,log, anddeletealready take a path or an id that says where the mock is — there's nothing left for-wto resolve on those.
Verification
A mock isn't done because generate or run exited 0 — hit it with
postman request and check the actual status/body, or mock get CLOUD_ID --json for a cloud one, then state whether it ended up local or cloud, and
(if deployed) private or public. For a scenario/status-code check, confirm
the header actually changed the response — a typo'd scenario name returns the same
Endpoint not defined as a wrong route, so a passing exit code alone proves
nothing.


