> ## Documentation Index
> Fetch the complete documentation index at: https://docs.liteclient.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scripting API

> JavaScript API for pre-request and post-response scripts in LiteClient

LiteClient supports pre-request and post-response scripts using a Postman-compatible `pm` API. Write JavaScript code that runs before sending a request or after receiving a response to automate workflows, set variables dynamically, and validate responses.

## Overview

Scripts enable advanced automation and testing workflows:

* **Pre-request scripts**: Run before a request is sent (set dynamic headers, compute signatures, etc.)
* **Post-response scripts**: Run after receiving a response (validate data, extract values, run tests)

<Note>
  Scripts run in a sandboxed Node.js `vm` environment with a 10-second timeout and 100KB size limit.
</Note>

## The pm Object

The `pm` object provides the scripting API. It's available globally in all scripts.

### pm.environment

Access and modify environment variables.

<ParamField path="pm.environment.get" type="function">
  Get the value of an environment variable.

  **Signature**: `pm.environment.get(name: string): string | undefined`

  ```javascript theme={null}
  const apiKey = pm.environment.get('API_KEY');
  console.log('Using API key:', apiKey);
  ```
</ParamField>

<ParamField path="pm.environment.set" type="function">
  Set or create an environment variable. Changes are persisted to storage.

  **Signature**: `pm.environment.set(name: string, value: string): void`

  ```javascript theme={null}
  // Extract token from response and save to environment
  const token = pm.response.json().access_token;
  pm.environment.set('AUTH_TOKEN', token);
  ```

  <Note>
    If the variable doesn't exist, it will be created automatically in the current environment.
  </Note>
</ParamField>

<ParamField path="pm.environment.unset" type="function">
  Remove an environment variable.

  **Signature**: `pm.environment.unset(name: string): void`

  ```javascript theme={null}
  pm.environment.unset('TEMP_TOKEN');
  ```
</ParamField>

### pm.globals

Access and modify global variables (shared across all environments).

<ParamField path="pm.globals.get" type="function">
  Get the value of a global variable.

  **Signature**: `pm.globals.get(name: string): string | undefined`

  ```javascript theme={null}
  const baseUrl = pm.globals.get('BASE_URL');
  ```
</ParamField>

<ParamField path="pm.globals.set" type="function">
  Set or create a global variable. Changes are persisted to storage.

  **Signature**: `pm.globals.set(name: string, value: string): void`

  ```javascript theme={null}
  pm.globals.set('REQUEST_COUNT', '42');
  ```
</ParamField>

<ParamField path="pm.globals.unset" type="function">
  Remove a global variable.

  **Signature**: `pm.globals.unset(name: string): void`

  ```javascript theme={null}
  pm.globals.unset('TEMP_VALUE');
  ```
</ParamField>

### pm.variables

Read-only access to resolved variables (combines globals, collection, and environment).

<ParamField path="pm.variables.get" type="function">
  Get the resolved value of a variable following precedence order.

  **Signature**: `pm.variables.get(name: string): string | undefined`

  **Resolution order**: Globals → Collection → Environment (narrowest wins)

  ```javascript theme={null}
  // Gets the most specific value
  const apiUrl = pm.variables.get('API_URL');
  ```

  <Note>
    Use `pm.variables.get()` when you don't care which scope the variable comes from. Use `pm.environment.get()` or `pm.globals.get()` when you need a specific scope.
  </Note>
</ParamField>

### pm.request

Access request data (available in both pre-request and post-response scripts).

<ParamField path="pm.request.url" type="string">
  The request URL (after variable substitution).

  ```javascript theme={null}
  console.log('Sending request to:', pm.request.url);
  ```
</ParamField>

<ParamField path="pm.request.method" type="string">
  The HTTP method (GET, POST, PUT, DELETE, etc.).

  ```javascript theme={null}
  if (pm.request.method === 'POST') {
    // Add special header for POST requests
    pm.request.headers.add('X-Request-Type', 'mutation');
  }
  ```
</ParamField>

<ParamField path="pm.request.headers" type="object">
  Request headers collection.

  **Methods**:

  * `get(name: string): string | undefined` - Get header value
  * `add(name: string, value: string): void` - Add header
  * `remove(name: string): void` - Remove header

  ```javascript theme={null}
  // Add authentication header
  const token = pm.environment.get('TOKEN');
  pm.request.headers.add('Authorization', `Bearer ${token}`);

  // Check existing header
  const contentType = pm.request.headers.get('Content-Type');
  ```
