Skip to content

Scripting API Reference

The pro global is the only entry point a script needs. Everything you can read or change lives under it. This page documents every method exposed by Probe's embedded QuickJS runtime, grouped by namespace.

pro is available in Composer pre-request and test scripts, Flow script nodes and script assertions, and the REST/MCP script-execute call. Script rules on live traffic don't use it: they run handleRequest / handleResponse in an external runtime — see the Scripting Overview.

gmp and pm are aliases of pro. Anywhere you see pro.foo below, gmp.foo and pm.foo work identically.

The outgoing request. Mutable in pre-request scripts, read-only in test scripts (assignments warn and are ignored).

In Composer, a pre-request script's edits change the request that goes out — on a single send, on every request of a collection run, and on REST/MCP sends. The saved request isn't modified. The Console shows the request as it was sent, and so does History for a single or REST/MCP send. A script sees the request before {{variables}} are resolved, the same way Postman does: use pro.variables.replaceIn(...) when you need resolved text. Probe resolves the variables in whatever the script leaves.

The headers Probe adds later aren't visible to the script and can't be removed by it: the Auth tab's header, the collection's default headers, the cookies, and the body's Content-Type and Content-Length. A header the script sets wins over the Auth tab and the collection's default headers, the same way a header on the Headers tab does. The Cookie header (cookie jar and Cookies tab) and a body's Content-Type are set last.

Get or set the HTTP method.

pro.request.method; // "GET"
pro.request.method = 'POST'; // overrides the method

Get or set the full URL string. A script that points the URL at another host still gets the Auth tab's credential and the collection's default headers attached, as in Postman, so only send a request to a host you trust with them.

pro.request.url;
pro.request.url = 'https://staging.example.com/api/v2/users';

A header collection with these methods. Header names match in any letter case, as in HTTP: get('content-type') finds Content-Type.

MethodBehavior
add({key, value})Set a header. Equivalent to upsert.
upsert({key, value})Set a header, replacing any existing entry with the same name.
remove(key)Delete a header by name.
get(key)Return the header value, or undefined.
has(key)Return true if the header is present.
toObject()Snapshot of all headers as a plain object.
pro.request.headers.upsert({ key: 'Authorization', value: 'Bearer ' + token });
pro.request.headers.remove('Cookie');
if (!pro.request.headers.has('User-Agent')) {
pro.request.headers.add({ key: 'User-Agent', value: 'probe-script/1.0' });
}

Get or set the request body as a raw string. For JSON bodies, you handle JSON.stringify yourself.

For a GraphQL request it's the {"query", "variables"} JSON Probe builds from the query and variables editors, and a replacement is sent as application/json. For a form-data or file body, setting it is ignored and logs pro.request.body.raw is ignored for form-data and file bodies: the form fields or the file are sent as they are.

pro.request.body.raw; // current body string
pro.request.body.raw = JSON.stringify({ a: 1 }); // replace the body

Available in response scripts only. Read-only — you can inspect the response and assert on it, but you can't rewrite it from a script. Use Map Local or Breakpoints for that.

HTTP status code as a number.

pro.expect(pro.response.code).to.equal(200);

Status text — "OK", "Not Found", etc.

Server response time in milliseconds.

pro.expect(pro.response.responseTime).to.be.below(500);

Response body size in bytes.

The raw response body as a string.

console.log(pro.response.body);

Returns the body as a string. Equivalent to pro.response.body, kept for Postman parity.

Parses the body as JSON. Throws if the body isn't valid JSON.

const data = pro.response.json();
console.log(data.userId);

Same shape as request headers, but read-only:

MethodBehavior
get(key)Header value or undefined.
has(key)true if the header is present.
toObject()All headers as a plain object.
const ct = pro.response.headers.get('Content-Type');
pro.expect(ct).to.contain('application/json');

Cookies parsed from Set-Cookie headers, with the same get / has / toObject interface.

if (pro.response.cookies.has('session')) {
pro.variables.replaceIn(pro.response.cookies.get('session'));
}

A merged view across all variable scopes, plus local variables. Precedence is local > the variables of a REST or MCP send > collection > environment > globals: the same order the request resolves {{key}} in, so a script reads the value that is sent. To save a value, use one of the scoped objects (pro.environment, pro.globals, pro.collectionVariables).

Returns the value, or undefined if the key is unknown in every scope.

Creates a local variable, the same as Postman's. It wins over every scope, and {{key}} resolves to it for the rest of that send: the request itself, the later scripts and the test scripts. In a collection run, it lasts until the run ends. A local variable is never saved.

pro.variables.set('requestTime', String(Date.now())); // {{requestTime}} in a header or the body
const baseUrl = pro.variables.get('baseUrl');

