Postman API Chaining — End-to-End Flow

API chaining means using data from one response in the next request — a token from login, an ID from create — so you can test a complete business workflow instead of isolated calls. This practice set covers an end-to-end chain, negative and security checks, and CSV-driven runs. Every script below was run with Newman against a local booking API and passed; the same flow works on the public Restful Booker practice API.

Advertisement

How Chaining Works

  1. Extract a value in the Tests tab: pm.collectionVariables.set('bookingId', pm.response.json().bookingid).
  2. Reuse it anywhere with double braces: {{baseUrl}}/bookings/{{bookingId}} or a header Authorization: Bearer {{token}}.
  3. Guard it in the next request's pre-request script, so a broken chain fails with a clear message.

Use collection variables for values produced during a run (IDs, tokens) and environment variables for per-environment settings (base URL, credentials). More: Postman Cheat Sheet.

Part 1 — The End-to-End Chain

Login → save token → Create → save ID → Get → Update → Verify update → Delete → Verify 404

Exercise 1: Login and extract the token

// POST {{baseUrl}}/auth   body: { "username": "admin", "password": "password123" }
pm.test('200 OK', () => pm.response.to.have.status(200));
const token = pm.response.json().token;
pm.test('token returned', () => pm.expect(token).to.be.a('string').and.not.empty);
pm.collectionVariables.set('token', token);

Exercise 2: Create a resource with unique data and extract its ID

// Pre-request script
if (!pm.collectionVariables.get('token')) {
    throw new Error('token missing - run Login first');     // Exercise 9: fail fast on a broken chain
}
pm.variables.set('firstname', 'Asha_' + Date.now());         // unique data every run
pm.variables.set('totalprice', 150);

// Body (raw JSON): { "firstname": "{{firstname}}", "totalprice": {{totalprice}} }

// Tests
pm.test('201 Created', () => pm.response.to.have.status(201));
const id = pm.response.json().bookingid;
pm.test('id returned', () => pm.expect(id).to.be.a('number'));
pm.collectionVariables.set('bookingId', id);
pm.collectionVariables.set('createdName', pm.response.json().booking.firstname);

Exercise 3: Fetch the resource

// GET {{baseUrl}}/bookings/{{bookingId}}
pm.test('200 and same name', () => {
    pm.response.to.have.status(200);
    pm.expect(pm.response.json().firstname).to.eql(pm.collectionVariables.get('createdName'));
});

Exercises 4–5: Update, then verify the update

// PUT {{baseUrl}}/bookings/{{bookingId}}   body: { "firstname": "Asha Updated", "totalprice": 200 }
pm.test('200 OK', () => pm.response.to.have.status(200));

// GET again — never trust the update response alone
pm.test('updated values', () => {
    const b = pm.response.json();
    pm.expect(b.firstname).to.eql('Asha Updated');
    pm.expect(b.totalprice).to.eql(200);
});

Exercises 6–7: Delete, then verify it's gone

// DELETE {{baseUrl}}/bookings/{{bookingId}}
pm.test('204 No Content', () => pm.response.to.have.status(204));

// GET {{baseUrl}}/bookings/{{bookingId}}
pm.test('404 after delete', () => pm.response.to.have.status(404));

Status codes vary between APIs — Restful Booker, for example, returns 201 for a successful delete. Always assert what the API documentation specifies.

Exercise 8: Run the whole chain

Put the requests in a folder in this order and run it with the Collection Runner or Newman:

newman run chaining.json -e qa.json

All nine assertions of the chain passed in our run.

Exercises 9–10: Handle and debug broken chains

  • Fail fast: the pre-request guard in Exercise 2 stops the run with a clear message instead of sending /bookings/undefined.
  • Debug: open the Postman Console (View → Show Postman Console) to see every request's resolved URL, headers and body — an unresolved {{bookingId}} shows up immediately.
  • Check the variable scope: a value set with pm.variables.set exists only for the current request; use collection or environment variables to pass data between requests.

Interview line: "I built end-to-end chains in Postman — login, token extraction, dynamic IDs, full CRUD with verification after each step — with pre-request guards so a broken chain fails clearly, and ran them with Newman in CI."