</ParamField>

<ParamField path="pm.request.body" type="object">
  Request body content.

  **Methods**:

  * `raw()` - Get body as string
  * `json()` - Parse body as JSON (throws if invalid)

  ```javascript theme={null}
  // Modify request body
  const body = pm.request.body.json();
  body.timestamp = new Date().toISOString();
  pm.request.body = JSON.stringify(body);
  ```
</ParamField>

### pm.response

Access response data (only available in post-response scripts).

<ParamField path="pm.response.code" type="number">
  HTTP status code.

  ```javascript theme={null}
  pm.test('Status is 200', () => {
    pm.expect(pm.response.code).to.equal(200);
  });
  ```
</ParamField>

<ParamField path="pm.response.status" type="string">
  HTTP status text (e.g., "OK", "Not Found").

  ```javascript theme={null}
  console.log('Response status:', pm.response.status);
  ```
</ParamField>

<ParamField path="pm.response.headers" type="object">
  Response headers collection.

  **Methods**:

  * `get(name: string): string | undefined` - Get header value
  * `has(name: string): boolean` - Check if header exists

  ```javascript theme={null}
  const contentType = pm.response.headers.get('Content-Type');
  pm.test('Response is JSON', () => {
    pm.expect(contentType).to.include('application/json');
  });
  ```
</ParamField>

<ParamField path="pm.response.body" type="string">
  Raw response body as string.

  ```javascript theme={null}
  console.log('Response length:', pm.response.body.length);
  ```
</ParamField>

<ParamField path="pm.response.json" type="function">
  Parse response body as JSON.

  **Signature**: `pm.response.json(): any`

  ```javascript theme={null}
  const data = pm.response.json();
  pm.test('Has user ID', () => {
    pm.expect(data.user.id).to.be.a('number');
  });
  ```

  <Note>
    Throws an error if the response body is not valid JSON.
  </Note>
</ParamField>

<ParamField path="pm.response.time" type="number">
  Response time in milliseconds.

  ```javascript theme={null}
  pm.test('Response time is acceptable', () => {
    pm.expect(pm.response.time).to.be.below(500);
  });
  ```
</ParamField>

### pm.test()

Define a test assertion (post-response scripts only).

<ParamField path="pm.test" type="function">
  Create a named test with an assertion function.

  **Signature**: `pm.test(name: string, fn: () => void): void`

  ```javascript theme={null}
  pm.test('User has valid email', () => {
    const user = pm.response.json();
    pm.expect(user.email).to.match(/@/);
  });
  ```

  **Test results** are displayed in the "Tests" tab of the response panel.
</ParamField>

### pm.expect()

ChaiJS-style assertions for testing.

<ParamField path="pm.expect" type="function">
  Create an assertion using Chai's expect syntax.

  **Signature**: `pm.expect(actual): Assertion`

  **Common assertions**:

  <Tabs>
    <Tab title="Equality">
      ```javascript theme={null}
      pm.expect(actual).to.equal(expected);
      pm.expect(actual).to.eql(expected); // deep equality
      pm.expect(actual).to.not.equal(value);
      ```
    </Tab>

    <Tab title="Type Checking">
      ```javascript theme={null}
      pm.expect(value).to.be.a('string');
      pm.expect(value).to.be.an('array');
      pm.expect(value).to.be.a('number');
      pm.expect(value).to.be.true;
      pm.expect(value).to.be.null;
      pm.expect(value).to.be.undefined;
      ```
    </Tab>

    <Tab title="Comparison">
      ```javascript theme={null}
      pm.expect(value).to.be.above(10);
      pm.expect(value).to.be.below(100);
      pm.expect(value).to.be.at.least(5);
      pm.expect(value).to.be.at.most(50);
      ```
    </Tab>

    <Tab title="String Matching">
      ```javascript theme={null}
      pm.expect(str).to.include('substring');
      pm.expect(str).to.match(/regex/);
      pm.expect(str).to.have.lengthOf(10);
      ```
    </Tab>

    <Tab title="Array/Object">
      ```javascript theme={null}
      pm.expect(array).to.be.an('array').that.is.not.empty;
      pm.expect(array).to.have.lengthOf(3);
      pm.expect(array).to.include('item');
      pm.expect(obj).to.have.property('key');
      pm.expect(obj).to.have.all.keys('a', 'b', 'c');
      ```
    </Tab>
  </Tabs>
