Skip to content

pm API reference

This page lists everything a script can reach: the pm object, console, the legacy Postman globals, and the few extra functions the sandbox provides. Anything not on this page is not available; the last section lists the Postman APIs that exist but throw.

Signatures use TypeScript-style notation. ? marks an optional argument.

NameWhat it is
pmThe script API described on this page
consoleScript console: log, info, warn, error, debug, dir, trace, clear
atob(text), btoa(text)Base64 decode and encode (Latin-1 text)
require(name), pm.require(name)The built-in libraries: lodash, crypto-js, moment, ajv, …
CryptoJS, _, tv4, cheerioPostman’s library globals: crypto-js, lodash, tv4 and cheerio, loaded when first used
xml2Json(text)XML to a JSON object, as in Postman (xml2js; a single child element is not an array). Throws for text that isn’t XML
crypto.getRandomValues(array), crypto.randomUUID()Secure random numbers and UUIDs
postman, tests, responseBody, responseCode, responseHeaders, responseTime, environment, globals, data, iterationThe legacy Postman API
Standard JavaScriptJSON, Math, Date, RegExp, Array, Object, Map, Set, Promise, queueMicrotask, typed arrays and the other built-ins of the language

See Sandbox and limits for what is not available (network, files, timers, npm packages).

Read-only facts about the current script.

PropertyTypeDescription
pm.info.eventName"prerequest" or "test"Which script is running: "prerequest" in pre-request scripts, "test" in post-response scripts (Postman’s names)
pm.info.requestNamestringThe request’s name
pm.info.requestIdstringThe request’s file path under requests/, for example Users/Get user.yaml. Empty for a request that isn’t saved.
pm.info.iterationnumberThe current iteration of a collection run, starting at 0. Always 0 for a single send.
pm.info.iterationCountnumberHow many iterations the run has. 1 for a single send.
if (pm.info.iteration === 0) console.log("first pass of", pm.info.requestName);

Five objects give access to variables. pm.variables looks through every scope; the others read and write one scope each.

ObjectScopeWritable
pm.variablesLocal values for this send (or the whole run) when writing; every scope when readingYes
pm.environmentThe active environmentYes
pm.collectionVariablesWorkspace variables (in zorvik.yaml)Yes
pm.globalsGlobal variablesYes
pm.iterationDataThe current row of the run’s data fileNo

pm.variables.get(name) and {{name}} in a request look through the scopes in this order and use the first one that has the name:

  1. Values given with --var on the command line (scripts can’t change these)
  2. pm.variables (local values)
  3. The current data file row (pm.iterationData)
  4. The active environment (pm.environment)
  5. Workspace variables (pm.collectionVariables)
  6. Global variables (pm.globals)

Methods of pm.environment, pm.collectionVariables and pm.globals

Section titled “Methods of pm.environment, pm.collectionVariables and pm.globals”
MethodReturnsDescription
get(name: string)anyThe variable’s value, or undefined when the scope doesn’t have it
set(name: string, value: any)undefinedSets the variable. A null or undefined name does nothing.
has(name: string)booleanWhether the scope has the variable
unset(name: string)undefinedRemoves the variable from the scope
clear()undefinedUnsets every variable of the scope
toObject()objectA copy of the scope as { name: value }
toJSON()objectSame as toObject()
replaceIn(text: string)stringtext with {{name}} replaced by this scope’s values and dynamic variables

pm.environment also has:

PropertyTypeDescription
pm.environment.namestring or undefinedName of the active environment, undefined when none is active
pm.environment.set("token", pm.response.json().access_token);
if (!pm.environment.has("userId")) pm.environment.set("userId", "1");
console.log(pm.environment.name, pm.environment.toObject());

pm.variables has the same methods, but reads across all scopes:

MethodReturnsDescription
get(name: string)anyThe value from the highest-precedence scope that has name, or undefined
has(name: string)booleanWhether any scope has name
set(name: string, value: any)undefinedSets a local value: it wins over the data row, environment, workspace and globals for the rest of the send, or for the rest of a collection run
unset(name: string)undefinedRemoves a local value (the other scopes are untouched)
clear()undefinedRemoves every local value
toObject()objectAll scopes merged, higher precedence winning
toJSON()objectA copy of the local values only
replaceIn(text: string)stringtext with {{name}} replaced using every scope, then dynamic variables
pm.variables.set("page", 2);
const url = pm.variables.replaceIn("{{base}}/items?page={{page}}");