Part 2 — Negative and Security Testing

# Test Request Expected
1 Malformed JSON {"firstname": "Asha", 400
2 Missing mandatory field {"totalprice": 100} 400 + message naming the field
3 Wrong Content-Type text/plain body 415
4 No or invalid token No Authorization header 401
5 Business-rule violation "totalprice": -1 422 (or 400)
6 Wrong ID type GET /bookings/abc 400
7 Non-existent ID GET /bookings/999999 404
8 Forbidden resource Another user's booking, or an admin endpoint 403 (or 404)
9 Boundary values Min/max lengths and numbers, 0, very large values Accepted or rejected per the spec
10 SQL injection string ' OR 1=1 -- in a text field Rejected or stored as plain text; no database errors
11 XSS payload <script>alert(1)</script> Validated or escaped; never executed where displayed
12 Rate limiting Many requests quickly 429 with Retry-After, if the API documents a limit
// Example negative tests (all passed in our run)
pm.test('400 when firstname missing', () => pm.response.to.have.status(400));
pm.test('error message', () => pm.expect(pm.response.json().error).to.include('firstname'));
pm.test('415 for wrong Content-Type', () => pm.response.to.have.status(415));
pm.test('401 without token', () => pm.response.to.have.status(401));

Check the error body too: a clear message, no stack trace, no internal details. Run security payloads only in test environments you're authorized to test. More: API Security Testing and Negative Testing & Error Handling.

Part 3 — Data-Driven Testing with CSV

# bookings.csv
firstname,totalprice,expectedStatus
Asha,150,201
Ravi,0,201
,100,400
Meera,-5,422
// Body: { "firstname": "{{firstname}}", "totalprice": {{totalprice}} }

// Tests — one assertion per row, labelled with the row's data
const expected = Number(pm.iterationData.get('expectedStatus'));
pm.test(`row ${pm.info.iteration + 1}: ${pm.iterationData.get('firstname') || '(empty)'} → ${expected}`,
        () => pm.response.to.have.status(expected));
newman run data-driven.json -d bookings.csv -r cli,htmlextra

Result in our run: row 1: Asha → 201, row 2: Ravi → 201, row 3: (empty) → 400, row 4: Meera → 422 — all passed. Putting the expected result in the data file lets one request cover positive and negative cases, and labeling each test with its row makes a failing iteration easy to spot.

Data-driven practice list

  • Validate every iteration independently (status, key fields, response time).
  • Include edge rows: empty values, maximum lengths, special and Unicode characters, zero and negative numbers.
  • Keep rows independent — generate unique values so one iteration can't affect another.
  • Clean up: delete created records at the end (or in a teardown folder).
  • For dependent data, create it inside the iteration (chaining) rather than relying on earlier rows.

Plan full positive, negative and edge-case sets for real endpoints in the API Testing Scenario Lab, and run collections in CI with Postman Newman CI/CD.

From Real Projects

I've worked with APIs at the level this page covers: CRUD operations, HTTP methods, JSON and XML formats, and extracting and validating values with JSON path. A good habit from that work: test the full create–read–update–delete cycle for a resource and check each response in detail. Testsigma supports web, mobile and API test automation, so understanding APIs was part of understanding the product I was testing. Save IDs from one response in variables so the next request can use them.

FAQs

What is API chaining in Postman?

Passing data from one response into later requests — typically a token from login and an ID from create — so a whole workflow can be tested in sequence.

Collection or environment variables for chaining?

Collection variables for values created during the run (tokens, IDs); environment variables for per-environment settings such as the base URL.

How do you verify a deleted resource?

Send a GET with the deleted ID and assert the documented "not found" response — usually 404.

How do you stop a chain when a variable is missing?

Check it in the pre-request script and throw an error with a clear message, so the run doesn't continue with undefined values.

How is data-driven testing done in Postman?

Attach a CSV or JSON file to the Collection Runner or Newman (-d file.csv); column names become variables, and pm.iterationData reads the current row — including expected results.