Update to Postman
Snapshot Oct 26, 2026 · 18:05 UTC · version 0.5.0
Collection source: downloaded plugin package.
Instructions updated for api-simulation
Skill instructions — Now says: one, and read the `<name>.context.md` beside it first: it holds the commands, the preconditions and the failures earlier runs hit, so reading it costs less...
Observed in instructions or declared skills. Runtime behavior has not been tested.
Up to 3 plugins free · no card required.
All fields and original values.
Skill instructions
Oct 24, 2026 · 12:56 UTC
one. One request through the changed path proves a change; build failure variants only when asked how the code fails or when it must survive a failure. Start it in the background with an explicit port, its log in a file: Without `--port`...
Oct 26, 2026 · 18:05 UTC
one, and read the `<name>.context.md` beside it first: it holds the commands, the preconditions and the failures earlier runs hit, so reading it costs less than rebuilding any of that from the `.sim.yaml` and the handlers. One request th...
Supporting files
Oct 24, 2026 · 12:56 UTC
[{"relative_path":"reference/sim_yaml_schema.md","size_in_bytes":2316}]
Oct 26, 2026 · 18:05 UTC
[{"relative_path":"reference/context_file.md","size_in_bytes":9005},{"relative_path":"reference/sim_yaml_schema.md","size_in_bytes":3833}]
Compare saved observations
Download comparison JSONSKILL.md text changes
− removed · + added
--- before +++ after @@ -16,9 +16,12 @@ HTTP, the same way in CI, and its log shows what each dependency was asked. Do only what the task needs. If a `.sim.yaml` in `postman/simulations/` -already covers it, run that one. One request through the changed path proves -a change; build failure variants only when asked how the code fails or when -it must survive a failure. +already covers it, run that one, and read the `<name>.context.md` beside it +first: it holds the commands, the preconditions and the failures earlier runs +hit, so reading it costs less than rebuilding any of that from the `.sim.yaml` +and the handlers. One request through the changed path proves a change; build +failure variants only when asked how the code fails or when it must survive a +failure. `postman simulation` needs CLI 1.70.0 or later (`postman --version`; an older CLI answers `postman simulation -h` with its general help). @@ -34,6 +37,11 @@ the contract will do; one that invents responses can send the caller down a path the real service never would. In a mock you build, answer `501` for calls this path doesn't make: a `404` reads to the caller like a real "not found". +- **Bring in each mock you don't own as a dependency first, then build the + simulation over them.** `postman dependency add mock <name-or-id>` declares + it in `.postman/resources.yaml` and materialises it under + `postman/.dependencies/`, and the member's `path:` points there; `-w + <workspace>` resolves a name from the workspace that owns it. - **Prefix each mock's `pm.state` keys with its name.** As of CLI 1.73.0, members of a local run read each other's keys, so two mocks storing `orders` overwrite each other. @@ -41,18 +49,17 @@ ## Running it The run is a server that never exits, so a foreground command never returns. -Start it in the background with an explicit port, its log in a file: +Start it in the background, its log in a file: ```bash postman simulation run postman/simulations/checkout-dev.sim.yaml --port 4900 --output ndjson > sim.ndjson 2> sim.err & ``` -Without `--port`, a busy 3000 silently becomes a random port and every base -URL points at nothing. It's up when `sim.ndjson` has a `listening` event; a -start-up error is in `sim.err`. It listens on 127.0.0.1 only, so a caller in -a container or VM can't reach it. Stop it with -`pkill -INT -f "simulation run <file>"`; `kill $!` leaves it running, -because the `postman` launcher ignores the signal. Nothing reloads: restart +`--port` is optional. It's up when `sim.ndjson` has a `listening` event; a +start-up error is in `sim.err`. That event carries the bound port and each +member's address, so take the base URLs from it rather than from the port you +asked for. Stop it with +`pkill -INT -f "simulation run .*<file>.sim.yaml"`. Nothing reloads: restart it after a mock edit. Point the caller at it without changing what the code does once deployed. @@ -60,10 +67,30 @@ `https://catalog.internal.example.com/v2` becomes `http://127.0.0.1:4900/catalog/v2`; a dropped `/v2` is the usual cause of a `404`. A hard-coded base URL should read an environment variable with -today's value as the default. If the code mustn't change at all, -`simulation run --proxy` reaches the members through `HTTPS_PROXY` instead; -it applies no conditions, and passes any other host through to the real -service. +today's value as the default. If the code mustn't change at all, run it +behind the proxy instead, below. + +## Through a proxy, when no base URL can change + +`simulation run <file.sim.yaml> --proxy` puts the members behind a local +forward proxy that answers for the dependencies' own hostnames, so the code +keeps the base URLs it ships with. Any other host passes through to the real +service. Reach for it when hostnames are hard-coded, built from config the +change shouldn't touch, or owned by an SDK — and because nothing it answers +for has to resolve, an internal hostname with no DNS record works. + +Read `postman simulation run --help` before driving it. The flags, what the +caller's own process needs in order to reach the proxy, and what to do about a +client that ignores it are all there and change with the CLI, so take them +from the command rather than from here. + +Two things decide whether a proxied run proves anything. A member with no +`origin:` in the `.sim.yaml` is never matched, so its traffic reaches the real +service and a run can come up having intercepted nothing — `simulation create` +copies that field from the mock's manifest, so editing the manifest alone +won't fix it ([reference/sim_yaml_schema.md](reference/sim_yaml_schema.md)). +And conditions don't apply here: member `scenarios` are ignored, so failures +need the one-port run. ## Reading the log @@ -102,10 +129,27 @@ caller did, and check the other members' logs for side effects, such as stock reserved and never released. +## Its context document + +Every simulation is created with a `<name>.context.md` beside it, holding what +running this one has taught: the commands that start it and prove it's up, the +preconditions and what breaks when one fails, what it takes for granted about +the dependencies themselves, the data seeded to test with, the failures earlier +runs already hit, and what a passing run still doesn't prove. The `.sim.yaml` says what the simulation is, not how it behaves, so +this is the file that saves a session the search. A new one is mostly +`@todo`s, which are the questions a first real run answers. + +Every line passes one test — the repo doesn't already state it — so it stays +about a screenful, and a claim carries the date and the run that established +it, because the log it came from isn't committed. Its sections and conventions +are in [reference/context_file.md](reference/context_file.md); read that +before writing it back. + ## Keeping it -Commit your own mocks, the `.sim.yaml` and what `postman dependency add` -changed, so the next session or CI reruns it in one command. Don't commit +Commit your own mocks, the `.sim.yaml`, its context document and what +`postman dependency add` changed, so the next session or CI reruns it in one +command. Don't commit `postman/.dependencies/`: a copy goes stale when its owner updates theirs, and `postman dependency install` restores it. Don't commit `sim.ndjson`: the CLI redacts common auth headers and fields, but other headers and bodies are @@ -136,3 +180,9 @@ your code against these stand-ins rather than the real services, what still needs the real service before release, and where each mock came from, including when you skipped the owner's. + +Then write the run back into `<name>.context.md`, so the next session starts +where this one ended: the `@todo`s it answered, whatever it found wrong, a +precondition you had to discover, what broke and why, and which members served +or stayed silent — the last is a line every run adds, so a member silent across +several runs reads as a pattern rather than a one-off.
Full technical diff · 2 changed fields
changed /included_files
[
{
"relative_path": "reference/sim_yaml_schema.md",
"size_in_bytes": 2316
}
][
{
"relative_path": "reference/context_file.md",
"size_in_bytes": 9005
},
{
"relative_path": "reference/sim_yaml_schema.md",
"size_in_bytes": 3833
}
]changed /skill_md_contents
"---\nname: api-simulation\ndescription: Runs your code for real against stand-ins for the HTTP services it calls, served together as one environment on one local port or one deployed URL, whether that code is a service you're changing, a frontend, a test suite or a demo. Use when you add or change code that calls other services and need to run it, test it, prove a fix or reproduce an upstream failure (timeouts, 5xx, 409, 429) end to end, locally or in CI, without the real services because they're unreachable, need credentials, cost money, have side effects or don't exist yet. Also answers what happens to a request, or to the data it writes, when a service it calls goes down, is slow or returns errors (\"what happens to a booking if the email service is down?\"), by running each failure instead of reading the code. Applies even when nobody says mock or simulation. To give a frontend or another team a stand-in for an API, use api-mocking. Covers `postman simulation`.\n---\n\n# API Simulation\n\nA simulation serves several mocks as one environment, each reached by its\nrouteKey: as a path prefix by default, or as an `x-mock-slug` header when the\ncaller's paths can't change.\n\nRun your code against it rather than stubbing its HTTP client in tests or\ncalling the real services. A stub skips the client, config, timeouts and\nerror handling that will run in production; the real services need\ncredentials and leave side effects. A simulation runs that code over real\nHTTP, the same way in CI, and its log shows what each dependency was asked.\n\nDo only what the task needs. If a `.sim.yaml` in `postman/simulations/`\nalready covers it, run that one. One request through the changed path proves\na change; build failure variants only when asked how the code fails or when\nit must survive a failure.\n\n`postman simulation` needs CLI 1.70.0 or later (`postman --version`; an older\nCLI answers `postman simulation -h` with its general help).\n\n## Building it\n\n- **Members are the code's HTTP dependencies.** Databases, queues and caches\n aren't; run them locally. **api-discovery** can find calls made through\n shared code; ask about the repo by its `git remote` name, because a close\n name matches another repo.\n- **Each member needs a mock: see `api-mocking`,** which looks for the owning\n team's published mock before building one. For a question, one built from\n the contract will do; one that invents responses can send the caller down a\n path the real service never would. In a mock you build, answer `501` for calls this path\n doesn't make: a `404` reads to the caller like a real \"not found\".\n- **Prefix each mock's `pm.state` keys with its name.** As of CLI 1.73.0,\n members of a local run read each other's keys, so two mocks storing\n `orders` overwrite each other.\n\n## Running it\n\nThe run is a server that never exits, so a foreground command never returns.\nStart it in the background with an explicit port, its log in a file:\n\n```bash\npostman simulation run postman/simulations/checkout-dev.sim.yaml --port 4900 --output ndjson > sim.ndjson 2> sim.err &\n```\n\nWithout `--port`, a busy 3000 silently becomes a random port and every base\nURL points at nothing. It's up when `sim.ndjson` has a `listening` event; a\nstart-up error is in `sim.err`. It listens on 127.0.0.1 only, so a caller in\na container or VM can't reach it. Stop it with\n`pkill -INT -f \"simulation run <file>\"`; `kill $!` leaves it running,\nbecause the `postman` launcher ignores the signal. Nothing reloads: restart\nit after a mock edit.\n\nPoint the caller at it without changing what the code does once deployed.\nUnder path routing, swap only the host and keep the path:\n`https://catalog.internal.example.com/v2` becomes\n`http://127.0.0.1:4900/catalog/v2`; a dropped `/v2` is the usual cause of a\n`404`. A hard-coded base URL should read an environment variable with\ntoday's value as the default. If the code mustn't change at all,\n`simulation run --proxy` reaches the members through `HTTPS_PROXY` instead;\nit applies no conditions, and passes any other host through to the real\nservice.\n\n## Reading the log\n\nA passing test command doesn't show the dependency path ran: read\n`sim.ndjson`. A member with no `request` events isn't wired or isn't on this\npath. Some answers come from the simulation itself and mean wiring, not code:\n\n- `404 Unknown simulation member`: a base URL lost its routeKey, or a client\n sent the wrong `x-mock-slug`.\n- `501`, or a generated mock's `404 Endpoint not defined`: a call the mock\n doesn't model yet.\n- `502 Proxy error`: the member's process died, usually an async throw in a\n mock without `interceptRequests: true`. It stays down and logs nothing\n until you restart; run that mock alone with `postman mock run` to see why.\n\n## When a dependency goes down\n\nRun it rather than reason from the code: each way of going down takes a\ndifferent path through the caller, and a stub skips the client code that\npicks the path. Fail the one dependency in each shape that matters, a run\neach, with the others answering normally:\n\n- **Unreachable:** point its base URL at a port nothing listens on.\n- **Hanging:** give its member a `latency` condition longer than the\n client's timeout. If the client sets none, that is the finding: Node's\n `fetch` waits about five minutes, so say so rather than wait it out.\n- **An error with a JSON body:** the `error` condition.\n- **An error with an HTML body,** as proxies send: a copy of its mock whose\n default handler answers `500` with HTML. No condition can do this.\n\nOnly `overrides.conditions` on a member change it. Members always serve\ntheir default handler and ignore `x-mock-scenario`, and a `scenarios` entry\nwith just a `path`, as the Postman app writes, does nothing. Fields and the\nother conditions are in [reference/sim_yaml_schema.md](reference/sim_yaml_schema.md). An injected\nfailure never reaches the mock and isn't logged, so judge it by what the\ncaller did, and check the other members' logs for side effects, such as\nstock reserved and never released.\n\n## Keeping it\n\nCommit your own mocks, the `.sim.yaml` and what `postman dependency add`\nchanged, so the next session or CI reruns it in one command. Don't commit\n`postman/.dependencies/`: a copy goes stale when its owner updates theirs,\nand `postman dependency install` restores it. Don't commit `sim.ndjson`: the\nCLI redacts common auth headers and fields, but other headers and bodies are\nlogged as sent. In CI, `postman dependency install` needs `POSTMAN_API_KEY`,\nand `postman collection run <collection> --simulation <file> --port <n>`\nstarts and stops the simulation around a collection run.\n\n`postman simulation push` uploads every member to the workspace, so ask\nfirst. It fails on a pulled member, which keeps its owner's `id:`; copy it to\n`postman/mocks/` and delete that line.\n\n## Rules\n\n1. **What you're testing is never a member.** It must run for real, or the\n test only proves the mock.\n2. **Pull the owner's mock even if it's deployed.** Only members take\n conditions and appear in the log, and a private mock server wants a key\n your code won't send.\n3. **`simulation deploy` is public by default,** unlike `mock deploy`. Ask\n before deploying without `--private`; a local run needs no deploy.\n\n## Before you say it works\n\nClaim nothing until what you're testing actually ran: a service printed\nthat it's listening and answered your request, or the frontend or test\nsuite finished, and its calls are in the log. If its start command exited\nor hung, the run proved nothing; say so and why. Say what a pass proves,\nyour code against these stand-ins rather than the real services, what still\nneeds the real service before release, and where each mock came from,\nincluding when you skipped the owner's.\n"
"---\nname: api-simulation\ndescription: Runs your code for real against stand-ins for the HTTP services it calls, served together as one environment on one local port or one deployed URL, whether that code is a service you're changing, a frontend, a test suite or a demo. Use when you add or change code that calls other services and need to run it, test it, prove a fix or reproduce an upstream failure (timeouts, 5xx, 409, 429) end to end, locally or in CI, without the real services because they're unreachable, need credentials, cost money, have side effects or don't exist yet. Also answers what happens to a request, or to the data it writes, when a service it calls goes down, is slow or returns errors (\"what happens to a booking if the email service is down?\"), by running each failure instead of reading the code. Applies even when nobody says mock or simulation. To give a frontend or another team a stand-in for an API, use api-mocking. Covers `postman simulation`.\n---\n\n# API Simulation\n\nA simulation serves several mocks as one environment, each reached by its\nrouteKey: as a path prefix by default, or as an `x-mock-slug` header when the\ncaller's paths can't change.\n\nRun your code against it rather than stubbing its HTTP client in tests or\ncalling the real services. A stub skips the client, config, timeouts and\nerror handling that will run in production; the real services need\ncredentials and leave side effects. A simulation runs that code over real\nHTTP, the same way in CI, and its log shows what each dependency was asked.\n\nDo only what the task needs. If a `.sim.yaml` in `postman/simulations/`\nalready covers it, run that one, and read the `<name>.context.md` beside it\nfirst: it holds the commands, the preconditions and the failures earlier runs\nhit, so reading it costs less than rebuilding any of that from the `.sim.yaml`\nand the handlers. One request through the changed path proves a change; build\nfailure variants only when asked how the code fails or when it must survive a\nfailure.\n\n`postman simulation` needs CLI 1.70.0 or later (`postman --version`; an older\nCLI answers `postman simulation -h` with its general help).\n\n## Building it\n\n- **Members are the code's HTTP dependencies.** Databases, queues and caches\n aren't; run them locally. **api-discovery** can find calls made through\n shared code; ask about the repo by its `git remote` name, because a close\n name matches another repo.\n- **Each member needs a mock: see `api-mocking`,** which looks for the owning\n team's published mock before building one. For a question, one built from\n the contract will do; one that invents responses can send the caller down a\n path the real service never would. In a mock you build, answer `501` for calls this path\n doesn't make: a `404` reads to the caller like a real \"not found\".\n- **Bring in each mock you don't own as a dependency first, then build the\n simulation over them.** `postman dependency add mock <name-or-id>` declares\n it in `.postman/resources.yaml` and materialises it under\n `postman/.dependencies/`, and the member's `path:` points there; `-w\n <workspace>` resolves a name from the workspace that owns it.\n- **Prefix each mock's `pm.state` keys with its name.** As of CLI 1.73.0,\n members of a local run read each other's keys, so two mocks storing\n `orders` overwrite each other.\n\n## Running it\n\nThe run is a server that never exits, so a foreground command never returns.\nStart it in the background, its log in a file:\n\n```bash\npostman simulation run postman/simulations/checkout-dev.sim.yaml --port 4900 --output ndjson > sim.ndjson 2> sim.err &\n```\n\n`--port` is optional. It's up when `sim.ndjson` has a `listening` event; a\nstart-up error is in `sim.err`. That event carries the bound port and each\nmember's address, so take the base URLs from it rather than from the port you\nasked for. Stop it with\n`pkill -INT -f \"simulation run .*<file>.sim.yaml\"`. Nothing reloads: restart\nit after a mock edit.\n\nPoint the caller at it without changing what the code does once deployed.\nUnder path routing, swap only the host and keep the path:\n`https://catalog.internal.example.com/v2` becomes\n`http://127.0.0.1:4900/catalog/v2`; a dropped `/v2` is the usual cause of a\n`404`. A hard-coded base URL should read an environment variable with\ntoday's value as the default. If the code mustn't change at all, run it\nbehind the proxy instead, below.\n\n## Through a proxy, when no base URL can change\n\n`simulation run <file.sim.yaml> --proxy` puts the members behind a local\nforward proxy that answers for the dependencies' own hostnames, so the code\nkeeps the base URLs it ships with. Any other host passes through to the real\nservice. Reach for it when hostnames are hard-coded, built from config the\nchange shouldn't touch, or owned by an SDK — and because nothing it answers\nfor has to resolve, an internal hostname with no DNS record works.\n\nRead `postman simulation run --help` before driving it. The flags, what the\ncaller's own process needs in order to reach the proxy, and what to do about a\nclient that ignores it are all there and change with the CLI, so take them\nfrom the command rather than from here.\n\nTwo things decide whether a proxied run proves anything. A member with no\n`origin:` in the `.sim.yaml` is never matched, so its traffic reaches the real\nservice and a run can come up having intercepted nothing — `simulation create`\ncopies that field from the mock's manifest, so editing the manifest alone\nwon't fix it ([reference/sim_yaml_schema.md](reference/sim_yaml_schema.md)).\nAnd conditions don't apply here: member `scenarios` are ignored, so failures\nneed the one-port run.\n\n## Reading the log\n\nA passing test command doesn't show the dependency path ran: read\n`sim.ndjson`. A member with no `request` events isn't wired or isn't on this\npath. Some answers come from the simulation itself and mean wiring, not code:\n\n- `404 Unknown simulation member`: a base URL lost its routeKey, or a client\n sent the wrong `x-mock-slug`.\n- `501`, or a generated mock's `404 Endpoint not defined`: a call the mock\n doesn't model yet.\n- `502 Proxy error`: the member's process died, usually an async throw in a\n mock without `interceptRequests: true`. It stays down and logs nothing\n until you restart; run that mock alone with `postman mock run` to see why.\n\n## When a dependency goes down\n\nRun it rather than reason from the code: each way of going down takes a\ndifferent path through the caller, and a stub skips the client code that\npicks the path. Fail the one dependency in each shape that matters, a run\neach, with the others answering normally:\n\n- **Unreachable:** point its base URL at a port nothing listens on.\n- **Hanging:** give its member a `latency` condition longer than the\n client's timeout. If the client sets none, that is the finding: Node's\n `fetch` waits about five minutes, so say so rather than wait it out.\n- **An error with a JSON body:** the `error` condition.\n- **An error with an HTML body,** as proxies send: a copy of its mock whose\n default handler answers `500` with HTML. No condition can do this.\n\nOnly `overrides.conditions` on a member change it. Members always serve\ntheir default handler and ignore `x-mock-scenario`, and a `scenarios` entry\nwith just a `path`, as the Postman app writes, does nothing. Fields and the\nother conditions are in [reference/sim_yaml_schema.md](reference/sim_yaml_schema.md). An injected\nfailure never reaches the mock and isn't logged, so judge it by what the\ncaller did, and check the other members' logs for side effects, such as\nstock reserved and never released.\n\n## Its context document\n\nEvery simulation is created with a `<name>.context.md` beside it, holding what\nrunning this one has taught: the commands that start it and prove it's up, the\npreconditions and what breaks when one fails, what it takes for granted about\nthe dependencies themselves, the data seeded to test with, the failures earlier\nruns already hit, and what a passing run still doesn't prove. The `.sim.yaml` says what the simulation is, not how it behaves, so\nthis is the file that saves a session the search. A new one is mostly\n`@todo`s, which are the questions a first real run answers.\n\nEvery line passes one test — the repo doesn't already state it — so it stays\nabout a screenful, and a claim carries the date and the run that established\nit, because the log it came from isn't committed. Its sections and conventions\nare in [reference/context_file.md](reference/context_file.md); read that\nbefore writing it back.\n\n## Keeping it\n\nCommit your own mocks, the `.sim.yaml`, its context document and what\n`postman dependency add` changed, so the next session or CI reruns it in one\ncommand. Don't commit\n`postman/.dependencies/`: a copy goes stale when its owner updates theirs,\nand `postman dependency install` restores it. Don't commit `sim.ndjson`: the\nCLI redacts common auth headers and fields, but other headers and bodies are\nlogged as sent. In CI, `postman dependency install` needs `POSTMAN_API_KEY`,\nand `postman collection run <collection> --simulation <file> --port <n>`\nstarts and stops the simulation around a collection run.\n\n`postman simulation push` uploads every member to the workspace, so ask\nfirst. It fails on a pulled member, which keeps its owner's `id:`; copy it to\n`postman/mocks/` and delete that line.\n\n## Rules\n\n1. **What you're testing is never a member.** It must run for real, or the\n test only proves the mock.\n2. **Pull the owner's mock even if it's deployed.** Only members take\n conditions and appear in the log, and a private mock server wants a key\n your code won't send.\n3. **`simulation deploy` is public by default,** unlike `mock deploy`. Ask\n before deploying without `--private`; a local run needs no deploy.\n\n## Before you say it works\n\nClaim nothing until what you're testing actually ran: a service printed\nthat it's listening and answered your request, or the frontend or test\nsuite finished, and its calls are in the log. If its start command exited\nor hung, the run proved nothing; say so and why. Say what a pass proves,\nyour code against these stand-ins rather than the real services, what still\nneeds the real service before release, and where each mock came from,\nincluding when you skipped the owner's.\n\nThen write the run back into `<name>.context.md`, so the next session starts\nwhere this one ended: the `@todo`s it answered, whatever it found wrong, a\nprecondition you had to discover, what broke and why, and which members served\nor stayed silent — the last is a line every run adds, so a member silent across\nseveral runs reads as a pattern rather than a one-off.\n"
Full snapshot data
{
"description": "Runs your code for real against stand-ins for the HTTP services it calls, served together as one environment on one local port or one deployed URL, whether that code is a service you're changing, a frontend, a test suite or a demo. Use when you add or change code that calls other services and need to run it, test it, prove a fix or reproduce an upstream failure (timeouts, 5xx, 409, 429) end to end, locally or in CI, without the real services because they're unreachable, need credentials, cost money, have side effects or don't exist yet. Also answers what happens to a request, or to the data it writes, when a service it calls goes down, is slow or returns errors (\"what happens to a booking if the email service is down?\"), by running each failure instead of reading the code. Applies even when nobody says mock or simulation. To give a frontend or another team a stand-in for an API, use api-mocking. Covers `postman simulation`.",
"included_files": [
{
"relative_path": "reference/context_file.md",
"size_in_bytes": 9005
},
{
"relative_path": "reference/sim_yaml_schema.md",
"size_in_bytes": 3833
}
],
"name": "api-simulation",
"skill_md_contents": "---\nname: api-simulation\ndescription: Runs your code for real against stand-ins for the HTTP services it calls, served together as one environment on one local port or one deployed URL, whether that code is a service you're changing, a frontend, a test suite or a demo. Use when you add or change code that calls other services and need to run it, test it, prove a fix or reproduce an upstream failure (timeouts, 5xx, 409, 429) end to end, locally or in CI, without the real services because they're unreachable, need credentials, cost money, have side effects or don't exist yet. Also answers what happens to a request, or to the data it writes, when a service it calls goes down, is slow or returns errors (\"what happens to a booking if the email service is down?\"), by running each failure instead of reading the code. Applies even when nobody says mock or simulation. To give a frontend or another team a stand-in for an API, use api-mocking. Covers `postman simulation`.\n---\n\n# API Simulation\n\nA simulation serves several mocks as one environment, each reached by its\nrouteKey: as a path prefix by default, or as an `x-mock-slug` header when the\ncaller's paths can't change.\n\nRun your code against it rather than stubbing its HTTP client in tests or\ncalling the real services. A stub skips the client, config, timeouts and\nerror handling that will run in production; the real services need\ncredentials and leave side effects. A simulation runs that code over real\nHTTP, the same way in CI, and its log shows what each dependency was asked.\n\nDo only what the task needs. If a `.sim.yaml` in `postman/simulations/`\nalready covers it, run that one, and read the `<name>.context.md` beside it\nfirst: it holds the commands, the preconditions and the failures earlier runs\nhit, so reading it costs less than rebuilding any of that from the `.sim.yaml`\nand the handlers. One request through the changed path proves a change; build\nfailure variants only when asked how the code fails or when it must survive a\nfailure.\n\n`postman simulation` needs CLI 1.70.0 or later (`postman --version`; an older\nCLI answers `postman simulation -h` with its general help).\n\n## Building it\n\n- **Members are the code's HTTP dependencies.** Databases, queues and caches\n aren't; run them locally. **api-discovery** can find calls made through\n shared code; ask about the repo by its `git remote` name, because a close\n name matches another repo.\n- **Each member needs a mock: see `api-mocking`,** which looks for the owning\n team's published mock before building one. For a question, one built from\n the contract will do; one that invents responses can send the caller down a\n path the real service never would. In a mock you build, answer `501` for calls this path\n doesn't make: a `404` reads to the caller like a real \"not found\".\n- **Bring in each mock you don't own as a dependency first, then build the\n simulation over them.** `postman dependency add mock <name-or-id>` declares\n it in `.postman/resources.yaml` and materialises it under\n `postman/.dependencies/`, and the member's `path:` points there; `-w\n <workspace>` resolves a name from the workspace that owns it.\n- **Prefix each mock's `pm.state` keys with its name.** As of CLI 1.73.0,\n members of a local run read each other's keys, so two mocks storing\n `orders` overwrite each other.\n\n## Running it\n\nThe run is a server that never exits, so a foreground command never returns.\nStart it in the background, its log in a file:\n\n```bash\npostman simulation run postman/simulations/checkout-dev.sim.yaml --port 4900 --output ndjson > sim.ndjson 2> sim.err &\n```\n\n`--port` is optional. It's up when `sim.ndjson` has a `listening` event; a\nstart-up error is in `sim.err`. That event carries the bound port and each\nmember's address, so take the base URLs from it rather than from the port you\nasked for. Stop it with\n`pkill -INT -f \"simulation run .*<file>.sim.yaml\"`. Nothing reloads: restart\nit after a mock edit.\n\nPoint the caller at it without changing what the code does once deployed.\nUnder path routing, swap only the host and keep the path:\n`https://catalog.internal.example.com/v2` becomes\n`http://127.0.0.1:4900/catalog/v2`; a dropped `/v2` is the usual cause of a\n`404`. A hard-coded base URL should read an environment variable with\ntoday's value as the default. If the code mustn't change at all, run it\nbehind the proxy instead, below.\n\n## Through a proxy, when no base URL can change\n\n`simulation run <file.sim.yaml> --proxy` puts the members behind a local\nforward proxy that answers for the dependencies' own hostnames, so the code\nkeeps the base URLs it ships with. Any other host passes through to the real\nservice. Reach for it when hostnames are hard-coded, built from config the\nchange shouldn't touch, or owned by an SDK — and because nothing it answers\nfor has to resolve, an internal hostname with no DNS record works.\n\nRead `postman simulation run --help` before driving it. The flags, what the\ncaller's own process needs in order to reach the proxy, and what to do about a\nclient that ignores it are all there and change with the CLI, so take them\nfrom the command rather than from here.\n\nTwo things decide whether a proxied run proves anything. A member with no\n`origin:` in the `.sim.yaml` is never matched, so its traffic reaches the real\nservice and a run can come up having intercepted nothing — `simulation create`\ncopies that field from the mock's manifest, so editing the manifest alone\nwon't fix it ([reference/sim_yaml_schema.md](reference/sim_yaml_schema.md)).\nAnd conditions don't apply here: member `scenarios` are ignored, so failures\nneed the one-port run.\n\n## Reading the log\n\nA passing test command doesn't show the dependency path ran: read\n`sim.ndjson`. A member with no `request` events isn't wired or isn't on this\npath. Some answers come from the simulation itself and mean wiring, not code:\n\n- `404 Unknown simulation member`: a base URL lost its routeKey, or a client\n sent the wrong `x-mock-slug`.\n- `501`, or a generated mock's `404 Endpoint not defined`: a call the mock\n doesn't model yet.\n- `502 Proxy error`: the member's process died, usually an async throw in a\n mock without `interceptRequests: true`. It stays down and logs nothing\n until you restart; run that mock alone with `postman mock run` to see why.\n\n## When a dependency goes down\n\nRun it rather than reason from the code: each way of going down takes a\ndifferent path through the caller, and a stub skips the client code that\npicks the path. Fail the one dependency in each shape that matters, a run\neach, with the others answering normally:\n\n- **Unreachable:** point its base URL at a port nothing listens on.\n- **Hanging:** give its member a `latency` condition longer than the\n client's timeout. If the client sets none, that is the finding: Node's\n `fetch` waits about five minutes, so say so rather than wait it out.\n- **An error with a JSON body:** the `error` condition.\n- **An error with an HTML body,** as proxies send: a copy of its mock whose\n default handler answers `500` with HTML. No condition can do this.\n\nOnly `overrides.conditions` on a member change it. Members always serve\ntheir default handler and ignore `x-mock-scenario`, and a `scenarios` entry\nwith just a `path`, as the Postman app writes, does nothing. Fields and the\nother conditions are in [reference/sim_yaml_schema.md](reference/sim_yaml_schema.md). An injected\nfailure never reaches the mock and isn't logged, so judge it by what the\ncaller did, and check the other members' logs for side effects, such as\nstock reserved and never released.\n\n## Its context document\n\nEvery simulation is created with a `<name>.context.md` beside it, holding what\nrunning this one has taught: the commands that start it and prove it's up, the\npreconditions and what breaks when one fails, what it takes for granted about\nthe dependencies themselves, the data seeded to test with, the failures earlier\nruns already hit, and what a passing run still doesn't prove. The `.sim.yaml` says what the simulation is, not how it behaves, so\nthis is the file that saves a session the search. A new one is mostly\n`@todo`s, which are the questions a first real run answers.\n\nEvery line passes one test — the repo doesn't already state it — so it stays\nabout a screenful, and a claim carries the date and the run that established\nit, because the log it came from isn't committed. Its sections and conventions\nare in [reference/context_file.md](reference/context_file.md); read that\nbefore writing it back.\n\n## Keeping it\n\nCommit your own mocks, the `.sim.yaml`, its context document and what\n`postman dependency add` changed, so the next session or CI reruns it in one\ncommand. Don't commit\n`postman/.dependencies/`: a copy goes stale when its owner updates theirs,\nand `postman dependency install` restores it. Don't commit `sim.ndjson`: the\nCLI redacts common auth headers and fields, but other headers and bodies are\nlogged as sent. In CI, `postman dependency install` needs `POSTMAN_API_KEY`,\nand `postman collection run <collection> --simulation <file> --port <n>`\nstarts and stops the simulation around a collection run.\n\n`postman simulation push` uploads every member to the workspace, so ask\nfirst. It fails on a pulled member, which keeps its owner's `id:`; copy it to\n`postman/mocks/` and delete that line.\n\n## Rules\n\n1. **What you're testing is never a member.** It must run for real, or the\n test only proves the mock.\n2. **Pull the owner's mock even if it's deployed.** Only members take\n conditions and appear in the log, and a private mock server wants a key\n your code won't send.\n3. **`simulation deploy` is public by default,** unlike `mock deploy`. Ask\n before deploying without `--private`; a local run needs no deploy.\n\n## Before you say it works\n\nClaim nothing until what you're testing actually ran: a service printed\nthat it's listening and answered your request, or the frontend or test\nsuite finished, and its calls are in the log. If its start command exited\nor hung, the run proved nothing; say so and why. Say what a pass proves,\nyour code against these stand-ins rather than the real services, what still\nneeds the real service before release, and where each mock came from,\nincluding when you skipped the owner's.\n\nThen write the run back into `<name>.context.md`, so the next session starts\nwhere this one ended: the `@todo`s it answered, whatever it found wrong, a\nprecondition you had to discover, what broke and why, and which members served\nor stayed silent — the last is a line every run adds, so a member silent across\nseveral runs reads as a pattern rather than a one-off.\n"
}SHA-256 of public snapshot: 1a9338a1a8e68680918783e3fac75c23aa66a2dcc63701290881a5dc91002dbf