The current row of the run’s data file (see Data files). It’s read-only and empty in a single send.

MethodReturnsDescription
get(name: string)anyThe column’s value, or undefined
has(name: string)booleanWhether the row has the column
toObject()objectThe row as { column: value }
toJSON()objectSame as toObject()
replaceIn(text: string)stringtext with {{column}} replaced by the row’s values

CSV values are always strings. JSON values keep their type: pm.iterationData.get("count") returns the number 3 for {"count": 3}.

Variables are text outside of scripts. When a script sets a value, it’s stored like this:

Value passed to setStored as
A stringThe string itself
A number or booleanIts text, for example "5" or "true"
An object or arrayJSON, for example {"x":1}
undefinedAn empty string
nullThe text "null"

Within the same script, get returns exactly what you passed to set. Later scripts, and {{name}} in requests, see the stored text:

pm.environment.set("count", 5);
pm.environment.get("count") + 1; // 6 in this script
// In the next script: pm.environment.get("count") === "5"

To store structured data, store JSON and parse it when reading:

pm.collectionVariables.set("ids", [1, 2, 3]); // stored as "[1,2,3]"
const ids = JSON.parse(pm.collectionVariables.get("ids")); // in a later script
ScopeIn the appIn zorvik run
pm.variablesDiscarded after the send or runDiscarded after the run
pm.environmentKept on this computer for the active environment. Without an active environment, not kept (with a console warning).Kept until the run ends
pm.collectionVariablesKept on this computerKept until the run ends
pm.globalsKept on this computer, shared by every workspaceKept until the run ends; starts empty

Values kept on this computer live in the app’s data folder, not in the workspace files, and win over the value saved in the file. unset removes the value a script set, so the value saved in the file (if any) applies again from the next send. See Variables and environments.

replaceIn also fills in these dynamic variables when no scope has the name. Nested variables are resolved up to 10 levels deep; names that aren’t found stay as they are.

NameValue
{{$guid}}, {{$uuid}}, {{$randomUUID}}A random UUID v4
{{$timestamp}}Unix time in seconds
{{$timestampMs}}Unix time in milliseconds
{{$isoTimestamp}}The current time in ISO 8601
{{$randomInt}}A whole number from 0 to 1000
{{$randomBoolean}}true or false
{{$randomAlphaNumeric}}One character, a–z or 0–9
{{$randomEmail}}An address like user4821@example.com

These are the same dynamic variables requests support; see Dynamic variables.

The request. In a pre-request script you can change it; in a post-response script it’s what was sent (read-only in effect). See what a pre-request script sees.

MemberTypeDescription
pm.request.urlURL objectThe URL. Assign a string to replace it: pm.request.url = "https://…".
pm.request.methodstringThe method. Assigning sets it in upper case: pm.request.method = "post" sends POST.
pm.request.headersheader listThe request’s headers (names compared without case)
pm.request.bodybody objectThe body text
pm.request.addHeader(header)undefinedSame as headers.add(header)
pm.request.upsertHeader(header)undefinedSame as headers.upsert(header)
pm.request.removeHeader(name: string)undefinedSame as headers.remove(name)
pm.request.getHeaders()objectThe headers as { name: value }
pm.request.toJSON()object{ url, method, header: [{key, value}], body: {mode, raw} }
MemberReturnsDescription
toString()stringThe whole URL text. Template strings work too: `${pm.request.url}`
toJSON()stringSame as toString()
update(url: string)undefinedReplaces the whole URL
getHost()stringThe host, for example api.example.com
getPath()stringThe path, / when there is none
getQueryString()stringThe query without ?, or an empty string
getPathWithQuery()stringPath and query, for example /users?page=1
getRemote()stringHost and port, for example api.example.com:8443 (no port when none is written)
protocolstring or undefinedFor example https
hoststring[]The host split at dots: ["api", "example", "com"]
portstring or undefinedThe port written in the URL
pathstring[]The path segments: ["users", "42"]
hashstring or undefinedThe part after #
queryquery listThe query parameters; changing them rewrites the URL

