Skip to content

Script reference ​

Everything a script can reach.

This is Sendwire's scripting surface — the objects available inside a pre-request or post-response script. It is not a web API: Sendwire has no server and exposes no HTTP endpoints of its own.

Everything below is available bare as well — response works exactly as sw.response does — so a pasted snippet usually runs unchanged.

There is no pm

Importing a Postman collection rewrites pm to sw automatically. Type it anyway and the editor underlines it before you run anything; run it anyway and you get an error naming the sw equivalent.

sw.response ​

Only available in a post-response script. There is no response before the request has been sent.

codeStatus code, as a number. 200
statusStatus text. "OK"
responseTimeTotal milliseconds.
sizeBody size in bytes.
text()The body, unparsed.
json()The body parsed as JSON. Throws if it is not.
xml()The body as a plain object.
soapBody()Inside <soap:Body>, as an object.
xmlValue(name)The text of the first element with that local name.
xmlValues(name)The text of every element with that local name.
soapFault()The fault as an object, or null.
headers.get(name)One header, case-insensitively.
headers.has(name)Whether it is present.
headers.all()Every header, as { key, value }.
connectionAddress, port, reuse, ALPN.
certificateThe leaf certificate the server presented.
js
sw.test("the order was created", () => {
  sw.expect(sw.response.code).to.equal(201)
  sw.expect(sw.response.json().status).to.equal("active")
  sw.expect(sw.response.headers.get("content-type")).to.include("json")
})

Namespace prefixes are ignored by the XML helpers, so soapBody().return works whether the server wrote <return> or <ns2:return>.

sw.environment ​

The active environment. Values set here are visible to every later request as {{name}}, and are written to your workspace.

get(key)The value, or undefined.
set(key, value)Store it. Non-strings are stringified.
unset(key)Remove it.
has(key)Whether it is set.
toObject()Everything, as a plain object.

sw.globals and sw.collectionVariables are the same object under different names, so Postman scripts that use them keep working.

js
// Capture it in one request
sw.environment.set("token", sw.response.json().data.token)

// Spend it in the next
// Authorization: Bearer {{token}}

sw.environment.get("token")
sw.environment.has("token")
sw.environment.unset("token")

sw.variables ​

Reading, plus one thing environment cannot do.

get(key)The value.
set(key, value)Same as environment.set.
has(key)Whether it is set.
replaceIn(text)Substitute every {{name}} in a string.

replaceIn is how you reach the dynamic values:

js
sw.environment.set("nonce", sw.variables.replaceIn("{{$guid}}"))
sw.environment.set("sentAt", sw.variables.replaceIn("{{$isoTimestamp}}"))

sw.request ​

The request about to be sent. Only useful in a pre-request script — afterwards it has already gone.

js
sw.request.headers.upsert({
  key: "X-Signature",
  value: sw.crypto.hmacSha256(sw.environment.get("apiSecret"), "message")
})

upsert replaces any header of the same name rather than adding a second one.

sw.test and sw.expect ​

js
sw.test("name", () => {
  sw.expect(actual).to.equal(expected)
})

Each test is one line in the Scripts tab, and one assertion in a suite run or a CI report. A test that throws fails; a test that returns passes.

The matchers, all of which chain through .to, .be and .not:

.equal(x)Strictly equal.
.eql(x)Deeply equal.
.above(n) / .below(n)Greater / less than.
.least(n) / .most(n)At least / at most.
.include(x)Substring, array member, or subset of an object.
.match(re)Matches a regular expression.
.property(key)Has that own property.
.a(type)"string", "number", "array", "object", "null" …
.lengthOf(n)Has that length.
.okTruthy.
.nullExactly null.
js
sw.expect(sw.response.responseTime).to.be.below(500)
sw.expect(sw.response.json().items).to.have.lengthOf(2)
sw.expect(sw.response.json().name).to.not.equal("")

sw.crypto ​

Signing, hashing and nonces, without pulling in a library.

hmacSha256(key, message)Hex.
hmacSha256Base64(key, message)Base64.
hmacSha1Base64(key, message)Base64. Some older APIs still want this.
sha256(message)Hex.
md5(message)Hex. Checksums only — not for anything security-bearing.
base64(text)Encode.
randomUUID()A v4 UUID.
randomInt(min, max)Inclusive of both ends.
nonce(bytes = 16)Random hex.

A signed request, in a pre-request script:

js
const stamp = Math.floor(Date.now() / 1000)
const nonce = sw.crypto.nonce()

const signature = sw.crypto.hmacSha256(
  sw.environment.get("apiSecret"),
  `${stamp}\n${nonce}\nPOST\n/v1/orders`
)

sw.request.headers.upsert({ key: "X-Signature", value: signature })
sw.request.headers.upsert({ key: "X-Timestamp", value: String(stamp) })

sw.sendRequest ​

Another request from inside a script — a token fetch before the real call, most often. Pre-request scripts wait for it.

js
sw.sendRequest("https://auth.example.com/token", (error, response) => {
  if (error) throw error
  sw.environment.set("token", response.json().access_token)
})

Or with options, and awaited:

js
const response = await sw.sendRequest({
  url: "https://auth.example.com/token",
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ client_id: sw.environment.get("clientId") })
})
sw.environment.set("token", response.json().access_token)

There is a limit on how many a single script may send, so a loop that has lost its exit condition stops rather than hammering somebody's API.

sw.console ​

log, warn, error and info. Output appears in the Scripts tab beside the test results, not in a devtools console you would have to open.

Also available ​

btoa and atob for base64, and the ordinary JavaScript standard library — JSON, Math, Date, Object, Array, String, RegExp, Promise. It is real JavaScript, so if it runs in JavaScript it runs here.

Not available ​

No require, no import, no filesystem, no network except sw.sendRequest. Scripts run in a sandbox with a time limit, so an accidental infinite loop fails that request instead of freezing the application.

Local-first. No account. No cloud. Telemetry off by default.