Postman JSON Examples: Request Bodies, Tests, Collections, and Newman CLI
Last updated:
Postman handles JSON in five distinct places — the request body editor, the response viewer, the Tests panel (where pm.response.json() parses the response and pm.test runs assertions), pre-request scripts (where you generate JSON programmatically before send), and the Collection file itself, which is a JSON document in the published Postman Collection v2.1.0 schema. Each surface has its own conventions. This guide walks through every one with runnable examples — raw bodies, Chai-style assertions, variable interpolation with {{varName}}, dynamic body generation, and running collections from CI with the Newman CLI. Pair this page with our curl JSON reference if you also issue requests from the terminal — many teams keep both in sync.
Body editor flagging a syntax error you cannot find? Paste the JSON into Jsonic's JSON Validator— it pinpoints trailing commas, missing quotes, and bracket mismatches with exact line numbers, faster than Postman's inline checker for large bodies.
Validate JSON bodyBuilding a JSON request body in Postman (raw JSON mode)
For any HTTP method that carries a body — POST, PUT, PATCH, DELETE with body — the standard JSON workflow is the same. Click the Body tab below the URL bar, select the raw radio, then change the format dropdown at the far right from Text to JSON. Postman now treats the editor as JSON: it syntax-highlights the document, underlines parse errors, and adds Content-Type: application/json to the request headers automatically. You do not need to set the Content-Type yourself.
A working example for creating a user resource:
POST https://api.example.com/users
Content-Type: application/json ← Postman adds this for you
{
"email": "ada@example.com",
"name": "Ada Lovelace",
"role": "admin",
"preferences": {
"theme": "dark",
"notifications": true
},
"tags": ["founder", "engineer"]
}The editor is forgiving in two places where production parsers are strict: it accepts single quotes in some contexts (browsers will reject them on the wire), and it does not always flag trailing commas inside large nested objects. If a request works in Postman but fails against your server with a 400, copy the body into a strict validator to find the difference. Postman's body editor is a development convenience — not a substitute for JSON Schemavalidation against the endpoint's contract.
For binary uploads (images, PDFs), switch the body type to form-data or binary instead — raw JSON is text-only. For mixed payloads (JSON metadata plus a file), use form-data with one field set to type File and the JSON fields as type Text.
Postman Collection format v2.1: JSON schema reference
A Postman Collection is a JSON document. Every collection conforms to the published v2.1.0 schema at https://schema.getpostman.com/json/collection/v2.1.0/collection.json — the full registry of Postman schemas lives at schema.postman.com. The shape is small enough to read in one sitting: an info block, an item array containing requests and nested folders, and optional variable and auth sections.
{
"info": {
"name": "Example API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_postman_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"item": [
{
"name": "Create user",
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{baseUrl}}/users",
"host": ["{{baseUrl}}"],
"path": ["users"]
},
"body": {
"mode": "raw",
"raw": "{\n \"email\": \"{{userEmail}}\"\n}",
"options": { "raw": { "language": "json" } }
}
},
"event": [
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
"pm.test('status 201', () => pm.response.to.have.status(201));",
"const body = pm.response.json();",
"pm.collectionVariables.set('userId', body.id);"
]
}
}
]
}
],
"variable": [
{ "key": "baseUrl", "value": "https://api.example.com" }
]
}A few details worth knowing. The info.schema URL is what makes the file a valid v2.1 collection — Newman and the Postman app key off it. The item array can hold either requests (with a request field) or folders (with a nested item array), so collections nest arbitrarily deep. The event array attaches scripts to lifecycle hooks — prerequest runs before send, test runs after the response. Bodies are stored as escaped JSON strings inside the raw field, which is why the example shows \\n and \\" — they are escaped because the collection file is itself JSON.
Because the format is plain JSON, collections diff cleanly in pull requests and merge with standard git tools. Many teams treat the collection JSON as a source-of-truth contract alongside their OpenAPI spec.
Variables in JSON bodies: {{varName}} interpolation
Anywhere Postman accepts a string — URL, headers, query params, the raw body — you can write {{varName}} and Postman substitutes the variable value at send time. Inside a JSON body this looks slightly odd because the editor flags {{varName}} as invalid JSON before substitution, but the actual request on the wire is valid — substitution happens before serialization.
POST {{baseUrl}}/users
Authorization: Bearer {{authToken}}
Content-Type: application/json
{
"email": "{{userEmail}}",
"tenant": "{{tenantId}}",
"createdBy": "{{$randomUUID}}",
"timestamp": "{{$isoTimestamp}}"
}Variables resolve in scope order: data (CSV/JSON for Collection Runner), local (pre-request script), environment (the active environment), collection (per collection), global. Earlier scopes win. The most common pattern is to keep long-lived values (base URLs, API keys) in environments — one per deploy target — and short-lived derived values (auth tokens captured from a login response) in collection variables.
Postman ships dynamic variables prefixed with $ that resolve fresh on every send: {{$randomUUID}}, {{$timestamp}}, {{$isoTimestamp}}, {{$randomFirstName}}, {{$guid}}, and many more. These are useful for idempotency keys, nonce values, and seed data without writing a pre-request script.
For values that must be JSON-encoded — embedded objects, strings with escape characters — set them in a pre-request script with JSON.stringify and reference the resulting string. Otherwise Postman inserts the variable as a plain string and you end up with unescaped quotes breaking the body.
Tests panel: pm.test() with JSON assertions
The Tests tab runs JavaScript after every response. The pm object is the Postman sandbox API — pm.test(name, fn) wraps an assertion block,pm.expect is the bundled Chai assertion library, and pm.response gives you the status, headers, body, and timing.
// Tests tab — runs after every response
pm.test("status code is 201", () => {
pm.response.to.have.status(201);
});
pm.test("response time under 500ms", () => {
pm.expect(pm.response.responseTime).to.be.below(500);
});
const body = pm.response.json();
pm.test("response has user id", () => {
pm.expect(body).to.have.property("id");
pm.expect(body.id).to.be.a("number");
});
pm.test("email matches request", () => {
pm.expect(body.email).to.eql(pm.variables.get("userEmail"));
});
pm.test("tags array is non-empty", () => {
pm.expect(body.tags).to.be.an("array").that.is.not.empty;
});Each pm.test shows as a separate row in the Test Results tab — green for pass, red for fail. Newman prints the same results in its CLI output and exits non-zero if any assertion fails, which is how the same tests gate your CI pipeline. Tests run independently — one failing assertion does not stop the others — so you get a complete picture per response.
For shared assertion logic across many requests, define helpers in a collection-level pre-request script and call them from each request's Tests tab. The collection pre-request runs before every request, so anything you assign to pm.collectionVariables or to a global there is available in the test script.
pm.response.json() and chai-style assertions
pm.response.json() parses the response body as JSON and returns the JavaScript value. Call it once at the top of your tests and reuse the result — repeated calls re-parse the same string. If the response is not valid JSON (HTML error page, plain text), the call throws; wrap it in a guard or check the Content-Type first if your endpoint sometimes returns non-JSON.
const body = pm.response.json();
// Deep equality
pm.test("user object matches", () => {
pm.expect(body.user).to.eql({ id: 42, email: "ada@example.com", role: "admin" });
});
// Property and array checks
pm.test("body shape", () => {
pm.expect(body).to.have.property("id").that.is.a("number");
pm.expect(body).to.have.nested.property("user.email");
pm.expect(body.results).to.be.an("array").with.lengthOf.at.least(1);
});
// JSON Schema validation (using tv4 from the sandbox)
const schema = {
type: "object",
required: ["id", "email"],
properties: {
id: { type: "number" },
email: { type: "string", format: "email" }
}
};
pm.test("matches schema", () => {
pm.response.to.have.jsonSchema(schema);
});The Chai surface inside Postman is the full BDD interface: .to.equal (strict equality), .to.eql (deep equality), .to.include, .to.have.property, .to.have.nested.property, .to.be.an, .to.have.lengthOf, .to.match (regex), and the negation modifier .not. For schema validation, pm.response.to.have.jsonSchema(schema) validates against a JSON Schema draft-04 document — useful for catching response shape regressions that simple property checks miss.
Generating dynamic JSON with pre-request scripts
The Pre-request Script tab runs JavaScript before the request is sent. Use it to compute values, sign requests, generate timestamps, or build a JSON body programmatically and stash it in a variable that the body editor references.
// Pre-request Script tab
const crypto = require("crypto-js");
// Build a JSON body with computed fields
const payload = {
email: pm.environment.get("userEmail"),
timestamp: new Date().toISOString(),
nonce: pm.variables.replaceIn("{{$randomUUID}}"),
items: Array.from({ length: 3 }, (_, i) => ({
sku: `SKU-${1000 + i}`,
qty: Math.floor(Math.random() * 10) + 1
}))
};
// Sign the payload (HMAC-SHA256 over the canonical JSON)
const canonical = JSON.stringify(payload);
const signature = crypto.HmacSHA256(canonical, pm.environment.get("apiSecret"))
.toString(crypto.enc.Hex);
// Stash for the request body and headers
pm.variables.set("requestBody", canonical);
pm.variables.set("requestSignature", signature);In the request body editor, reference the variable directly:
{{requestBody}}And in headers: X-Signature: {{requestSignature}}. The Postman sandbox includes crypto-js, moment, lodash, uuid, chai, tv4, cheerio, and xml2js — enough to build most signed-request workflows without external dependencies. For values you want available to many requests in the same run, use pm.collectionVariables.set instead of pm.variables.set (collection variables persist across requests in a run; pm.variables is request-scoped).
For test data generation at scale — Mock JSON datafor large fixture sets — consider generating the data outside Postman and feeding it in via the Collection Runner's data file feature (CSV or JSON), which makes each row a separate iteration.
Newman CLI: running collections in CI with JSON reporter
Newman is the official command-line runner for Postman collections. Install it globally or as a dev dependency: npm install -g newman (current major version is 6.x as of 2026). Once installed, run any v2.1 collection file from the terminal — same requests, same scripts, same assertions as the GUI.
# Basic run
newman run postman/collection.json
# With environment, multiple reporters, and JSON output
newman run postman/collection.json \
--environment postman/env-staging.json \
--reporters cli,json \
--reporter-json-export newman/report.json
# Common flags for CI
newman run collection.json \
--iteration-data data/users.csv \
--folder "Auth" \
--bail \
--timeout-request 10000 \
--reporters cli,junit,json \
--reporter-junit-export reports/junit.xmlNewman exits with status 0 if all assertions pass, non-zero if any fail — that exit code is what fails your CI job and blocks the deploy. The --reporters flag accepts a comma list: cli (default colored output), json (machine-readable run report), junit (CI-friendly XML), and htmlextra (rich HTML via a community plugin). Most CI setups ship both cli for live logs and junit for the test-results UI in GitHub Actions, GitLab, or Jenkins.
The JSON reporter writes a structured run record — every request, every assertion, timing, response codes — that you can upload as a build artifact or post to a webhook. The default output location is newman/<timestamp>.json if you omit --reporter-json-export. Sample structure:
{
"collection": { "info": { "name": "Example API" } },
"environment": { "name": "staging" },
"run": {
"stats": {
"requests": { "total": 4, "failed": 0 },
"assertions": { "total": 12, "failed": 1 }
},
"timings": { "responseAverage": 142, "started": 1716470000000 },
"executions": [
{
"item": { "name": "Create user" },
"response": { "code": 201, "responseTime": 187 },
"assertions": [{ "assertion": "status 201", "skipped": false }]
}
],
"failures": [
{
"error": { "name": "AssertionError", "message": "expected 200 to equal 201" },
"source": { "name": "List users" }
}
]
}
}Pair Newman with our JSON in CI/CD guide for caching node_modules, parallelizing across folders, and feeding the JSON report into status-check bots. For broader patterns, our JSON API testing guide compares Newman against alternative runners (Hurl, Bruno, custom Jest + supertest setups).
Importing/exporting Postman collections as JSON files
Collections are portable JSON files. Export from the Postman app via the three-dot menu on a collection in the sidebar → Export → choose Collection v2.1.0 (default). The download is a single .postman_collection.json file. Environment files export the same way from the Environments tab — choose Export on the environment, and you get a .postman_environment.json file with the variable list.
Both files are plain JSON, suitable for committing to git. A common repo layout:
postman/
├── collection.json # the exported collection
├── env-staging.json # staging environment
├── env-production.json # prod environment (secrets via CI vars)
└── README.md # how to run
# Inject secrets at run time — do not commit them
newman run postman/collection.json \
--environment postman/env-production.json \
--env-var "apiKey=$PROD_API_KEY"Importingworks in reverse — drag any v2.1 collection JSON onto the Postman app's Import dialog and the requests appear in the sidebar. Postman also imports OpenAPI 3.x specs (generates a collection from the operations), curl commands (paste from terminal), and HAR files (captured from browser DevTools). For teams that maintain an OpenAPI spec as the source of truth, the OpenAPI → Postman import path keeps the two in rough sync — re-import to refresh after spec changes.
Postman's schema registry at schema.postman.comhosts every published version of the collection schema. If you are building tooling that reads or writes Postman files, point your validator at the schema URL referenced in the file's info.schema field — that is the contract.
Key terms
- Postman Collection (v2.1)
- A JSON document describing one or more HTTP requests, their bodies, headers, scripts, and folder structure. Conforms to the v2.1.0 schema at
schema.getpostman.com. Portable across the Postman app, Newman, and third-party tooling. - pm.test
- The assertion wrapper in the Tests panel —
pm.test(name, fn)runs the function and records pass/fail. Each call is independent; one failure does not block others. Used by both the Postman GUI and Newman. - pm.response.json()
- Parses the response body as JSON and returns the JavaScript value. Throws if the body is not valid JSON. The standard entry point for response assertions.
- pm.expect (Chai)
- The bundled Chai assertion library inside the Postman sandbox. Supports the full BDD interface:
.to.equal,.to.eql,.to.have.property,.to.be.an,.not, and more. - Variable interpolation
- Postman's template syntax —
{{varName}}inside any string field is replaced with the variable value at send time. Scopes resolve in order: data, local, environment, collection, global. - Newman
- Postman's official command-line runner — executes v2.1 collections outside the GUI. Current major version is 6.x. Reports via CLI, JSON, JUnit, or HTML; exits non-zero on assertion failure, making it CI-ready out of the box.
- Pre-request script
- JavaScript that runs before the request is sent. Used for signing payloads, generating dynamic values, capturing data, and building computed JSON bodies. Has access to the same
pmsandbox API as tests.
Frequently asked questions
How do I send JSON in a Postman request body?
Open the request, set the method to POST (or PUT, PATCH), and click the Body tab below the URL bar. Choose the raw radio option, then in the dropdown that appears at the far right of the body type row, change the format from Text to JSON. Postman now treats the body as JSON, syntax-highlights it, and automatically sets the Content-Type header to application/json — you do not need to add it manually. Paste or type your JSON object into the body editor: {"email": "user@example.com", "name": "Ada"}. The editor catches syntax errors (missing quotes, trailing commas, mismatched braces) and shows a red underline at the problem. Click Send. The response panel shows status, headers, body, and timing. If you ever need to verify a tricky body against a strict parser, paste it into the Jsonic JSON Validator first — Postman is forgiving in places where production servers are not.
What is the Postman Collection JSON format?
A Postman Collection is a JSON document that describes one or more HTTP requests, their bodies and headers, organized into folders, with optional tests and pre-request scripts. The current format is Collection v2.1.0 — every collection JSON file starts with an info block (name, schema URL https://schema.getpostman.com/json/collection/v2.1.0/collection.json) and an item array containing requests and nested folders. The schema is published at https://schema.postman.com/ and is widely supported by tooling: the Postman app, the Newman CLI, the VS Code Postman extension, and many third-party API tools all read and write v2.1. Collection files are portable — you can commit them to git, diff them in pull requests, and run them in CI without the Postman GUI. Export from the app via the three-dot menu on a collection → Export → choose v2.1.0.
How do I assert on a JSON response in Postman tests?
Open the Tests tab on the request and write JavaScript using the pm object. Parse the response with pm.response.json(), then write assertions with pm.test(name, fn) wrapping pm.expect(value).to.eql(expected). A simple shape: const body = pm.response.json(); pm.test("status is 200", () => pm.response.to.have.status(200)); pm.test("has id", () => pm.expect(body.id).to.be.a("number")); pm.test("email matches", () => pm.expect(body.email).to.eql("user@example.com")). Each pm.test creates a separate assertion result that shows pass/fail in the Test Results tab and in Newman output. pm.expect is the bundled Chai assertion library — you have .to.equal, .to.eql (deep equality), .to.have.property, .to.be.an("array"), .to.have.lengthOf(n), and the full Chai surface. Tests run after every response, including in Newman CI runs.
How do I use variables inside a JSON body?
Wrap the variable name in double curly braces inside the JSON body — Postman interpolates {{varName}} at send time. Example: {"email": "{{userEmail}}", "token": "{{authToken}}"}. The variable can come from any scope: collection variables (per-collection, persists with the collection), environment variables (selected via the environment dropdown), or global variables (rarely recommended). Set values via the environment quick-look (the eye icon in the top right) or programmatically in scripts with pm.environment.set("authToken", value). Note: the JSON body editor flags {{varName}} as invalid JSON before substitution — that is expected. Postman substitutes the variable text before parsing on the wire, so the actual request body is valid. For values that should be JSON-encoded (escaped strings, embedded objects), set the variable in a pre-request script with JSON.stringify and reference the result.
How do I run Postman tests from CI?
Use Newman — the official command-line collection runner from Postman. Install with npm install -g newman (current major version is 6.x as of 2026). Export your collection from the Postman app as a v2.1 JSON file, commit it to your repo alongside an environment JSON file, then in your CI job run: newman run postman/collection.json -e postman/env-staging.json --reporters cli,json --reporter-json-export newman/report.json. Newman exits with a non-zero status code if any pm.test fails, which fails the CI job. The cli reporter prints colored output, and the json reporter writes a machine-readable report you can upload as an artifact or post to a status check. For GitHub Actions, Newman runs in any Node-based job; for GitLab, Jenkins, or CircleCI, the command line is the same. Pair this with our JSON in CI/CD guide for caching and parallelization patterns.
How do I extract a value from a JSON response and reuse it?
In the Tests tab of the first request, parse the response and store the value to a variable scope that the next request can read. Common pattern: const body = pm.response.json(); pm.collectionVariables.set("authToken", body.token); pm.collectionVariables.set("userId", body.user.id). Now any subsequent request in the same collection can reference {{authToken}} in its Authorization header (Bearer {{authToken}}) and {{userId}} in its URL (/users/{{userId}}). Choose the scope deliberately: pm.environment.set persists in the active environment (good for tokens that vary by env), pm.collectionVariables.set lives with the collection (good for derived values inside one run), and pm.variables.set is request-scoped (cleared after the request completes). Newman respects all three scopes the same way the GUI does, so the chain works identically in CI.
What is the difference between raw JSON and form-data in Postman?
Raw JSON sends a single application/json body — the editor contains a JSON document, Postman sets Content-Type: application/json, and the server parses it with its JSON parser. Use this for REST APIs and any modern HTTP API. Form-data sends a multipart/form-data body — each row is a separate field with a key, a value, and an optional file. Postman sets Content-Type: multipart/form-data; boundary=... and encodes each field with its boundary delimiter. Use form-data for file uploads (the type column lets you switch a row from text to file) and for endpoints that explicitly accept form encoding. There is also x-www-form-urlencoded for application/x-www-form-urlencoded (key=value&key=value), used by older form-style endpoints. If your API expects JSON, never use form-data — the server will see a multipart body and reject it. When in doubt, check the API docs or the OpenAPI spec for the endpoint's requestBody content type.
How do I import an OpenAPI spec into Postman?
In the Postman app, click Import (top left), then drag the OpenAPI file (openapi.yaml or openapi.json) or paste its URL. Postman parses the spec and offers to generate a Collection — pick that option. It creates a folder per tag, a request per operation, populates the URL with the server URL from the spec, fills in path and query parameters as variables, and generates example JSON request bodies from the schemas. The generated requests are real Postman requests you can edit, add tests to, and run in Newman like any other collection. Updates to the spec do not auto-sync; re-import to refresh, or use the Postman API platform's native OpenAPI linking feature for two-way sync. For schema-first workflows, the generated examples are a fast way to bootstrap a working collection without hand-writing every request.
Further reading and primary sources
- Postman Schema Registry — Official registry hosting every published Postman schema, including Collection v2.1.0
- Postman Collection v2.1.0 Schema — The JSON Schema document that every v2.1 collection conforms to
- Postman Learning Center — Writing Tests — Official guide to pm.test, pm.expect, and the sandbox API
- Newman CLI on GitHub — Source, release notes, and reporter ecosystem for the Newman command-line runner
- Chai Assertion Library — Full BDD API reference for the assertion surface bundled in pm.expect