Returns true if any scope has the key.

Returns the merged map, with the same precedence: a local variable wins a conflict, then a REST or MCP send's variables, then the collection.

Resolves {{var}} placeholders in a string using the same precedence. Also resolves dynamic variables prefixed with $.

const url = pro.variables.replaceIn('{{baseUrl}}/users/{{userId}}');

pro.environment / pro.globals / pro.collectionVariables

Section titled “pro.environment / pro.globals / pro.collectionVariables”

Three scoped variable stores. Each exposes the same methods. In Composer, what a pre-request or test script writes is saved as soon as the script finishes, so the request that follows, and the rest of the same send, already see it:

ScopeWhere a write goes
pro.environmentThe active environment of the request's collection: the variable's current value. A variable that doesn't exist yet is added with that current value.
pro.collectionVariablesThe same active environment. Probe has no separate store for collection variables: a Postman collection's variables import into an environment.
pro.globalsThe global variables, as their current value.
pro.variables (local)Nowhere: see pro.variables.set.
  • A script never changes a variable's initial value. unset and clear clear the current value, so the variable falls back to its initial value. A variable that has no initial value is removed.
  • Setting a disabled variable enables it, so the new value is used.
  • A secret stays secret: it keeps its flag and its value goes to the keychain.
  • With no active environment, pro.environment and pro.collectionVariables writes aren't saved, and each one logs pro.environment.set("token") was not saved: no active environment (with the call and the name it was given). pro.globals still works.
  • A REST/MCP send that names an environment reads it and saves its writes to it, instead of the active environment.
  • A script that throws an error the script doesn't catch changes nothing: none of its request edits or variable writes apply. If it's a pre-request script, the request still goes out, unchanged. A syntax error or a timeout in a pre-request script stops a single or REST/MCP send instead; a collection run still sends that request.

Flow script nodes use the same calls differently: a variable set there becomes one of the node's outputs. See Scripting in Flows.

MethodBehavior
get(key)Read a value.
set(key, value)Write a value. Coerced to string.
unset(key)Delete a value.
has(key)Test for presence.
toObject()Snapshot of the scope.
clear()Remove every key in this scope.
name (getter)The scope name — "environment", "globals", or "collection".
// Capture a token from a login response and stash it for later requests.
pro.environment.set('authToken', pro.response.json().token);
// Wipe a stale value.
pro.globals.unset('deviceId');

Native Rust implementations exposed as JS functions — fast and deterministic.

SHA-256 hex digest.

pro.crypto.sha256('hello');
// "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

SHA-1 hex digest.

MD5 hex digest.

HMAC-SHA256 hex digest.

const sig = pro.crypto.hmacSha256(timestamp + body, secret);
pro.request.headers.upsert({ key: 'X-Signature', value: sig });

HMAC-SHA1 hex digest.

Standard Base64 encode.

pro.crypto.base64Encode('Hello'); // "SGVsbG8="

Standard Base64 decode. Returns a string starting with Error: on bad input.

Percent-encode for URLs.

pro.crypto.urlEncode('hello world&foo=bar');
// "hello%20world%26foo%3Dbar"

Percent-decode. Returns a string starting with Error: on bad input.

Decode a JWT — splits on ., base64-decodes the header and payload, and returns a parsed object:

{
header: { alg: 'HS256', typ: 'JWT' },
payload: { sub: '1234567890', name: 'John' },
signature: 'abc123...'
}
const auth = pro.request.headers.get('Authorization') || '';
const token = auth.replace(/^Bearer\s+/, '');
const decoded = pro.crypto.jwtDecode(token);
console.log('exp:', decoded.payload.exp);

The function does not verify the signature.

The assertion library, modelled on Chai's BDD chain. pro.test wraps a block of assertions so one failure doesn't kill the whole script and so each block shows up in the scripting console with pass/fail status.

Run fn and record the outcome under name. Throws inside fn are caught and turned into failures.

pro.test('status is 200', function () {
pro.expect(pro.response.code).to.equal(200);
});

Returns an assertion chain modelled on Chai's expect BDD API. The chain accepts these passthrough words for readability — they don't change behavior: to, be, been, is, that, which, and, has, have, with, at, of, same, but, does, still, also.

It also accepts these modifiers that change the next assertion: .deep (structural equality), .nested (dotted/bracket property paths), .own (own properties only), .any / .all (for .keys).

MethodBehavior
.equal(v) / .equals(v) / .eq(v)Strict ===. .deep.equal(v) compares structurally.
.eql(v) / .eqls(v)Deep (structural) equality — not key-order sensitive.

.not flips the next assertion. Apply it anywhere in the chain.

