Turn a Bruno or Postman Run Into a Live Sequence Diagram
Written by Ahmed at Analyst Engineering, a Senior Technical Business Analyst with 10+ years in banking and payments delivery.
Key takeaways
- A collection run already contains everything a sequence diagram needs: an ordered list of requests, responses, status codes, and timings.
- Ten lines in a post-response script turn every Bruno or Postman run into a diagram input, with no extra tooling.
- newman run with the json reporter writes a complete machine readable trace of the run, which a model transcribes into Mermaid in one pass.
- A diagram regenerated by CI on every pipeline run is documentation that cannot go stale, because it is rebuilt from a passing test.
- Attaching a generated diagram to a pull request explains an integration change to reviewers who will never read the collection.
A Bruno or Postman collection run already contains everything a sequence diagram needs: an ordered list of requests, responses, status codes, and timings. Capture that with a ten line post-response script or the newman JSON reporter, hand it to a model, and you get an accurate Mermaid sequence diagram of the flow as it actually runs, regenerated on every pipeline execution.
Analysts run collections constantly. We run them to understand a new API, to validate a fix, to demonstrate a flow in a refinement session. Then we close the runner and the only thing left is a screenshot in a ticket.
That run was a full trace of the integration, and throwing it away is a waste. Ten lines of script turn every run into a diagram, and CI turns that diagram into documentation that cannot go stale, because it is rebuilt from a test that passed. This is the second evidence source in the diagrams as code with AI workflow, and it is the one that fits in a pipeline. If you are still setting up collections, start with your first API collection in Bruno and Postman.
What does a collection run already know?
More than you would guess. For every request in the run, both tools record:
- The method and URL, which is the arrow label
- The order of execution, which is the vertical axis
- The response status, which is the return arrow
- The response time, which becomes the latency annotation
- The test results, which tell you whether that arrow is a success or a failure branch
- Any chained variables, which is where you see the identifier flowing from one call to the next
That is every field a sequence diagram needs. The only thing missing is the transcription, which is exactly the task a language model does well and a human does tediously.
Capturing the trace in Postman
Put this in the collection level post-response script, so it runs after every request without touching individual requests.
// Collection > Scripts > Post-response
const trace = pm.collectionVariables.get("trace")
? JSON.parse(pm.collectionVariables.get("trace"))
: [];
trace.push({
step: trace.length + 1,
name: pm.info.requestName,
method: pm.request.method,
url: pm.request.url.getPath(),
status: pm.response.code,
ms: pm.response.responseTime,
ok: pm.response.code < 400,
});
pm.collectionVariables.set("trace", JSON.stringify(trace));
console.log(JSON.stringify(trace[trace.length - 1]));
Run the collection, open the console, and you have a clean ordered trace. For a payments flow it looks like this:
[
{"step":1,"name":"Create payment","method":"POST","url":"/payments","status":202,"ms":141,"ok":true},
{"step":2,"name":"Get status","method":"GET","url":"/payments/:uetr","status":200,"ms":38,"ok":true},
{"step":3,"name":"Poll until settled","method":"GET","url":"/payments/:uetr","status":200,"ms":41,"ok":true},
{"step":4,"name":"Duplicate submit","method":"POST","url":"/payments","status":409,"ms":55,"ok":true},
{"step":5,"name":"Fetch receipt","method":"GET","url":"/payments/:uetr/receipt","status":200,"ms":67,"ok":true}
]
Note step 4. The 409 is an expected result, because the test asserts that a duplicate submission is rejected. That distinction matters when you generate the diagram, and it is why the ok field records whether the assertion passed rather than whether the status was a success code. Chaining and scripting in collections more broadly is covered in API request chaining and scripts.
Capturing the trace in Bruno
Bruno does the same thing with its own script API, which reads a little cleaner:
// collection.bru > script:post-response
const trace = bru.getVar("trace") || [];
trace.push({
step: trace.length + 1,
name: req.getName(),
method: req.getMethod(),
url: new URL(req.getUrl()).pathname,
status: res.getStatus(),
ms: res.getResponseTime(),
});
bru.setVar("trace", trace);
If you are running headless, you do not need the script at all. The Bruno command line interface writes the whole run for you:
bru run --env staging --reporter-json run.json
The same applies to Postman through newman:
newman run payments.postman_collection.json \
-e staging.postman_environment.json \
--reporters cli,json \
--reporter-json-export run.json
Both files contain the complete ordered execution, including request bodies, response bodies, timings, and assertion results. For a diagram you only need a fraction of it, so trim before you do anything else. This is the version I pipe into the model:
jq '[.run.executions[] | {
name: .item.name,
method: .request.method,
url: .request.url.path | join("/"),
status: .response.code,
ms: .response.responseTime,
failed: (.assertions // [] | map(select(.error)) | length)
}]' run.json > trace.json
Trimming is not only about token count. A raw newman report contains full response bodies, which means real data, and sending those to a model is a decision you should make deliberately rather than by accident. The field selection above keeps the shape of the flow and drops every value. The wider version of that judgment is in AI guardrails for analysts.
Generating the diagram
Give the model the trace, your participant vocabulary, and a strict instruction:
Transcribe this API test run into a Mermaid sequenceDiagram.
- Participants: Analyst (the collection runner) and the services named
in the context pack. Do not add any participant not listed.
- One request arrow and one response arrow per execution, in order.
- Label request arrows with method and path, response arrows with the
status code.
- Any execution where `failed` is greater than zero goes in an
`alt` block labelled with the failing assertion.
- Add `Note right of` with the response time for anything over 100ms.
- Do not infer internal service-to-service calls. This run only
observed the client boundary.
The last rule is the important one. A collection run sees the client boundary and nothing else. Left unconstrained, a model will cheerfully add a Processor and a Kafka to the diagram because the flow obviously has them, and now your evidence-based diagram contains fiction. If you want the internal hops, get them from a log export and merge the two sources deliberately.
The output:
sequenceDiagram
autonumber
participant A as Analyst
participant API as Payments API
A->>API: POST /payments
API-->>A: 202 Accepted (141ms)
A->>API: GET /payments/{uetr}
API-->>A: 200 RCVD (38ms)
loop until terminal status
A->>API: GET /payments/{uetr}
API-->>A: 200 ACSC (41ms)
end
Note over A,API: duplicate submission test
A->>API: POST /payments (same idempotency key)
API-->>A: 409 Conflict (55ms)
A->>API: GET /payments/{uetr}/receipt
API-->>A: 200 (67ms)
That diagram took about twenty seconds to produce and it documents the integration contract more clearly than the collection does, because the order and the polling loop are visible at a glance.
Why this is the diagram to put in front of non technical people
Because it is a picture of something that demonstrably works, generated from a run anyone can repeat.
A collection is unreadable to a product owner. A screenshot of a 200 response means nothing to a compliance reviewer. A ten line sequence diagram showing “payment submitted, accepted in 141ms, settled, duplicate correctly rejected” is immediately legible to both, and the fact that it was generated from an actual passing run rather than drawn by hand is the part that makes it credible.
Three places I use this deliberately:
- In the pull request that changes an integration. Reviewers who will never open the collection see what changed in the flow.
- In refinement, when explaining an API to a team that has not used it. The diagram plus the ability to rerun it live is far more convincing than a specification walkthrough.
- In the handover pack when an integration goes to production support. The diagram says what normal looks like, which is the thing an on call engineer needs at 2am and never has.
The deeper argument, that running the thing is how you actually learn the system, is in you do not understand the system until you test it. The full collection and testing method is in API Testing and QA Mastery for BAs.
Wiring it into CI so it cannot go stale
This is the step that turns a neat trick into documentation infrastructure.
- name: Run API collection
run: |
newman run collections/payments.json \
-e envs/staging.json \
--reporters cli,json \
--reporter-json-export run.json
- name: Generate flow diagram
run: node scripts/trace-to-mermaid.js run.json > docs/diagrams/payment-flow.md
- name: Fail if the documented flow changed
run: git diff --exit-code docs/diagrams/payment-flow.md
The last step is the whole point. If the generated diagram differs from the committed one, the job fails and somebody has to look. A difference means one of two things, and both should block a merge until they are understood: the API changed shape, or the collection changed what it exercises.
Two practical notes. First, generate the Mermaid deterministically in trace-to-mermaid.js rather than by calling a model in CI, so the diff is stable run to run. Use the model once, interactively, to write that script from a sample trace, then let the script do the repeated work. Second, keep the response times out of the committed file or the diff will fail on every run for no reason. Round them into buckets, or emit them only in the human facing copy.
This is the same maintenance loop as contract testing and it fails for the same good reason: something about the integration is no longer what was agreed. Getting collections running in a pipeline at all is covered in API tests in CI.
Combining the two evidence sources
The test run diagram and the log diagram show different halves of the same flow, and they are strongest together.
The test run gives you the client boundary with perfect repeatability and no production data. The logs give you the internal hops and the behavior your tests never exercise. Generate both for the same flow and compare: any hop the logs show that your collection never triggers is untested behavior, and that list is a genuinely good source of test cases.
That comparison is a five minute exercise that has produced better coverage findings for me than most formal test design sessions, because it is grounded in what the system actually does rather than what the specification describes. Deriving cases from evidence like this is the discipline in negative test design.
The takeaway
A collection run is a complete trace of an integration, and throwing it away after reading the status codes wastes the most easily available diagram input you have. Capture it with a collection level post-response script or the newman and bru JSON reporters, trim it to method, path, status, timing, and assertion result, and transcribe it into Mermaid with one rule: do not infer any call the run did not observe.
Then wire it into CI so the diagram is rebuilt on every run and the pipeline fails when the documented flow no longer matches the tested one. That is documentation that maintains itself. Pair it with diagrams from Splunk and Datadog logs for the internal hops, and see the whole system in diagrams as code with AI. The collection and testing method behind it is in API Testing and QA Mastery for BAs, and everything else is at The Tech BA Toolkit.
Ahmed is a Senior Technical Business Analyst with 10+ years in banking and payments. He builds practical guides and tools for analysts at The Tech BA Toolkit.
Tags: API Testing, Postman, Bruno, Documentation, QA
About the author
Analyst Engineering is written by Ahmed, a Senior Technical Business Analyst with 10+ years of banking and payments delivery experience: ISO 20022 and SWIFT messaging, payments API integration, Kafka event validation, and production support. Every article comes from real delivery work, and each one is reviewed and updated as tools and standards change.
Related articles
- Diagrams as Code with AI: The Analyst's System for Mermaid, BPMN, and Sequence Diagrams How analysts use AI to draw and maintain Mermaid, BPMN, and sequence diagrams: the context pack, the house style file, the review loop, and the git workflow.
- Draw Sequence Diagrams from Splunk and Datadog Logs: The Flow as It Actually Ran Turn correlated Splunk or Datadog logs into an accurate Mermaid sequence diagram with AI. The queries, the export shape, the prompt, and the verification step.
- Mermaid for Analysts: The Six Diagram Types You Actually Need A practitioner reference for Mermaid: sequence, flowchart, state, ER, C4 context, and gantt diagrams, with copy-paste syntax and where each one renders.
- Chaining API Requests With JavaScript in Bruno and Postman: The Scripts Analysts Need Chain API requests in Bruno and Postman: capture values, pre-request and post-response scripts, token refresh, polling, branching, and a Stripe sandbox flow.
Free account
Practice on the Labs, keep your progress
A free account, no password: an email link signs you in. It saves your steps and self-assessments on the Labs, shows your missions on a dashboard, unlocks the solutions, and, if you tick the box, sends you new missions and articles when they ship.
Your email is used to sign you in. Nothing else, unless you ask. Privacy.