Postman 101: Getting Past the Send Button

By Pasindu Kavinda ·

I once spent the better part of an afternoon convinced our login endpoint was broken. Kept hitting Send, kept getting a 401, kept re-reading the backend code. Turned out I’d copied the token into the wrong request and was authenticating against a stale value from twenty minutes ago. The API was fine. I was the bug.

That’s the thing nobody tells you about Postman. Most people use maybe 5% of it - type a URL, smash Send, squint at the JSON, repeat. Which is fine until you’re pasting bearer tokens by hand for the fortieth time and quietly losing your mind. So here’s the stuff that actually moved the needle for me, roughly in the order it stopped hurting.

collections are folders, and that’s the point

First thing: stop having a graveyard of “New Request” tabs. Group your requests into a collection. A collection is just a folder that travels with metadata - think of it as the project’s API surface, saved.

For a to-do app I’d have something like:

Todo API
├── Auth
│   ├── Register
│   └── Login
├── Todos
│   ├── List todos
│   ├── Create todo
│   └── Delete todo

The unglamorous win here is that a collection is a file you can export and commit to the repo. New person joins, they import it, and they’ve got every endpoint with example bodies instead of grepping through route files guessing what the payload shape is. I’ve onboarded people with a shared collection and it cut the “wait, what does this endpoint even want” questions to basically zero.

environments, or: stop hardcoding your base URL

This is the one I’ll actually die on a hill for. Do not hardcode http://localhost:3000 into forty requests. You will regret it the moment you need to hit staging.

Make an environment. It’s a bag of key-value variables. I keep at least two - Local and Staging - and each one defines the same keys with different values:

VariableLocalStaging
base_urlhttp://localhost:3000https://staging.example.com
token(empty)(empty)

Then every request URL becomes {{base_url}}/todos. Switching from local to staging is now a dropdown in the top right, not a find-and-replace across your whole collection. The day I learned this properly I deleted about an hour of recurring busywork from my week.

One gotcha that bit me early: there’s a difference between environment variables and collection variables and global ones, and they resolve in a priority order. If a value seems stubbornly wrong, you’ve probably got the same key defined in two scopes and the wrong one is winning. Postman highlights variables in orange when they resolve and leaves them red-ish when they don’t - trust that hint.

the token dance, automated

Okay, the actual reason I stopped hating Postman. You know the loop: call login, copy the token out of the response, paste it into the Authorization header of every other request. Every time it expires, do it again.

You can make login save the token for you. In the Login request, open the Tests tab (it runs after the response comes back, the naming is a lie) and write:

const res = pm.response.json();
pm.environment.set("token", res.access_token);

Now token in your environment gets overwritten automatically the instant login succeeds. Set your other requests’ auth to Bearer {{token}} once, and you never touch it again. Log in, everything downstream is authenticated. This is the single feature that turns Postman from a fancy curl into something that saves you time.

Little thing worth knowing: Pre-request Script runs before the request fires, Tests runs after. So token-grabbing goes in Tests (you need the response first). Generating a timestamp or a nonce to send goes in Pre-request. I mixed these up for embarrassingly long.

chaining requests so you’re not babysitting IDs

Same trick scales. Say “Create todo” returns the new todo’s id, and you want a “Delete todo” request pointed at it. In Create todo’s Tests:

pm.test("todo was created", () => {
  pm.response.to.have.status(201);
});

const body = pm.response.json();
pm.environment.set("last_todo_id", body.id);

Then Delete todo hits {{base_url}}/todos/{{last_todo_id}}. Create, then delete, and it just works on the thing you actually made - no copy-pasting UUIDs between tabs. Chaining like this is how you build a little end-to-end flow: register, login, create, verify, clean up.

write two assertions and it stops being a toy

That pm.test(...) block above is the other half of the value, and most people skip it. Here’s my opinion: if you’re not writing at least a couple of assertions, you’re not testing, you’re just looking. And looking is how a shape change sneaks past you - the request 200s, the JSON scrolls by, you nod, and you never notice price quietly became a string.

I don’t go overboard. Two or three checks per important request:

pm.test("status is 200", () => pm.response.to.have.status(200));

pm.test("returns an array of todos", () => {
  const data = pm.response.json();
  pm.expect(data).to.be.an("array");
  pm.expect(data[0]).to.have.property("id");
});

Now it’s making a claim about correctness, not just displaying bytes. When something changes on the backend, the test goes red instead of you finding out from a confused frontend dev three days later.

running the whole thing at once

Once your collection has assertions, the Collection Runner becomes worth it. Hit run, pick an environment, and Postman fires every request in order and shows you a green/red board of every assertion. It respects the order, so your register → login → create → delete flow runs top to bottom with the variables carrying between steps.

And the bit that made it click for me: there’s a CLI called Newman that runs the exact same collection from a terminal.

newman run todo-api.postman_collection.json \
  -e staging.postman_environment.json

Which means the same collection you click through by hand can run in CI on every push. Export the collection and the environment, commit them, add a Newman step to the pipeline. Now your “did I break the API” check isn’t vibes, it’s a build step that fails loudly. I don’t always set this up - for a throwaway prototype it’s overkill - but for anything a second person depends on, it’s saved me from shipping a broken endpoint more than once.

stuff that bit me

A few scars, so they’re not yours too:

Secrets in exported collections. If you paste a real API key or a prod token as a plain variable’s current value and export, congratulations, it might be in the JSON you just committed. Keep secrets in the environment’s current-value column (which isn’t shared by default) and leave the initial value blank.

The {{token}} that renders red isn’t set - you either picked the wrong environment in the dropdown or never ran login this session. Nine times out of ten it’s the dropdown.

And Tests-runs-after, Pre-request-runs-before. Say it to yourself once and save the afternoon I lost.

That’s basically the whole beginner-to-useful arc. Collections to stay organized, environments so you’re not hardcoding, a couple of scripts to auto-grab tokens and chain IDs, and a few assertions so it’s actually checking something. Get those four and you’ve left the Send-button-and-squint crowd behind.

Kavinda

© 2026 Pasindu Kavinda

LinkedIn Medium 𝕏 GitHub