In a pre-request script the URL is not resolved yet, so parts may be {{variables}}: for {{base}}/users, getHost() returns {{base}}.

Pre-request script
pm.request.url.query.upsert({ key: "page", value: "2" });
pm.request.url.query.add("debug=true");
pm.request.url.query.remove("legacy");
console.log(pm.request.url.toString());

Query values are written into the URL text as you give them. Encode them yourself with encodeURIComponent when they contain &, =, # or other special characters.

MemberTypeDescription
rawstringThe body text. Assign to replace it; objects are stored as JSON.
mode"raw"Always "raw"
update(value: string or {raw})undefinedReplaces the body: update("text") or update({ raw: "text" })
isEmpty()booleanWhether the body is empty
toString()stringThe body text
toJSON()object{ mode: "raw", raw }
Pre-request script
const body = JSON.parse(pm.request.body.raw || "{}");
body.sentAt = new Date().toISOString();
pm.request.body.raw = JSON.stringify(body);

pm.request.headers, pm.response.headers and pm.request.url.query are Postman-style property lists of { key, value } items. Header names are compared without case; query keys with case.

MethodReturnsDescription
get(name)string or undefinedValue of the first item named name
one(name){key, value} or undefinedThe first item named name
has(name, value?)booleanWhether an item named name exists (with exactly value, when given)
all(){key, value}[]Copies of all items, in order
toObject()object{ key: value }; with duplicates the last one wins
count()numberNumber of items
each(fn), map(fn), filter(fn), find(fn)as for arraysArray methods over all()
add(item, value?)undefinedAdds an item (duplicates allowed)
append(item, value?)undefinedSame as add
upsert(item, value?)undefinedSets the value of the first item with that key, or adds it
remove(nameOrPredicate)undefinedRemoves every item with that key, or every item for which predicate({key, value}) is true
clear()undefinedRemoves all items
toJSON(){key, value}[]Same as all()
toString()stringHeaders: Name: value lines. Query: the query string.

An item can be given as { key, value }, { name, value }, a "Name: value" string (headers), a "key=value" string (query), or as two arguments (name, value). Values are stored as text. A query parameter without = has the value null.

pm.request.headers.add({ key: "X-Trace", value: "on" });
pm.request.headers.add("X-Client: docs");
pm.request.headers.upsert("Accept", "application/json");
pm.request.headers.remove((h) => h.key.startsWith("X-Debug-"));

pm.response.headers has the same methods, but it’s a copy: changing it does nothing.

Available in post-response scripts. In pre-request scripts pm.response is undefined.

MemberTypeDescription
codenumberThe status code, for example 200
statusstringThe reason phrase, for example OK (the server’s, or the standard one when the server sends none, as in HTTP/2)
reason()stringSame as status
responseTimenumberTotal time in milliseconds (may have decimals)
responseSizenumberBody size in bytes
headersheader listThe response headers (read-only copy, names without case)
text()stringThe body as text (invalid UTF-8 replaced)
json()anyThe body parsed as JSON. Throws SyntaxError: pm.response.json(): the response body is not valid JSON (…) when it isn’t.
toresponse assertionChai-style assertions on the response; see Response assertions
cookiescookie listThe cookies this response set (Set-Cookie); see pm.cookies for its methods
events{event, data, id}[]Only for Server-Sent Events requests in a collection run; see below
toJSON()object{ code, status, header: [{key, value}], body }
const json = pm.response.json();
console.log(pm.response.code, pm.response.status, pm.response.responseTime);
console.log(pm.response.headers.get("content-type"));

Bodies larger than 16 MB reach scripts cut to their first 16 MB, with a console warning. See limits.

For an SSE request in a collection run, pm.response.events is the list of events read before reading stopped. Each event is:

FieldTypeDescription
eventstringThe event name; "message" for events sent without an event: line
datastringThe event’s data (lines joined with \n)
idstring or nullThe last event ID in effect when the event arrived (an id: from an earlier event carries over), or null

For an SSE request, pm.response.text() is the events in wire format (event:, id: and data: lines). For every other request pm.response.events is undefined. See Repeat until and event streams.

const done = pm.response.events.find((e) => e.event === "done");
pm.test("job finished", () => pm.expect(done).to.exist);
pm.test(name: string, fn?: () => void | Promise<void>): void
pm.test(name: string, fn: (done: (error?: any) => void) => void): void
pm.test.skip(name: string, fn?: Function): void