</ParamField>

### pm.sendRequest()

Make HTTP requests from within scripts.

<ParamField path="pm.sendRequest" type="function">
  Send an HTTP request from a script. Accepts a URL string or a request options object.

  **Signatures**:

  * `pm.sendRequest(url: string, callback?: (err, response) => void): void`
  * `pm.sendRequest(request: object, callback?: (err, response) => void): void`

  **Request object properties**:

  * `url` (string, required) — The request URL
  * `method` (string, optional) — HTTP method, defaults to `GET`
  * `header` or `headers` (object, optional) — Request headers
  * `body` (string or `{ raw: string }`, optional) — Request body

  **Callback response object**:

  * `code` (number) — HTTP status code
  * `status` (string) — Status text (e.g. `"200 OK"`)
  * `headers` (object) — Response headers
  * `json()` — Parse response body as JSON
  * `text()` — Get response body as string

  ```javascript theme={null}
  // Simple GET
  pm.sendRequest('https://api.example.com/health', function (err, res) {
      console.log('Status:', res.code);
  });

  // POST with body
  pm.sendRequest({
      url: 'https://api.example.com/auth/token',
      method: 'POST',
      header: { 'Content-Type': 'application/json' },
      body: { raw: JSON.stringify({ grant_type: 'client_credentials' }) }
  }, function (err, res) {
      if (!err) {
          pm.environment.set('token', res.json().access_token);
      }
  });
  ```

  <Note>
    Limited to 5 calls per script execution. Shares the 10-second script timeout. If the callback is omitted, errors are silently ignored.
  </Note>
</ParamField>

### console

Log messages and debugging output.

<ParamField path="console.log" type="function">
  Log informational messages.

  **Signature**: `console.log(...args: any[]): void`

  ```javascript theme={null}
  console.log('Token extracted:', token);
  console.log('User data:', user.name, user.email);
  ```
</ParamField>

<ParamField path="console.error" type="function">
  Log error messages.

  **Signature**: `console.error(...args: any[]): void`

  ```javascript theme={null}
  console.error('Failed to parse response:', error.message);
  ```
</ParamField>

<ParamField path="console.warn" type="function">
  Log warning messages.

  **Signature**: `console.warn(...args: any[]): void`

  ```javascript theme={null}
  console.warn('Deprecated API endpoint used');
  ```
</ParamField>

<Note>
  Console output is displayed in the "Tests" tab with a 200-entry limit. Logs are cleared between requests.
</Note>

## Script Examples

### Pre-Request Script Examples

<Tabs>
  <Tab title="Dynamic Headers">
    Add computed headers before sending the request:

    ```javascript theme={null}
    // Add timestamp header
    pm.request.headers.add('X-Request-Time', new Date().toISOString());

    // Add HMAC signature
    const secret = pm.environment.get('API_SECRET');
    const payload = pm.request.body.raw();
    const signature = computeHMAC(secret, payload);
    pm.request.headers.add('X-Signature', signature);
    ```
  </Tab>

  <Tab title="Token Refresh">
    Check token expiration and refresh if needed:

    ```javascript theme={null}
    const expiresAt = pm.globals.get('TOKEN_EXPIRES_AT');
    const now = Date.now();

    if (!expiresAt || now >= parseInt(expiresAt)) {
      console.log('Token expired, refreshing...');
      pm.sendRequest({
        url: pm.environment.get('TOKEN_URL'),
        method: 'POST',
        header: { 'Content-Type': 'application/json' },
        body: { raw: JSON.stringify({ grant_type: 'client_credentials', client_id: pm.environment.get('CLIENT_ID') }) }
      }, function (err, res) {
        if (!err) {
          const data = res.json();
          pm.environment.set('AUTH_TOKEN', data.access_token);
          pm.globals.set('TOKEN_EXPIRES_AT', (now + data.expires_in * 1000).toString());
          console.log('Token refreshed');
        }
      });
    }
    ```
  </Tab>

  <Tab title="Request Counter">
    Track request count:

    ```javascript theme={null}
    const count = parseInt(pm.globals.get('REQUEST_COUNT') || '0');
    pm.globals.set('REQUEST_COUNT', (count + 1).toString());
    console.log('Request number:', count + 1);
    ```
  </Tab>