pro.expect(200).to.not.equal(404);
MethodBehavior
.a(type) / .an(type)Check typeof ('string', 'number', 'object', 'array', 'null', 'undefined', etc.).
.instanceof(Ctor) / .instanceOf(Ctor)value instanceof Ctor.
pro.expect('hello').to.be.a('string');
pro.expect([1, 2, 3]).to.be.an('array');
MethodBehavior
.include(v) / .includes(v) / .contain(v) / .contains(v)Substring (string), element (array), or subset of keys/values (object). .deep.include(v) matches members/values structurally.
.match(regex) / .matches(regex)Regex test against the value.
.string(substr)Value is a string that contains substr.
.oneOf(arr)Value is one of arr (common for pro.expect(pro.response.code).to.be.oneOf([200, 201])).
.members(arr)Same elements as arr, order-independent.
.keys(...names) / .key(name)Object has the named keys. .all.keys(...) requires all (default); .any.keys(...) requires at least one. Accepts an array or a vararg list.
pro.expect('hello world').to.include('world');
pro.expect([1, 2, 3]).to.include(2);
pro.expect({ id: 1, name: 'Ada' }).to.include({ name: 'Ada' });
pro.expect(pro.response.json()).to.deep.include({ created: true });
pro.expect(pro.response.headers.get('Content-Type')).to.match(/json/);
MethodBehavior
.above(n) / .greaterThan(n) / .gt(n)value > n.
.below(n) / .lessThan(n) / .lt(n)value < n.
.least(n) / .gte(n)value >= n.
.most(n) / .lte(n)value <= n.
.within(min, max)min <= value <= max.
.closeTo(n, delta) / .approximately(n, delta)`

.lengthOf(n) / .length(n) — checks value.length === n.

pro.expect(pro.response.json().items).to.have.lengthOf(10);

These trigger on access — no parentheses.

GetterBehavior
.trueStrict === true.
.falseStrict === false.
.null=== null.
.undefined=== undefined.
.NaNNumber.isNaN(value).
.exist / .existsNot null and not undefined.
.okTruthy.
.emptyEmpty string, empty array, or empty object.
.finiteA finite number (not NaN / Infinity).
pro.expect(pro.response.cookies.has('session')).to.be.true;
pro.expect(data.token).to.exist;
pro.expect(data.error).to.be.null;

.property(name) walks into a property — and optionally asserts its value. After this call, the chain's value becomes that property. Use .nested.property('a.b[1]') for a path, and .own.property(name) to require an own (non-inherited) property.

pro.expect(data).to.have.property('user').and.to.have.property('id', 42);
pro.expect(data).to.have.nested.property('items[0].id');
MethodBehavior
.throw([matcher]) / .throws(...)The value (a function) throws; optional matcher is a substring, regex, or error constructor.
.satisfy(fn) / .satisfies(fn)fn(value) returns truthy.
pro.expect.fail(msg)Force-fail with a message.

.jsonSchema(schema) — validates against a small JSON Schema subset: type (object, array, string, number, integer, boolean), enum, minimum, maximum, minLength, maxLength, required (array of names), and nested properties.

pro.expect(pro.response.json()).to.have.jsonSchema({
type: 'object',
required: ['userId', 'name'],
properties: {
userId: { type: 'integer' },
name: { type: 'string', minLength: 1 },
},
});

Postman-style assertions that read straight off the response, so you don't have to pull out pro.response.code yourself. Each throws on mismatch (so a pro.test block records the failure) and supports .not.

AssertionBehavior
.to.have.status(code)Status code equals code (a number), e.g. 200.
.to.have.status(name)Status reason text equals name (a string), e.g. "Created".
.to.have.header(name)Response has the header (case-insensitive).
.to.have.header(name, value)Header equals value.
.to.have.body()Body is non-empty.
.to.have.body(string | regex)Body equals the string, or matches the regex.
.to.have.jsonBody()Body parses as JSON.
.to.have.jsonBody(path)JSON body has the dotted/bracket path.
.to.have.jsonBody(path, value)JSON body at path deep-equals value.
.to.have.jsonBody(object)Whole JSON body deep-equals object.
.to.have.jsonSchema(schema)JSON body validates against schema.
.to.be.okStatus is exactly 2xx.
.to.be.successStatus is 2xx.
.to.be.info / .redirection / .clientError / .serverErrorStatus is 1xx / 3xx / 4xx / 5xx.
.to.be.errorStatus is ≥ 400.
pro.test('created', function () {
pro.response.to.have.status(201);
pro.response.to.have.header('Location');
pro.response.to.have.jsonBody('id');
pro.response.to.not.be.error;
});

pm is a full alias of pro, and Probe also ships the response-cookie / variable / info surfaces Postman scripts expect, so most collections run unchanged:

Postman APINotes
pm.test, pm.test.skip, pm.test.index().skip records a skipped test; .index() returns tests run so far.
pm.expect(...) + pm.expect.fail(...)The Chai chain documented above.
pm.response.*.code, .status, .responseTime, .responseSize, .text(), .json(), .reason(), .headers.get/has/all/each (case-insensitive), .cookies.get/has, and the .to.have.* / .to.be.* assertions above.
pm.cookies.get/has/toObjectTop-level cookie access for the response's domain.
pm.variables.get, .set (creates a local variable for the rest of the send or run), .has, .replaceIn, .toObject.
pm.environment / pm.collectionVariables / pm.globals.get, .set, .unset, .has, .clear, .toObject.
pm.iterationData.get/has/toObjectRead-only data-file row (empty outside a data-driven run).
pm.info.eventName, .iteration, .iterationCount, .requestName, .requestId.

Older collections that predate pm.* also work through these legacy globals:

Legacy globalMaps to
tests['name'] = boolEach key becomes a pass/fail test.
responseBody / responseCode.code / responseCode.name / responseTimeThe response body string / status code / reason / timing.
postman.setEnvironmentVariable / getEnvironmentVariable / clearEnvironmentVariable(s)pm.environment.set / .get / .unset / .clear.
postman.setGlobalVariable / getGlobalVariable / clearGlobalVariable(s)pm.globals.*.
postman.getResponseHeader(name)pm.response.headers.get(name).
postman.setNextRequest(name)pm.execution.setNextRequest(name) (not supported yet).

Same console you'd use anywhere. Output goes to the Composer console, or to the run report for Flow scripts.

MethodBehavior
console.log(...args) / console.info(...)Info-level message. Args are stringified; objects use JSON.stringify.
console.warn(...)Warning-level message.
console.error(...)Error-level message.
console.debug(...)Debug-level message.
console.table(value)Pretty-prints value as JSON.
console.time(label) / console.timeEnd(label)Wall-clock timer. timeEnd logs <label>: <ms>ms.
console.clear()Empty the captured log buffer for this run.

Make a blocking HTTP request from inside a script. Capped at 5 sub-requests per execution with a 10 second per-request timeout. TLS certificates are verified; to reach a server with a self-signed certificate (a local dev server), opt in per call with insecure: true.

urlOrOptions is either a URL string (defaults to GET) or an options object:

FieldTypeDefault
urlstringrequired
methodstring'GET'
headersobject{}
bodystring''
insecurebooleanfalse — true skips TLS certificate verification for this call only

Returns a response object synchronously:

FieldType
codenumber — HTTP status, 0 on transport error
statusstring — reason phrase, or "Error: ..." on failure
headersobject
bodystring
responseTimenumber — milliseconds
text()function — returns body
json()function — parses body

If a callback(err, response) is provided, it's also invoked. err is always null — transport errors arrive as code: 0.

const res = pro.sendRequest({
url: 'https://api.example.com/auth/refresh',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken: pro.environment.get('refreshToken') }),
});
if (res.code === 200) {
pro.environment.set('authToken', res.json().token);
}

Flow control for the collection runner, from Postman. Probe accepts both calls, so imported scripts run without errors, but no send acts on them yet.

Not supported yet. In Postman it makes the runner jump to the request named name after this one. In Probe the run goes on in order.

Not supported yet. In Postman it skips the current request. In Probe the request is still sent.

Read-only metadata about the current execution.

PropertyType
pro.info.requestNamestring — display name of the request being scripted.
pro.info.requestIdstring — internal ID.

A handful of {{...}} placeholders resolve to a fresh value every time. Use them inside pro.variables.replaceIn(...), in Composer fields, or in scripted strings.

PlaceholderProduces
{{$guid}}A v4 UUID (e.g. 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed).
{{$timestamp}}Unix timestamp in seconds.
{{$isoTimestamp}}ISO 8601 UTC timestamp like 2026-05-08T13:24:31.412Z.
{{$randomInt}}Random integer in [0, 1000).
{{$randomEmail}}userN@example.com with a random integer.
const url = pro.variables.replaceIn('https://api.example.com/orders?nonce={{$guid}}&t={{$timestamp}}');
LimitValue
Wall-clock timeout per script10 seconds
Memory cap64 MB
Stack size1 MB
pro.sendRequest calls per script5
pro.sendRequest per-request timeout10 seconds

No require, import, fetch, XMLHttpRequest, process, Buffer, fs, DOM, or timers (setTimeout/setInterval).