Adds a named test. The function runs right away:

  • A function without parameters passes when it returns without throwing, and fails with the error’s message when it throws.
  • An async function (or one that returns a promise) passes when the promise resolves and fails when it rejects. If it never settles, the test fails with The test did not finish: its promise never settled.
  • A function with a parameter gets a done callback. Call done() to pass or done(error) to fail. If done is never called, the test fails with The test did not finish: done() was never called.
  • pm.test(name) without a function, and pm.test.skip(name, fn), record a skipped test. Skipped tests neither pass nor fail.

A failing test doesn’t stop the script. pm.test returns undefined.

pm.test("status is 200", () => pm.response.to.have.status(200));
pm.test("async check", async () => {
const body = await Promise.resolve(pm.response.json());
pm.expect(body.items).to.be.an("array");
});
pm.test.skip("pagination (not deployed yet)", () => {
pm.expect(pm.response.json().next).to.exist;
});

There are no timers in the sandbox, so done and promises can only wait for other promises, not for time to pass.

pm.expect(value: any, message?: string): Assertion

Starts a chai-style assertion. When message is given, it’s put in front of the failure message: status check: expected 1 to equal 2. Every supported chain and assertion is listed in Assertions.

pm.expect(pm.response.json().name).to.be.a("string").and.not.be.empty;

Passing pm.response to pm.expect gives the response assertions: pm.expect(pm.response).to.have.status(200).

MemberDescription
pm.execution.setNextRequest(name: string or null)In a collection run, which request runs next
pm.execution.skipRequest()In a pre-request script: don’t send this request. A single send shows Not sent; a collection run reports it as skipped (with the reason) and goes on. In a post-response script it does nothing.

setNextRequest takes a request’s name, or its path under requests/ (as in pm.info.requestId). After the current request finishes, the run continues with that request instead of the next one in the list. setNextRequest(null) ends the current iteration.

  • It works in pre-request and post-response scripts. The last call wins; a post-response call wins over a pre-request one.
  • A name is looked up among the requests of the run: the first request with that name, then a request with that path.
  • If no request of the run has that name or path, the iteration ends, with a console warning: setNextRequest: no request named 'X' in this run; the iteration ends here.
  • An iteration can send at most 10,000 requests. A loop that goes beyond that stops the run with Stopped: iteration N sent more than 10000 requests (a setNextRequest loop?).
  • A single send ignores it.

postman.setNextRequest(name) does the same. See Collection runner.

Post-response script of 'Check job'
if (pm.response.json().status !== "done") {
pm.execution.setNextRequest("Check job"); // run this request again
}

Sends another request from a script: to get a token before the request, to create test data, or to clean up after it.

Pre-request script: get a token first
const res = await pm.sendRequest({
url: pm.variables.replaceIn("{{baseUrl}}/login"),
method: "POST",
header: { "Content-Type": "application/json" },
body: { mode: "raw", raw: JSON.stringify({ user: pm.environment.get("user"), password: pm.environment.get("password") }) },
});
pm.request.headers.upsert({ key: "Authorization", value: "Bearer " + res.json().token });
Form
pm.sendRequest(url)A GET of that URL
pm.sendRequest({ url, method, header, body })header: [{key, value, disabled}], { name: value } or "Name: value" lines. body.mode: raw (raw text; with options.raw.language: "json" it gets Content-Type: application/json), urlencoded ([{key, value}]), formdata (text fields), graphql ({query, variables})
pm.sendRequest(request, (err, res) => …)Calls back later with an error or the response (with code, headers, json(), cookies…)
await pm.sendRequest(request)Without a callback it returns a promise. await works at the top level of a script.
  • {{variables}} in the request are not filled in, as in Postman: use pm.variables.replaceIn.
  • It uses the app’s settings (proxy, certificates, the cookie jar) and the time left of the script’s time limit. A request an AI agent’s run makes may only go to hosts the user approved.
  • Each call shows in the Console: pm.sendRequest POST https://api.test/login → 200 OK.
  • A script can send up to 100 requests. A failure (no connection, a timeout) reaches the callback as err, or rejects the promise.