</Tabs>

### Post-Response Script Examples

<Tabs>
  <Tab title="Extract Token">
    Extract authentication token from response:

    ```javascript theme={null}
    const response = pm.response.json();

    if (response.access_token) {
      pm.environment.set('AUTH_TOKEN', response.access_token);
      console.log('Token saved to environment');
      
      // Calculate expiration time
      const expiresIn = response.expires_in || 3600;
      const expiresAt = Date.now() + (expiresIn * 1000);
      pm.globals.set('TOKEN_EXPIRES_AT', expiresAt.toString());
    }
    ```
  </Tab>

  <Tab title="Response Validation">
    Validate response structure and data:

    ```javascript theme={null}
    pm.test('Status is 200 OK', () => {
      pm.expect(pm.response.code).to.equal(200);
    });

    pm.test('Response is JSON', () => {
      const contentType = pm.response.headers.get('Content-Type');
      pm.expect(contentType).to.include('application/json');
    });

    pm.test('Response has required fields', () => {
      const data = pm.response.json();
      pm.expect(data).to.have.property('id');
      pm.expect(data).to.have.property('email');
      pm.expect(data.email).to.be.a('string');
    });

    pm.test('Response time is acceptable', () => {
      pm.expect(pm.response.time).to.be.below(1000);
    });
    ```
  </Tab>

  <Tab title="Extract & Chain">
    Extract data for use in subsequent requests:

    ```javascript theme={null}
    const user = pm.response.json();

    // Save user ID for next request
    pm.environment.set('USER_ID', user.id.toString());
    pm.environment.set('USER_EMAIL', user.email);

    console.log('User created:', user.id, user.email);

    pm.test('User ID is valid', () => {
      pm.expect(user.id).to.be.a('number');
      pm.expect(user.id).to.be.above(0);
    });
    ```
  </Tab>

  <Tab title="Error Handling">
    Handle errors gracefully:

    ```javascript theme={null}
    if (pm.response.code >= 400) {
      console.error('Request failed:', pm.response.status);
      
      try {
        const error = pm.response.json();
        console.error('Error details:', error.message);
      } catch (e) {
        console.error('Non-JSON error response');
      }
    } else {
      pm.test('Request successful', () => {
        pm.expect(pm.response.code).to.be.below(400);
      });
    }
    ```
  </Tab>
</Tabs>

## Script Limits

Scripts run in a sandboxed environment with the following limits:

* **Timeout**: 10 seconds maximum execution time
* **Size**: 100KB maximum script size
* **Console output**: 200 entries maximum
* **Test results**: 200 tests maximum
* **`pm.sendRequest()` calls**: 5 per script execution
* **No external modules**: Cannot use `require()` or `import`
* **No file system access**: Cannot read/write files

<Note>
  Scripts that exceed the timeout or size limit will be terminated and an error will be displayed in the Tests tab.
</Note>

## Postman Compatibility

LiteClient's scripting API is compatible with Postman Collection v2.1:

* **Import**: Pre-request and test scripts are preserved when importing Postman collections
* **Export**: Scripts are included when exporting to Postman format
* **Limitations**: Collection-level and folder-level scripts are not supported (request-level only)

<Note>
  When importing a collection with collection-level or folder-level scripts, a warning will be displayed. You'll need to manually copy those scripts to individual requests.
</Note>

## Best Practices

### Script Organization

* Keep scripts focused on a single responsibility
* Use comments to explain complex logic
* Extract common logic to environment variables (as JSON strings)
* Use meaningful test names that describe what's being validated

### Performance

* Avoid expensive operations in pre-request scripts (they delay request sending)
* Cache computed values in variables instead of recalculating
* Use `console.log()` sparingly in production scripts

### Error Handling

* Always wrap JSON parsing in try-catch blocks
* Check for variable existence before using them
* Provide descriptive error messages in console output
* Use tests to validate assumptions about response structure

### Variable Management

* Use globals for values shared across all requests (base URLs, API keys)
* Use environment variables for values specific to an environment (dev/prod tokens)
* Use descriptive variable names (avoid single letters)
* Clean up temporary variables with `unset()` when done