The cookies the cookie jar sends to this request’s URL (before sending in a pre-request script, after the response in a post-response script). pm.response.cookies has the same methods for the cookies the response set.

MethodReturns
get(name)The value, or undefined
has(name, value?)Whether the cookie is there (with that value)
one(name){ name, value, domain, path, expires, secure, httpOnly }
all(), toObject(), count(), each(fn), filter(fn), map(fn)The list, { name: value }, how many, …

pm.cookies.jar() reads and changes the jar, for the request’s own site only (the same host, or its subdomains or parent domain): another site’s cookies are refused with Scripts can only use the cookies of the request’s own site.

MethodDoes
get(url, name, (err, value) => …)One cookie’s value
getAll(url, (err, cookies) => …)Every cookie for that URL
set(url, name, value, (err) => …)Store a cookie (path /)
unset(url, name, (err) => …), clear(url, (err) => …)Remove one, or all, for that URL

Without a callback each returns a promise. With the cookie jar switched off (Settings → Requests), the jar methods fail with The cookie jar is off.

Shows the response your way: a table, a list, a summary. The response pane gets a Visualize tab.

Post-response script
const template = `
<table>
<tr><th>Name</th><th>Price</th></tr>
{{#each items}}<tr><td>{{name}}</td><td>{{price}}</td></tr>{{/each}}
</table>`;
pm.visualizer.set(template, { items: pm.response.json() });
Method
set(template, data)Renders a Handlebars template with data (values are HTML-escaped; {{{raw}}} isn’t)
clear()Removes it

The result is plain HTML and CSS in a sandbox: scripts in the template don’t run and nothing loads from the internet, so Postman templates that draw charts with a JavaScript library show only their HTML. Inline <svg> and CSS work. At most 5 MB.

setTimeout, setInterval, setImmediate and their clear… functions work. The script waits for its timers (and the promises they start) before it ends, within its time limit: an interval nobody clears runs until the script is stopped.

setTimeout(() => pm.environment.set("checkedAt", Date.now()), 500);
MethodLevel
console.log(...values)log
console.info(...values)info
console.warn(...values)warn
console.error(...values)error
console.debug(...values)debug
console.dir(...values)log
console.trace(...values)debug
console.clear()Does nothing

Values are joined with spaces. Strings are shown as they are, objects and arrays as JSON, errors as Name: message, functions as [Function: name]. When the first argument is a string with placeholders, these are replaced: %s (text), %d (number), %i (whole number), %f (decimal number), %j, %o and %O (JSON), and %% (a percent sign).

Older Postman collections use these forms. They keep working.

Legacy formEquivalent
tests["name"] = conditionA test named name that passes when condition is truthy (added after the pm.test results)
postman.setEnvironmentVariable(name, value)pm.environment.set
postman.getEnvironmentVariable(name)pm.environment.get
postman.clearEnvironmentVariable(name)pm.environment.unset
postman.clearEnvironmentVariables()pm.environment.clear
postman.setGlobalVariable(name, value)pm.globals.set
postman.getGlobalVariable(name)pm.globals.get
postman.clearGlobalVariable(name)pm.globals.unset
postman.clearGlobalVariables()pm.globals.clear
postman.getResponseHeader(name)pm.response.headers.get(name)
postman.setNextRequest(name)pm.execution.setNextRequest(name)
environmentA copy of the environment’s values when the script started
globalsA copy of the global values when the script started
dataA copy of the data file row
iterationpm.info.iteration
responseBodypm.response.text() (post-response only)
responseCode{ code, name, detail } where name and detail are the reason phrase (post-response only)
responseHeaderspm.response.headers.toObject() (post-response only)
responseTimepm.response.responseTime (post-response only)
tests["Status code is 200"] = responseCode.code === 200;
postman.setEnvironmentVariable("token", JSON.parse(responseBody).token);

These exist in Postman but not in Zorvik. Using them throws an error, so a script fails clearly instead of silently doing nothing.

APIError message
pm.vaultpm.vault is not supported in Zorvik (use secret variables)
pm.execution.runRequest(…)pm.execution.runRequest is not a function (use pm.sendRequest)

pm.vault throws as soon as it’s read, so even if (pm.vault) throws.

require of a package that isn’t built in throws Cannot find module 'name'. Scripts can require only these built-in libraries: …. See Sandbox and limits for the full comparison.