# AI features and your data Source: https://docs.requestly.com/account/ai-and-your-data What Requestly sends to its AI service when you use the AI Assistant or the Test Authoring Agent, what is masked before it leaves your machine, and what you should keep out of AI features entirely. Requestly's AI features work by sending part of your API data to an AI model so it can answer you. This page describes exactly what is sent, what is removed first, and what you should never put in front of them. ## Which features use AI Two features send data to Requestly's AI service: * **AI Assistant**, the chat panel you open from the footer, from **Debug with AI** or **Visualize with AI** in the response panel, or with `Cmd/Ctrl + Shift + A`. * **Test Authoring Agent**, the **Generate tests** button in the Post-response script editor. See [Generate API test cases using AI](../api-client/ai-test-generator). Both are available in cloud projects only. A local project never reaches the AI service. Everything else in Requestly runs without an AI model. Sending a request, running a collection, importing a file and evaluating your scripts involve no AI service at all. ## What gets sent When you use one of those two features, Requestly sends: * **What you typed**: your chat message or your test-generation instruction. * **The API data the task needs**: the request being discussed (URL, method, headers, query parameters, body, scripts) and, where the feature uses it, the response your last send returned. * **What the assistant looks up.** The assistant can list your project's collections and requests by name, and reads the full contents of the ones it decides it needs. It does this without asking you first. Your whole project is not sent with each message. That payload goes to Requestly's AI service, which calls a third party AI model provider to produce the answer. ## What is masked before it leaves Requestly strips known credentials out of the payload on your machine, before anything is sent: * **Authorization configuration.** Every secret field of a request's or collection's auth setup, across all supported auth types, is replaced with a mask. An auth type Requestly does not recognise is masked in full rather than passed through. * **Secret variables.** Any variable you marked secret is masked, in environments and in collection or project scope alike. * **Credential-shaped headers and body keys.** Headers, form fields and JSON body keys whose names conventionally carry a credential, such as an `Authorization` header or an `api_key` field, are masked by name. ## What is not masked, and what that means for you Masking works on structure, not on meaning. A credential that sits in a place Requestly cannot recognise as a credential is sent as ordinary content. Examples: * A token pasted into the middle of a raw JSON body under a field name that reads like anything else. * Anything in the URL, including an `api_key` query parameter or a password. The URL is sent as you wrote it. * A body that is not JSON or a form, such as XML or plain text. * Your pre-request and post-response scripts, and anything you type into a chat message or test instruction. * Real customer names, emails or account numbers in a sample response you sent and then asked the assistant about. So the rule to work by is: **do not submit live credentials or personal data into test environments.** Use test accounts, test keys and synthetic data in any request you intend to discuss with an AI feature. If a request holds production credentials or real customer data, do not point an AI feature at it. ## Review what comes back The assistant and the agent can be wrong, so check what they produce before you keep it: * The Test Authoring Agent shows generated scripts in a diff you accept, edit or discard. It never writes a script without that step. * The AI Assistant asks you to approve a change before it writes to your project. That is manual mode, which is where every app session starts. The status line under the chat composer tells you which mode you are in. Click it, or press `Shift + Tab` in the chat panel, to switch. In **auto mode** the assistant applies changes and sends requests without asking you first, and each action is recorded in the transcript so you can see what it did. Deleting items from your project asks every time, whichever mode you are in. Auto mode lasts until you switch back or restart the app: starting a new chat does not reset it. Read what was produced before you accept it. An assertion that looks right can still test the wrong thing. ## Turning AI features off If your organization is managed through BrowserStack, an administrator controls AI features for everyone in it by turning **Enable AI features** on or off in the BrowserStack admin dashboard. Requestly's own **Settings** page reports that state but cannot change it, which is why the switch there is greyed out. With AI features turned off, the AI Assistant and the **Generate tests** button do not appear, and no data reaches the AI service from any member's machine. If your account is not linked to BrowserStack, AI features are on and Requestly shows no AI section in Settings: there is no organization policy to report, and no per-user setting to change. ## Related topics * [Generate API test cases using AI](../api-client/ai-test-generator) * [Vault](../api-client/vault/vault), for keeping secrets out of your requests in the first place * [Organization resources](organization-resources) # Billing & Subscriptions Source: https://docs.requestly.com/account/billing-subscriptions Learn how to manage billing teams, assign licenses, update payment info, and view billing history with Requestly's easy-to-use tools. *** Efficient license management is essential for seamless operations. Requestly allows organizations to effortlessly manage their subscriptions and licenses. > [!NOTE] > > Billing, subscriptions, and license management are handled on the **BrowserStack billing dashboard**, not inside the Requestly desktop app. The desktop app's Settings does not include a Billing section. Open the **Billing** area of your [BrowserStack account](https://www.browserstack.com/) to complete the steps below. ### Role Overview | | Billing Manager | Admin | Member | | - | - | - | - | | Subscriptions (Upgrade or Cancel) | Yes | - | - | | Payment Details (Edit card & billing details) | Yes | - | - | | License Management | Yes | Yes | - | | Manage Admins | Yes | Yes | - | | Manage Members | Yes | Yes | - | | Access Premium Features | No | Yes | Yes | To better understand how Billing Teams works, watch the following video: [https://www.youtube.com/embed/5uiXm-Hs600](https://www.youtube.com/embed/5uiXm-Hs600) *** ## Creating a Billing Team Setting up a billing team is the first step in managing your organization's licenses. Follow these steps to create one: **1. Open the Billing dashboard** Sign in to your [BrowserStack account](https://www.browserstack.com/) and open the **Billing** dashboard. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/ad28f8a0-8741-4888-941a-bcb733f654f7.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=1cdc5c1db57c035b5b20ddf0a8d770c1) **2. Click Upgrade** After you open Billing, click the **Upgrade** button to select your plan and begin the process of allocating seats. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/d5f98a0f-7b95-4596-b5aa-89800759e078.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=8ed088b6be4aaf5e58db05e7c5acdd61) **3. Select Seats** Choose the number of seats you want to allocate for your team. This will determine how many licenses are available for assignment. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/3d20f3c3-5f65-4709-9d33-d651c7838783.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=2fc017efd022752d0d14a0e7e082e227) **4. Proceed to Checkout** After selecting the number of seats, click the **Upgrade** button to go to the checkout page. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/13cdca45-8902-4c93-9e2b-0333fdcfa001.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=3ea1e657ae27599279661243911e1b33) **5. Complete Checkout** Review your order summary on the checkout page. Enter the required payment details and complete the purchase. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/a542989f-c987-404b-962d-7007ab034b27.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=b6d3eee7c20d2ea904fb70a40d3280e4) **6. Automatic Team Creation** After the checkout is complete, a Billing Team will be created automatically. You’ll be redirected to the **Billing Dashboard**, where you can manage your plan. **7. Review Plan Details** In the **Billing Dashboard**, you can view the details of your current plan, including the number of licenses purchased and their status. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/7f8e13c3-e4be-4e28-9c36-a62780718bdd.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=b781af3ca2e15bd74d382b7b395439e5) *** ## Managing Licenses The **Billing Dashboard** provides a simple way to manage license holders, ensuring your team has seamless access to premium features. ### Assigning a License Easily allocate licenses to team members who need premium access to tools and features. **1. Open Billing Dashboard** Open the **Billing** dashboard in your [BrowserStack account](https://www.browserstack.com/). **2. Click Assign License** Click the **Assign License** button to begin the allocation process. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/2e6edf62-1d63-46b1-ab93-43f547cc6398.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=afab3ad865755ac431c08330f5a49e6a) **3. Select User and Assign** Select a user from the list of available members and click **Assign**. > [!TIP] > > If the user is not listed, use the **Invite & Assign License** option. Enter the user’s email to send an invitation. Once the user signs up, they will be automatically assigned a license. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/fbc7123f-4854-4ae0-b357-2084b524d26d.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=7be32ddd381797c0a5d0bd6ff9b6e7be) ### Revoking a License Revoking a license ensures that premium access is no longer available to users who no longer need it, helping maintain efficient license usage. **1. Go to Billing Dashboard** Open the **Billing** dashboard in your [BrowserStack account](https://www.browserstack.com/). **2. Locate User** Find the user whose license you wish to **revoke**. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/e434cc06-cb9d-4a54-8e42-b085ba6cd2c4.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=83f876702b6f4bb09bf5566051b6af3c) **3. Revoke License** Click the ellipsis(**three-dot**) menu next to their name and select **Revoke License**. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/ab12ef92-6845-4d18-b116-275871e12cd9.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=9c243b31fde3fa924f0aa44fd70f170d) *** ## Updating Billing Information Keep your billing details up to date to avoid service disruptions. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/920629a2-8c58-4c1c-9bbe-0ecc8dbc0114.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=7e10628b520939fc1aaa5a7d0593ac66) ### Modify Billing Information Navigate to the **Billing Information** section. Update your billing addresses and contact details as needed. ### Change Payment Method Go to the **Payment Methods** section. Add a new payment option or edit existing ones to ensure uninterrupted service. *** ## Billing History and Invoices Stay on top of your financial records with easy access to billing history and invoices. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/billing-subscriptions/e65e3883-42b2-4be9-bbdf-6f740dda185c.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=421e04b0563073b41d5972c7a0f09a71) ### View Billing History Navigate to the **Billing History** section to review records of past billing activities. ### Download Invoices Go to the **Invoices** section and click **Download** next to the invoice you wish to save. ### Handle Unpaid Invoices Locate any outstanding payments in the **Billing Dashboard** and follow the prompts to complete the payment process. *** ### Billing Teams vs. Team Projects * **Billing Teams**: Responsible for managing licenses and billing processes on the BrowserStack dashboard. * **Team Projects**: Enable collaboration by letting teams share and manage API collections, environments, and variables inside the Requestly app. # Data Recovery Policy Source: https://docs.requestly.com/account/data-recovery How Requestly retains and recovers deleted projects, collections, requests, and environments. *** When you delete a project, collection, request, environment, or any other resource in a **team or personal cloud project**, the data is retained for **7 days** before being permanently removed. ## Recovering deleted data If you need to restore something that was deleted, contact our support team within the 7-day window and we will restore it for you. **1. Contact support** Email [support@requestly.io](mailto:support@requestly.io) from the email address associated with your Requestly account. **2. Share the details we need** Include the following so our team can locate the right data quickly: * **Project name** (and project ID, if you have it) * **Resource type:** project, collection, request, environment, etc. * **Resource name** of the item(s) you would like restored * **Approximate time of deletion** (date and time, with timezone) **3. We restore the data** Our team will recover the data and confirm once it is available in your project. Restored items reappear in the same location they were deleted from. > [!WARNING] > > After **7 days**, deleted data cannot be recovered. We recommend reaching out as soon as you notice an accidental deletion. ## Local projects Data in [local projects](../collaboration/local-workspace) lives entirely on your device and is **not backed up by Requestly**. If you delete a local project, or the files and folders backing it, the data cannot be recovered by our team. > [!NOTE] > > For local projects, we recommend keeping the project folder under your own backup (Time Machine, OneDrive, Git, etc.) so you can restore from there if needed. ## What's covered | Resource type | Recoverable within 7 days? | | - | - | | Projects (cloud) | Yes | | Collections | Yes | | Requests / Endpoints | Yes | | Environments & variables | Yes | | Local project data | No (stored on your device) | # Data residency Source: https://docs.requestly.com/account/data-residency Why the Requestly desktop and web apps show a data-residency compliance screen for some BrowserStack organizations, and where Requestly runs. Requestly's cloud services run in the **United States**. Requestly has no regional deployment, and there is no setting that changes where your cloud data is stored. Because of that, BrowserStack can mark Requestly as restricted for an organization that is subject to data residency, also called **Geo-Region Restriction (GRR)**. When it does, Requestly shows a compliance screen instead of the app. ## What you see Signing in to the Requestly desktop app or web app with a restricted account replaces the app with a compliance notice: > **This product is not compliant with Data Residency (GRR) regulations** > > Your Organization has enabled Data Residency, which mandates you to use compliant products. Contact your Customer Success Manager to discuss continued usage of this product. The only action on that screen is **Sign out**. The app itself does not load behind it, so no requests, collections, environments or projects are reachable while you are signed in with that account. You are not doing anything wrong, and there is no setting inside Requestly that clears this. The restriction comes from your BrowserStack organization, not from your Requestly account. ## Who is affected The restriction is set per BrowserStack group, and it is resolved **per product**. Requestly is restricted for a group when both of these are true: * BrowserStack has set a data-residency region on the group, and * Requestly is not exempted from that group's data-residency setting. > [!NOTE] > > Having data residency enabled does not by itself block Requestly. BrowserStack can exempt individual products from a group's data-residency setting, and an exempted product is not blocked. Whether Requestly is exempted for your organization is a question for your Customer Success Manager. Where it does apply, it applies to everyone in that group. Data residency is treated restrictively: if you belong to more than one group and any one of them is restricted for Requestly, you see the compliance screen. Accounts that belong to no restricted group are unaffected and never see any of this. ## What to do **1. Contact your Customer Success Manager** The compliance screen names this for a reason: data residency is a BrowserStack organization setting, and your Customer Success Manager is the person who can tell you whether Requestly can be used under your organization's terms. **2. Or sign in with an unrestricted account** Click **Sign out** on the compliance screen and sign in with an account that does not belong to a restricted group. ## If the restriction is lifted Requestly reads your organization's data-residency setting from BrowserStack each time your organization's details are synced, which includes every sign-in. Once BrowserStack clears the restriction or exempts Requestly, the compliance screen stops appearing. If it still appears after you have been told the restriction was lifted, sign out and sign back in. ## Related documentation * [Billing and subscriptions](/account/billing-subscriptions) * [Organization resources](/account/organization-resources) # Deploy on Windows Source: https://docs.requestly.com/account/enterprise-deployment/deploy-windows-msix Deploy the Requestly API Client to Windows devices as an MSIX package, and control its automatic updates with a policy. As an IT administrator, you can deploy the Requestly API Client to Windows devices as an MSIX package, and control its automatic updates with a policy. > [!NOTE] > > This guide covers Windows only. An enterprise build for macOS and Linux is coming soon. ## What to expect * The app installs per user or for all users on a device, and updates itself through Windows. * You can turn **automatic updates off with a registry value, Group Policy or Intune**. * Users who move from the `.exe` installer keep their data and stay signed in. ## Before you start ### System requirements * Windows 10 version 21H2 (build 19044) or later, or Windows 11. See [MSIX supported platforms](https://learn.microsoft.com/en-us/windows/msix/supported-platforms). * x64. ### Device settings Check these settings on each device before you deploy. | Setting | Required state | Needed for | | - | - | - | | [Allow all trusted apps to install](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-applicationmanagement#allowalltrustedapps) (`HKLM\SOFTWARE\Policies\Microsoft\Windows\Appx\AllowAllTrustedApps`) | Not `0` (not Disabled) | Install | | [Delivery Optimization](https://learn.microsoft.com/en-us/windows/deployment/do/waas-delivery-optimization) service (DoSvc) | Present on the device (any startup type or download mode) | Updates | | `assets.requestly.com` | Reachable for users and SYSTEM, with HTTP Range requests | Updates | | [AppLocker](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/packaged-apps-and-packaged-app-installer-rules-in-applocker) or [App Control](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/select-types-of-rules-to-create#app-control-for-business-file-rule-levels) | Allow publisher BrowserStack, Inc. with no upper version | Install, start, updates | | [Run only specified Windows applications](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-admx-shellcommandpromptregedittools#restrictapps) | `Requestly API Client.exe` on the list | Start | | Microsoft Store Install Service (InstallService) | Not Disabled (Manual is the default) | Double-click install with [App Installer](https://learn.microsoft.com/en-us/windows/msix/app-installer/app-installer-root) | | [Archive infrequently used apps](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-applicationmanagement#allowautomaticapparchiving) (`HKLM\SOFTWARE\Policies\Microsoft\Windows\Appx\AllowAutomaticAppArchiving`) | `0` (Disabled), recommended on Windows 11 | Keeping the app installed | > [!NOTE] > > The app is not in the Microsoft Store. If Windows archives it, Windows cannot restore it. Set **Archive infrequently used apps** to Disabled to keep the app installed. ## Deploy the app Choose one method. In each command, replace ``, `` and `` with your own values. The commands use `requestly-api-client-2610.15.1-win-x64.msix` as an example. Replace it with the file name of the version you downloaded. **PowerShell (one user)** Run [Add-AppxPackage](https://learn.microsoft.com/en-us/powershell/module/appx/add-appxpackage) as the user. You do not need admin rights. ```powershell theme={null} Add-AppxPackage -Path "\requestly-api-client-2610.15.1-win-x64.msix" ``` **Double-click (one user)** The user opens the `.msix` file, and [App Installer](https://learn.microsoft.com/en-us/windows/msix/app-installer/app-installer-root) installs it. The Microsoft Store Install Service must not be Disabled. If it is, run this as admin: ```powershell theme={null} Set-Service InstallService -StartupType Manual ``` **DISM (all users)** This provisions the app for current and future users on the device, with [Add-AppxProvisionedPackage](https://learn.microsoft.com/en-us/powershell/module/dism/add-appxprovisionedpackage) or [DISM](https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/dism-app-package--appx-or-appxbundle--servicing-command-line-options). Run it as admin, or from a [Group Policy startup script](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn789196\(v=ws.11\)). In PowerShell: ```powershell theme={null} Add-AppxProvisionedPackage -Online -PackagePath "\requestly-api-client-2610.15.1-win-x64.msix" -SkipLicense ``` Without PowerShell, for example in a `.cmd` startup script: ```cmd theme={null} DISM /Online /Add-ProvisionedAppxPackage /PackagePath:"\requestly-api-client-2610.15.1-win-x64.msix" /SkipLicense ``` **Group Policy logon task** **1. Create the task** Go to **User Configuration → Preferences → Control Panel Settings → Scheduled Tasks**. **2. Set the trigger and context** Set the trigger to **At log on**, and select **Run in logged-on user's security context**. **3. Set the action** The action runs a script from a share. The script installs the app only when it is not there yet. ```cmd theme={null} powershell.exe -ExecutionPolicy Bypass -NoProfile -File "\\\\install.ps1" ``` Save this as `install.ps1` on the share: ```powershell theme={null} if (-not (Get-AppxPackage com.requestly.api-client)) { Add-AppxPackage -Path "\\\\requestly-api-client-2610.15.1-win-x64.msix" } ``` **Microsoft Intune** **1. Add the app** Go to **Apps → Windows → Add → [Windows MSIX line-of-business app](https://learn.microsoft.com/en-us/intune/app-management/deployment/add-lob-windows)**, and upload the `.msix` file. **2. Assign it** Assign the app as **Required** to a device group, with **Install context** set to **Device**. **3. Verify the install** After the next device sync, run this as admin on a device: ```powershell theme={null} Get-AppxPackage -AllUsers com.requestly.api-client | Select-Object Name, Version ``` ## Install location and user data The app installs to this folder, for version `X.Y.Z.0` on an x64 device: ```text theme={null} C:\Program Files\WindowsApps\com.requestly.api-client_X.Y.Z.0_x64__kmhnz6pyr4q72 ``` User data and logs stay in the same folder as with the `.exe` installer, so users keep their data when they move to the MSIX: ```text theme={null} %APPDATA%\Requestly API Client ``` The app log is `%APPDATA%\Requestly API Client\logs\main.log`. ## Configure automatic updates Set the policy in Computer Configuration (HKLM), before the app first starts. **Registry** The policy lives in this key: ```text theme={null} HKEY_LOCAL_MACHINE\SOFTWARE\Policies\BrowserStack\Requestly API Client ``` Set the value with [reg add](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/reg-add) or your management tool. This command turns automatic updates off: ```cmd theme={null} reg add "HKLM\SOFTWARE\Policies\BrowserStack\Requestly API Client" /v AutoUpdate /t REG_DWORD /d 0 /f ``` **Group Policy** **1. Get the template** Download the [ADMX template](https://assets.requestly.com/assets/desktop/policy-templates/requestly-api-client-policy-templates.zip). **2. Add it to your policy store** Add `RequestlyAPIClient.admx` and `en-US\RequestlyAPIClient.adml` to your [policy store](https://learn.microsoft.com/en-us/troubleshoot/windows-client/group-policy/create-and-manage-central-store). **3. Set the policy** Go to **Computer Configuration → Administrative Templates → BrowserStack → Requestly API Client → Automatic updates**. **Intune** **1. Import the template** Go to **Devices → Configuration → [Import ADMX](https://learn.microsoft.com/en-us/intune/device-configuration/settings-catalog/import-custom-admx-templates)**, and import the same two files from the [ADMX template](https://assets.requestly.com/assets/desktop/policy-templates/requestly-api-client-policy-templates.zip). **2. Create a profile** Create an **Imported ADMX** profile with the Computer Configuration setting. **3. Assign it** Assign the profile to a device group. ### Supported settings | Setting | Value | | - | - | | **AutoUpdate** Enables or disables automatic updates of the desktop app. | `REG_DWORD` `1`\* (enabled) `0` (disabled) | \* Default. When the value is not set, or has any other type or value, updates stay on. ## Good to know * An app installed for all users (DISM, or Intune with Device context) reads only HKLM. A User Configuration policy has no effect on it. * After a self-update, Intune can show the app as "Failed" (`0x87D1041C`), because Intune looks for the exact version it deployed. The app is not affected. * To move from the `.exe` installer: remove its assignment, uninstall it for each user, then install the MSIX. ## FAQ > **Can automatic updates be turned off?** > > Yes. Set `AutoUpdate` to `0` with a registry value, Group Policy or Intune. See [Configure automatic updates](#configure-automatic-updates). When updates are off, the app shows no update prompt, and **Check for Updates** is disabled. > **Does an update close the app while a user works?** > > No. When you deploy a new version while the app is open, the app keeps running. The user gets the new version the next time they start the app. > **Can a later deployment downgrade an app that updated itself?** > > No. If the app has already updated itself to a newer version, a later DISM or Intune deployment of an older version does not downgrade it. > **We use AppLocker or App Control. Why does the app not install or start?** > > These policies block packaged apps that they do not allow. Allow the publisher **BrowserStack, Inc.** with no upper version limit, so that the rule also covers future updates. Do not allow the app by its file path, because the path changes with each version. > **How do I check which version is installed?** > > Run this in PowerShell: > > ```powershell theme={null} > Get-AppxPackage com.requestly.api-client | Select-Object Name, Version > ``` > > Add `-AllUsers` and run it as admin to see every user on the device. # How is the Browser Extension Different from the Desktop App Source: https://docs.requestly.com/account/how-is-browser-extension-different-from-a-desktop-app Requestly is available as both a **browser extension** and a **desktop application**. While both platforms offer a similar set of features, their capabilities differ slightly to address platform-specific limitations and better cater to distinct use cases. > [!NOTE] > > This comparison covers Requestly's interception and rules capabilities. For the API client, the **desktop app** is the primary and recommended experience. The **browser extension** is comparatively a **lighter tool** that runs directly within the browsers and is ideal for **browser-focused workflows**. The **desktop app** is designed to provide more control over network traffic across the **entire system**, including apps outside the browser. This comparison outlines functional differences to help you choose the right setup for your use case. ## Platform & Browser Support **Browser Extension -** Supports all major web browsers, including all Chromium-based browsers, Firefox, and Safari (limited support) **Desktop App -** Supports all browsers and any app making network requests. like desktop apps, backend services, mobile devices, etc. > 📎 The extension runs inside the browser environment. The desktop app operates system-wide and works with any browser, application or even hardware devices like smartphones etc. ## HTTP Interception > 🔧 Use the desktop app if you need to work with network traffic beyond the browser, such as from curl, Postman, mobile devices, or backend services. | **Feature** | **Browser Extension** | **Desktop App** | | - | - | - | | Browser Interception | ✅ | ✅ | | System-wide Proxy | ❌ | ✅ | | Mobile App Interception | ❌ | ✅ | | Locally Installed App Interception | ❌ | ✅ | ## HTTP Rules | **Feature** | **Browser Extention** | **Desktop App** | | - | - | - | | HTTP Rules | ✅ \[Limitations below]👇 | ✅ | | Delay Rule max delay | 5000ms (Fetch/ XHR requests) 10000ms (Other resources) | Unlimited | | Redirect to local file | ❌ | ✅ | | Serve local file Response | ❌ | ✅ | | Modify HTML/JS/CSS Response | ❌ | ✅ | | Map Local | ❌ | ✅ | | Map Remote | ✅ | ✅ | > 💡 The extension works within the limitations of browser APIs. Features like serving local files or modifying HTML/CSS content are only supported in the desktop app due to broader system access. ## Mocking & Debugging | **Feature** | **Browser Extension** | **Desktop App** | | - | - | - | | File Server | ✅ | ✅ | | Bulk Mocking | ❌ | ✅ | | Session Book | ✅ | ❌ | | Network Sessions | ❌ | ✅ | > 📌 Tip: Use Desktop App when mocking multiple endpoints or importing HAR files. ## Workspaces & Import/Export | **Feature** | **Browser Extension** | **Desktop App** | | - | - | - | | Local Workspace (Beta) | 🚧 (Coming Soon) | ✅ | | Import / Export HAR file | 🚧 (Coming Soon) | ✅ | ## Visibility of Executed Rules The way Requestly shows rule executions varies between the browser extension and desktop app, tailored to their respective environments: **Browser Extension** 1\. A **pop-up notification** shows which rule was triggered when browsing. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-is-bowser-extension-different-from-a-desktop-app/c16facc7-0a43-449a-a2bc-2b175a443f8c.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=a8574d4290c10b7f850ac7e6b0e51b54) 2\. Requestly Extension’s **icon turns green** in the extension toolbar. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-is-bowser-extension-different-from-a-desktop-app/48bfa7f8-5eb1-44f7-bff2-6b7ad79ec86d.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=1364dab68812a45a0c6b84ac3d3d3abc) 3\. The **extension popup panel** also lists recently executed rules, making it easy to confirm if a rule applied. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-is-bowser-extension-different-from-a-desktop-app/b13f05bd-d271-45d5-872a-e4ea2381336b.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=28ec51b2d697c8ccc98c3bfcae9508a9) **Desktop App** The **rules table** visually highlights which rules were applied by turning the corresponding request rows **green**. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-is-bowser-extension-different-from-a-desktop-app/ce0d85d4-1396-4a96-96cc-8f3945dc4ae1.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=f16096e016bfcabefd66bdbc8495cb36) # Organization resources Source: https://docs.requestly.com/account/organization-resources Control what your organization's members can do in Requestly: which external packages scripts may import, and whether members can leave Safe mode. An organization Owner or Admin can decide what everyone in the organization is allowed to do in Requestly. Those controls live under **Settings > Organization > Resources**, and each individual control is called a resource. Two resources are governed today, both in the **Scripts & packages** section: | Resource | What it controls | Where it takes effect | | - | - | - | | **External packages** | Which external packages scripts in this organization may import. | The Requestly desktop app | | **Script mode** | Whether members of this organization can run a request's scripts in Developer mode. | The Requestly desktop app and the Requestly CLI | > [!NOTE] > > Resources is enabled per organization. If you are an Owner or Admin and the entry is missing under Settings > Organization, contact Requestly support. ## Who can change a policy Only an organization Owner or Admin can change a policy. Everyone else in the organization sees exactly the same pages, read only: the list carries a quiet **Read only - you can view these settings.** line, and the resource's own page states **You can view this policy but not change it**, along with who to ask. There is no error page and no redirect, so a member can always see what applies to them and who set it. Every row and every resource page also names who changed the policy last and when. Only the latest change is recorded, so there is no history to browse. ## Change a policy **1. Open Resources** Go to **Settings**, open the **Organization** group and select **Resources**. Each row names the resource, describes what it controls, and shows the choice that currently applies. **2. Open the resource** Click anywhere on the row. The resource gets its own page, where each option is listed with the consequence of choosing it. **3. Choose an option** Options are listed least restrictive first. Selecting one shows what it means for your members before you commit to it. **4. Curate the list, if the option carries one** Some options reveal a list panel. Add and remove entries there. Nothing is written until you save. **5. Save** Click **Save** in the page header. **Save** stays unavailable until you change something, and **Cancel** discards the draft. A successful save returns you to the Resources list. ## External packages This resource controls which external packages scripts in this organization may import with `require()`. See [Import packages into your scripts](/api-client/import-packages-into-your-scripts) for what `require()` can load. | Option | What it means | | - | - | | **Allow all** | Scripts can import any external package. This is the default. | | **Allow selected** | Only the packages listed below can be imported. | | **Deny** | Scripts cannot import any external package. | > [!NOTE] > > Requestly's built-in library is always available and is exempt from this policy. Packages bundled with Requestly resolve whatever you choose here, including under **Deny**. This setting controls external packages only. That exemption covers everything Requestly ships in the sandbox, reached either by name through `require()` (for example `require('crypto-js')`) or through the convenience globals `_`, `CryptoJS` and `xml2Json`. ### Curate the approved list Choosing **Allow selected** reveals an **Approved packages** panel. Two entry forms are accepted: * `axios` permits any version of that package. * `axios@1.7.2` permits only that release. Add an entry with **Add** or by pressing Enter. To add several at once, paste them into the field separated by newlines, commas, semicolons or spaces. Duplicates are rejected with a message rather than silently dropped, so if you meant to change a package's version, remove the existing entry first. Requestly does not verify that an approved package exists. A well-formed name that no registry resolves is still accepted, which is what lets you approve a private or not-yet-published package. > [!WARNING] > > Pinning a version permits only that release and blocks an unversioned `require()` of the same package. Most scripts do not specify a version, so most scripts break when you pin one. Saving **Allow selected** with an empty list is blocked, because an empty approved list denies every external package, which is what **Deny** already means. The **Save** button explains itself with "Add at least one entry, or choose Deny.", and the panel offers **Choose Deny instead** as the way out. ### What a governed member sees Under **Allow selected** or **Deny**, a script that imports a package the policy does not permit is blocked when the request runs, with a message naming the package: `Package 'some-package' is blocked by your organization's package policy. Ask an admin in your organization to approve it.` Installing such a package from the Package Library is refused for the same reason. ## Script mode This resource controls whether members of this organization can run a request's scripts in Developer mode. Safe mode is what every request opens in either way. See [Script execution modes](/api-client/rq-api-reference/overview#script-execution-modes) for what the two modes do. | Option | What it means | | - | - | | **Allow Developer mode** | Requests open in Safe mode, and a member can switch one into Developer mode. This is the default. | | **Safe mode only** | Every request runs in Safe mode. No member can switch one into Developer mode. | Developer mode reaches the host machine: scripts running in it can read files, run shell commands and open raw sockets on the member's machine. Safe mode is still what every request opens in, so this setting decides whether a member may leave it. Under **Safe mode only**, members see Developer mode marked unavailable rather than hidden. The per-request mode control keeps showing the mode, so a member who reaches for it learns their organization set this instead of discovering it from a script that failed. ### Developer mode in the CLI `rq collection run --script-execution-mode developer` requires credentials and is refused when the policy is **Safe mode only**. A run that passes no mode flag, or passes `safe`, needs no credentials and is unaffected. See [Script execution mode and your organization's policy](/api-client/cli#script-execution-mode-and-your-organizations-policy). ## How enforcement works Policies apply to everyone in the group, including the admins who set them. Enforcement is performed by the Requestly app on each member's machine, in every project, including local ones. It is not enforced at the network level or on our servers. The Resources page states this once, behind the **How enforcement works** link next to the enforcement line, together with the surfaces each resource is enforced on. A change can take up to a minute to reach a member's machine, and a run already in progress finishes on the policy it started with. > [!WARNING] > > An out-of-date desktop app does not apply these policies. Policies you set are saved and apply on every up-to-date app, and the Resources page replaces its enforcement line with an update prompt when the app you are reading it in is too old to apply them. Where a policy denies something, Requestly explains itself rather than failing silently: the restricted surface names what was restricted and says it "has been restricted by your organization's admin." It does not offer a workaround, so it will not suggest installing the desktop app to reach something your admin denied. ## Defaults A resource with no policy set is **Allow all**. There is no separate "not set" state, so a resource you have never touched behaves exactly as it did before Resources existed, and a newly added resource appears set to **Allow all**. If loading the policies fails, the page says so rather than showing every resource at its default. Any policies your organization has set stay in force while the page cannot display them. ## Related documentation * [Import packages into your scripts](/api-client/import-packages-into-your-scripts) * [Script execution modes](/api-client/rq-api-reference/overview#script-execution-modes) * [Run collections from the command line](/api-client/cli) * [User roles in a shared project](/collaboration/how-to-get-started-with-shared-workspace/user-roles) # Set up Microsoft Entra ID Source: https://docs.requestly.com/account/sso/how-to-set-up-sso-with-microsoft-entra-id Set up SSO with Microsoft Entra ID If your company uses [Microsoft Entra ID](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id), you can set up the single sign-on feature for use with Requestly. This gives your employees the convenience of a one-click login, without using additional multi-factor authentication. > [!NOTE] > > SSO is an enterprise-plan feature. Contact the Requestly team to enable it for your organization. ## Step 1. **Create an Microsoft Entra ID enterprise application** 1. Go to the [**Microsoft Entra ID**](https://entra.microsoft.com/) portal. 2. Go to **Identity > Applications > Enterprise applications.** 3. Click on **+** **New application.** ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-set-up-sso-with-microsoft-entra-id/4ca2707a-b5d7-432c-b658-be6ec164d66d.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=ad9046a4522d0a0e0611d955d076b6bf) 4. Enter app name as desired, select **Integrate any other application you don’t find in the gallery (Non-gallery)**, and click **Create** ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-set-up-sso-with-microsoft-entra-id/353eb1f4-5052-4ccb-a653-36744c7e44e9.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=2a38fccbe0a294bbdd180d5504bf1a91) 5. After this you're redirected to the newly created Requestly application **Overview**. ## Step 2. Configure Microsoft Entra ID SAML Application 1. On the app's **Overview** page, select **2. Set up single sign-on**. You can assign users and groups later. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-set-up-sso-with-microsoft-entra-id/68c57f5a-2641-4e40-8459-fd10163a37ee.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=feec55f396709ffaf3f0ca378cb9cb61) 2. On the app's **Single sign-on** page, select **SAML** as the single sign-on method. 3. Under the **Basic SAML Configuration** section, click **Edit.** 4. Add the following values and **save**: * **Identifier (Entity ID):** `urn:requestly.io` * **Reply URL:** `https://app.requestly.io/__/auth/handler` * **Sign on URL (optional):** Leave it empty. We don’t support IDP initiated SSO right now ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-set-up-sso-with-microsoft-entra-id/290821e7-a92c-4cc6-b502-e1e19194c9af.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=fbf10b11438df5da624a288db8ad62d5) ## Step 3. Setup SAML claims 1. Under the **Attributes and Claims** section, click **Edit**.  2. Enter the following values: | Unique User Identifier (Name ID) | user.mail | | - | - | | first\_name | user.givenname | | last\_name | user.surname | | email | user.mail | ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-set-up-sso-with-microsoft-entra-id/1338f76e-6299-4eb6-b3a9-b35f6f1146b3.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=e758fd150ea16ec64196e0bbce67db8f) ## Step 4. Share SAML metadata with Requestly 1. Under **SAML Certificates** section, copy the **App Federation Metadata URL**. 2. Share the copied value with us `contact@requestly.io` # SAML SSO with Okta Source: https://docs.requestly.com/account/sso/setup-sso-with-okta If your company uses Okta as an Identity Provider, then you can set up the single sign-on feature for use with Requestly. This gives your employees the convenience of a one-click login, without using additional multi-factor authentication. > [!NOTE] > > SSO is an enterprise-plan feature. Contact the Requestly team to enable it for your organization. ## **Step 1. Create and configure a SAML application in Okta** 1. Log in to your Okta account and head to the **Applications** page. 2. Click on `Create App Integration` and select `SAML 2.0` ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/setup-sso-with-okta/a70c4b4f-a380-424e-b1c6-de6ef0559d4b.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=5d81ad824f9826ba77f68364e55c0c50) In the `1. General Settings` step, add App Name as `Requestly` and then click `Next` ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/setup-sso-with-okta/fb983e56-46c8-4a1d-96db-7e22f361727c.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=7fee43305597557cd3b3dfccc7407ebe) 4. In the `2. Configure SAML` step, add the following details and then click `Next` | Single sign-on URL | `https://app.requestly.io/__/auth/handler` | | - | - | | Audience URI (SP Entity ID) | `urn:requestly.io` | | Name ID format | Email Addresss | | Application username | Email | ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/setup-sso-with-okta/0821978f-4009-4189-b3a8-7a76e5f2e8ef.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=33e98b72e5f85148d765a78479bda733) ## **Step 2. Share SAML metadata with Requestly** ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/setup-sso-with-okta/fb4784b9-6f59-4525-87bb-bbdfc1d457a1.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=be04a8abaadf13d831f41b4a2b05cc43) Copy the **Metadata URL**. 2. Share the copied value with us [`contact@requestly.io`](mailto:contact@requestly.io) # Generate API Test Cases using the Test Authoring Agent Source: https://docs.requestly.com/api-client/ai-test-generator Learn how to automatically author Post-response API test scripts using the Test Authoring Agent in Requestly. Use natural language instructions to create reliable, comprehensive API tests without manually writing JavaScript. The Test Authoring Agent is a Requestly-integrated AI agent that authors executable Post-response test scripts directly from real API request and response data. It removes repetitive, error-prone manual work and helps engineers and QA teams validate API behavior faster with consistent coverage. Simply describe what you want to validate in plain English. The agent analyzes your latest API response and produces ready-to-run test cases for your current request. > [!NOTE] > > **Availability:** The Test Authoring Agent requires a **Pro plan or above** and AI features enabled for your organization. It is rolling out gradually; if you don't see it, update to the latest version. [https://www.youtube.com/embed/iv4MvArAdYU?si=WsJdhBkKWmTua7RG](https://www.youtube.com/embed/iv4MvArAdYU?si=WsJdhBkKWmTua7RG) ## Getting Started with AI Test Cases Generator **1. Send Your API Request** The Test Authoring Agent requires an actual API response to understand structure, values, and risk areas. ![Test Authoring Agent Send Request Firsttogeneratetestsfromitsresponse 1](https://mintcdn.com/requestly/O0nig7kakQWmexIp/images/TestAuthoringAgent-SendRequestFirsttogeneratetestsfromitsresponse-1.png?fit=max\&auto=format\&n=O0nig7kakQWmexIp\&q=85\&s=8a7a8a340e0c2caa9426ca1f87525c91) 1. Open any request in the API Client 2. Click the **Send** button to execute the request 3. Wait for the response to be received **2. Once you have a response** Once the response is available: 1. Navigate to the **Scripts** section 2. Open the **Post-response** tab 3. Click **Generate tests** (the button reads **Improve tests** if the request already has a post-response script) This opens the test generation panel. ![Test Authoring Agent AI Test Generatordialog](https://mintcdn.com/requestly/O0nig7kakQWmexIp/images/TestAuthoringAgent-AITestGeneratordialog.png?fit=max\&auto=format\&n=O0nig7kakQWmexIp\&q=85\&s=a57dc4636e5826a5b72b9dc2aa500498) **3. Enter Natural Language Instructions** Describe what the tests should validate using plain English. The agent understands API context, response payloads, and common testing patterns. ![Test Authoring Agent Generatetestcases](https://mintcdn.com/requestly/O0nig7kakQWmexIp/images/TestAuthoringAgent-Generatetestcases.png?fit=max\&auto=format\&n=O0nig7kakQWmexIp\&q=85\&s=043f307b4620d8f27e8721748b9f4493) **Example instructions** * "Generate test cases" * "Test that status is 200 and success is true" * "Ensure the response has id, name, and email fields" * "Validate pagination fields like page, limit, and total" * "Check that items array is not empty" * "Verify all timestamps are valid ISO 8601 dates" * "Add schema validation for the response" * "Test missing required fields" Click **Generate** to continue. **4. Review the Output** The Test Authoring Agent presents the generated output in a git-style diff view: * Green lines show new tests that will be added * Red lines show tests that will be removed * Unchanged lines remain neutral This human-in-the-loop review ensures full control before any script changes are applied. ![Test Authoring Agent Reviewthe Output(2)](https://mintcdn.com/requestly/O0nig7kakQWmexIp/images/TestAuthoringAgent-ReviewtheOutput\(2\).png?fit=max\&auto=format\&n=O0nig7kakQWmexIp\&q=85\&s=9f7f4d8286e551cbf39b14e6ab1c9a7b) **5. Accept, Edit, or Discard** After reviewing the diff, you can: * **Accept** to replace the full Post-response script with the generated tests * **Edit prompt** to refine your prompt and regenerate tests * **Close** to discard all changes and keep the existing script Accepted tests are saved immediately and are ready to run. ## What the Test Authoring Agent Creates The agent authors structured, runnable API test cases using: * rq.test blocks for clear test intent * Chai-based assertions via rq.response and rq.expect * Field-level, schema-level, and behavior-based validations All generated tests are compatible with the Collection Runner and CI workflows. ## What the Test Authoring Agent Creates The agent creates comprehensive test scripts using Requestly's [`rq.test`](/api-client/rq-api-reference/rq-test) and [`rq.expect`](/api-client/rq-api-reference/rq-expect) APIs with [Chai.js assertions](/api-client/tests#example-tests). ### Example Generated Tests For a user API endpoint returning: ```json theme={null} { "status": 200, "success": true, "data": { "id": 123, "name": "John Doe", "email": "john@example.com", "role": "admin" } } ``` With instruction: **"Test that status is 200, success is true, and user object has required fields"** The AI generates: ```javascript theme={null} rq.test("Status code is 200", () => { rq.response.to.have.status(200); }); rq.test("Response is valid JSON", () => { rq.response.to.have.jsonBody(); }); rq.test("Success field is true", () => { rq.response.to.have.jsonBody("success", true); }); rq.test("User data object has required fields (id, name, email, role)", () => { rq.response.to.have.jsonBody("data.id"); rq.response.to.have.jsonBody("data.name"); rq.response.to.have.jsonBody("data.email"); rq.response.to.have.jsonBody("data.role"); }); ``` ## Advanced Test Scenarios The AI Test Generator can handle complex scenarios: ### Schema Validation Instruction: **"Validate the entire response structure against a schema"** Generates schema validation tests that ensure the response conforms to the expected data structure. ```javascript theme={null} rq.test("Response has valid schema", () => { rq.response.to.have.jsonSchema({ type: "object", required: ["status", "success", "data"], properties: { status: { type: "number" }, success: { type: "boolean" }, data: { type: "object" } } }); }); ``` ## Tips for Better AI-Generated Tests 1. **Be Specific**: Clearly state what you want to test. Instead of "test the response," say "test that status is 200 and email is a valid email address" 2. **Reference Field Names**: Mention specific fields you want validated. The AI understands JSON paths like "user.email" or "data.items\[0].status" 3. **Use Examples**: Phrases like "similar to POST requests" or "like production data" help the AI understand context 4. **Combine Multiple Concerns**: You can ask for multiple validations in one instruction: "Validate status is 200, success is true, and items array is not empty" 5. **Iterative Refinement**: Use the "Edit Instruction" feature to progressively enhance your tests ## Current Limitations * AI Test Generator currently generates **Post-response scripts only** * Requires an actual API response to analyze. * Best results when the response has a well-structured JSON format ## Combining AI-Generated and Manual Tests You don't need to rely entirely on AI-generated tests. You can: 1. **Start with AI**: Let the AI generate basic validation tests 2. **Add Custom Logic**: Manually add additional test cases or pre-request scripts 3. **Refine Iteratively**: Use the Edit Instruction feature to improve generated tests over time 4. **Mix Approaches**: Combine AI-generated assertions with custom JavaScript logic ## Running and Debugging Tests After accepting the AI-generated tests, you can: * **Run Tests**: Click the **Send** button again to execute the request and run all tests * **View Results**: Check the test results in the **Test Results** panel * **Debug**: Use `console.log()` in the script to debug test execution * **Modify**: Edit the generated code directly if you need fine-grained control See [Writing Tests](/api-client/tests) for more information about executing and debugging tests. ## Related Topics * [AI features and your data](/account/ai-and-your-data) - What is sent to the AI service, what is masked first, and what to keep out * [Writing Tests](/api-client/tests) - Learn about manual test writing and all available assertion methods * [Scripts](/api-client/scripts) - Understand Pre-request and Post-response scripts * [Collection Runner](/api-client/collection-runner) - Run multiple requests and tests in sequence * [RQ API Reference](/api-client/rq-api-reference) - Full documentation of the `rq` object and its methods # API Collections Source: https://docs.requestly.com/api-client/api-collections Organise and manage APIs with Requestly’s API Collections. Learn to create, rename, delete collections, use folders, and explore collection variables. *** API Collections help developers and QA teams organize and group APIs for better management. They also offer additional features such as detailed API information and collection-specific variables. Let's explore how to create, manage, and utilize API Collections and their features. [https://www.youtube.com/embed/m8wdY3oSGRc](https://www.youtube.com/embed/m8wdY3oSGRc) ## Create API Collection **Step 1:** Click **+ New** and select **Collection**. ![](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---1-4.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=a3246f3b8e8c475ac13efa73ba99d45b) **Step 2:** Provide a descriptive name (e.g., “User Management APIs”) and hit **Enter**. ![](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---3.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=fd10d9a3a973b3aa82be7f4a9eb625fb) Once a collection is created, you can add requests and sub-collections. ## Rename API Collection **Step 1:** Click the **More** icon next to the collection name you want to rename, then select Rename. ![](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---2-4.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=4e30b4e0eca75cb9c4d8f4d1eca58aed) **Step 2:** An inline input field will appear with the current name. Update the name and press **Enter** to save the changes. ![](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---3-4.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=7713865383d136e4c300a4b074b6443d) ## Delete API Collection **Step 1:** Click the **More** icon next to the collection name and select `Delete`. **Step 2:** Confirm the action in the Delete Collection prompt. ![Confirm Delete Collection prompt with buttons labeled Cancel and Delete Collection](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---7.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=0a59f8ea0e579e5f8a6a49e929d68c27) > [!WARNING] > > Make sure you are deleting the correct collection. Deleted collections in cloud projects can be restored within 7 days by contacting support. See the [Data Recovery Policy](../account/data-recovery) for details. ## Create Folders Folders allow you to create sub-groups within a collection. They can have their own collection variables and share all the features of a collection. Folders(Sub-Collections) inherit all the collection variables from its parent. However, You can override parent-collection variables by defining a collection variable inside the sub-collection. **Step 1:** Click on the Add Folder icon next to the collection name. ![](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---5.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=311cafa8c5a9f08bd929b520fe09719d) **Step 2:** Provide a descriptive name (e.g., “Login APIs”) and press **Enter**. ![](https://mintcdn.com/requestly/71zp2E4ip50ZwDis/images/API-Collection---6.png?fit=max\&auto=format\&n=71zp2E4ip50ZwDis\&q=85\&s=4fa70bde7083ffe2779faa3430e67751) ## Collection Variables Collections include a **collection variables** feature that allows you to define and manage reusable values specific to the collection. Collection Variables are defined as key-value pairs that work as the base set of variables for collections. They can be used in API definitions with double curly braces `{{collection_variable}}` Learn more about this feature on the [Variables](/api-client/environments-and-variables) page. ## Collection Runner The **Collection Runner** allows you to execute multiple API requests from a collection sequentially in a single run. It helps automate request workflows such as *login → create resource → fetch resource* while utilizing existing variables and scripting capabilities. Use it to configure iterations, delays, and environments, view detailed run results, debug failed requests, and export summaries for analysis. Learn more about this feature on the [**Collection Runner**](https://docs.requestly.com/api-client/collection-runner) page. # Component Library Source: https://docs.requestly.com/api-client/api-design/component-library Keep schemas, parameters, responses, and other OpenAPI components in one place per project and reference them from any specification with $ref. A pagination parameter, an error response, a `User` schema: the same handful of definitions turn up in every specification you write. The Component Library is where they live once. Each entry is an ordinary OpenAPI component object, and any specification in the project can point at it with a `$ref`. There is exactly one library per project, shared by every specification in it. Find it under **Components Library** in the **API Design** sidebar panel, below **Specs**. The section starts collapsed, so click the header to open it. ![The Components Library section of the API Design sidebar, expanded to show entries grouped under Schemas, Parameters, and Responses](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-components-library.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=c714930a0ad3a32e2d9f74526e55b437) ## Categories Entries are grouped by category, and the categories are OpenAPI's own. All ten are available. | Category | Holds | | - | - | | **Schemas** | Data shapes. The most-used category by a wide margin. | | **Parameters** | A single path, query, header, or cookie parameter. | | **Responses** | A complete response: description, content, headers. | | **Headers** | A single response header definition. | | **Request bodies** | A complete request body: description, content, whether it is required. | | **Security schemes** | An authentication scheme, such as a bearer token or an API key. | | **Examples** | A named example value. | | **Links** | A relationship from one operation's response to another operation. | | **Callbacks** | An out-of-band request the API makes back to the caller. | | **Path items** | A reusable set of operations on one path. | > [!NOTE] > > Path items are an OpenAPI 3.1 feature, and referencing one is currently flagged as an error in a 3.1 document rather than in a 3.0 one. Treat that diagnostic as a known rough edge, not as a problem with your reference. ## Create a component **1. Pick a category** Click the `+` on the **Components Library** header and choose a category from the menu. Once a category has entries it gets its own group row, and you can hover that and click the `+` there to go straight into it. Empty categories are not shown, so the header menu is the only route to a category's first entry. The same menu is on **+ New → Component** in the sidebar toolbar. ![The New component menu listing all ten OpenAPI component categories, from Schemas to Path items](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-new-component-menu.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=4029f87768815128bc6a96c11bb164c3) **2. Name it** The component opens in a new tab with its name focused in the breadcrumb. Type a name and press Enter. A name may use letters, digits, dots, hyphens, and underscores, up to 128 characters. It has to be unique within its category, and it is case sensitive: `User` and `user` are two different schemas, which is what OpenAPI itself does. **3. Write the body** The editor is seeded with a minimal valid object for the category you chose, so you are editing rather than starting from nothing. A new schema arrives as: ```yaml theme={null} type: object properties: id: type: string required: - id ``` Write the component object only. There is no `components:` wrapper and no name key inside the body: the name is the entry's name in the sidebar. **4. Save** Press `Cmd/Ctrl + S` or click **Save**. A `• unsaved` marker sits beside the name until you do. > [!WARNING] > > A component's category is fixed once it is created. Moving a definition from **Schemas** to **Responses** means creating the new entry and deleting the old one, then repointing the references. ## The component editor ![A schema component open in its editor tab, with the Components Library, Schemas, and component name in the breadcrumb](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-component-editor.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=2de0f26f9cb1a6142876a03b37f67ea1) A single editor pane, in YAML or JSON, with a **YAML / JSON** dropdown and two icon buttons in the toolbar, one to copy the document and one to prettify it. There is no outline and no documentation rail: a component is one object, not a whole document. `$ref` completion works here too, so a component can reference another component. A `NotFound` response that points at an `Error` schema is written exactly the way a specification would write it. ## Reference a component from a specification In the specification editor, type `$ref:` and pick the entry from the list. Library entries are labelled `library` in the right-hand column, and selecting one writes the path for you: ```yaml theme={null} paths: /pets: get: summary: List pets responses: '200': description: OK content: application/json: schema: $ref: '../../components/schemas/Pet.yaml' '404': $ref: '../../components/responses/NotFound.yaml' ``` Requestly resolves these by category and name rather than by walking the path, so they always resolve inside Requestly. The written path is not correct relative to the files on disk, so another OpenAPI tool pointed at the exported document will not follow it. Bundle or inline the components before handing a document to external tooling. > [!TIP] > > Let the completion write the path. Hand-typing the relative depth is the easiest way to create a reference that resolves nowhere. In the editor, a library reference is drawn as a chip carrying the entry's name and category rather than the raw path. Hover it for the target's description and a preview of its body, and `Cmd/Ctrl + click` it to open that component in its own tab. See [create and edit a specification](/api-client/api-design/create-and-edit-a-specification#reference-a-component-with-ref) for the rest of the `$ref` behaviour. ## When a reference does not resolve Requestly checks every reference against the library and flags the ones that fail, both inline in the editor and in the Issues panel. | What went wrong | What you see | | - | - | | No such entry | The reference names a category and entry the project's library does not have. Check the spelling and the case. | | Wrong category | The reference points at the right name in the wrong category, for example a schema where a response is expected. The message names the category that belongs there. | | Invalid name | The name in the path uses characters OpenAPI component names do not allow. | | A URL | References to a component on another host are not supported. Bring the definition into the library instead. | Full triage, including the governance rules that run alongside these checks, is in [issues and governance](/api-client/api-design/issues-and-governance). ## Rename or delete Both are on the entry's `⋯` menu in the sidebar, and renaming is also available by clicking the name in the breadcrumb. Renaming changes the path every reference uses, so references written against the old name stop resolving and are flagged in the specifications that hold them. Deleting asks you to confirm and warns that references to the entry will break. Neither can be undone. In a local project, library entries are files on disk under `components//`, so a rename or a delete is a change you can review and commit like any other. Commit the project's `.requestly/` folder too: each entry has a metadata file there, and an entry whose metadata is missing is skipped silently rather than reported. # Create and Edit a Specification Source: https://docs.requestly.com/api-client/api-design/create-and-edit-a-specification Write an OpenAPI 3.x document in Requestly with key completion, an outline that tracks your cursor, $ref navigation, and a live documentation preview. The specification editor is a text editor for your OpenAPI document, with three things wrapped around it: an outline of the document in the sidebar, a documentation preview beside it, and problems flagged on the lines that caused them. ## Prerequisites * A project is open. Specifications belong to a project, so there is nowhere to put one until you have picked a project. * Your role can edit. On a read-only role the editor opens, but it will not accept typing and **Save** is disabled with the reason on hover. ## Create a specification **1. Start a new specification** In the API Client sidebar, open **API Design** and click the `+` on the **Specs** header. Choose **OpenAPI 3.1 (default)** or **OpenAPI 3.0**. You can also use **+ New → API spec** from the sidebar toolbar, which offers the same two versions. **2. Name it** The document opens in a new tab with the name in the breadcrumb focused. Type a name and press Enter. You can rename it later by clicking the name in the breadcrumb. **3. Write the document** A new specification is seeded with a minimal valid document so the editor is never a blank page: ```yaml theme={null} openapi: 3.1.0 info: title: New spec version: 0.0.0 paths: {} ``` Fill in `info`, then add servers, paths, and operations. **4. Save** Press `Cmd/Ctrl + S`, or click **Save** in the tab header. A `• unsaved` marker sits next to the name until you do. > [!TIP] > > Once saved, the specification appears under **Specs** in the sidebar and expands into an outline of what you wrote. ## The editor at a glance ![The specification editor with the document outline in the sidebar, the OpenAPI document in the middle, the documentation preview on the right, and the issues panel docked below](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-spec-editor.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=d6ec90a65e63b29daf16591837dbcbb3) Four regions, all working on the same document: * **The outline**, in the sidebar under the specification's name. The document's structure as a tree. * **The document**, in the middle. Where you type. * **The Documentation rail**, on the right. A rendered preview of whatever you are looking at. * **The Issues panel**, below the editor. Everything currently wrong with the document. It can be docked to the bottom or the right, or collapsed out of the way. See [issues and governance](/api-client/api-design/issues-and-governance). Drag the divider between the document and the rail to give either one more room. ## The toolbar Above the document: * **Back** and **forward** arrows. These walk your navigation history inside the document, so after following a `$ref` or clicking an outline row you can return to the exact line you left. * The **OpenAPI version** of the specification, as a label. It is not a switcher. * A **YAML / JSON** dropdown. Picking the other format converts the document in place. * Two icon buttons on the right: **Copy code** copies the whole document, and **Prettify code** runs Prettier over it, in YAML as well as JSON. Long lines are not wrapped. OpenAPI nests deeply, and wrapping breaks the indentation you are reading structure from, so the document scrolls sideways instead. > [!WARNING] > > Converting YAML to JSON drops every comment in the document, because JSON has none. Converting back gives you valid YAML but not your original formatting, and YAML anchors and merge keys do not survive: a merge key is flattened and left behind as a literal `<<` property. If the conversion fails because the document does not parse, Requestly tells you why and leaves the document untouched. ## Write with help from the editor As you type inside the document, Requestly offers completions for the OpenAPI keys and values that are valid at the cursor, drawn from the OpenAPI 3.1 schema. HTTP methods and enum values are ranked above generic keys, so inside a path item the methods come first. Hover a key to read what it means. Problems appear as you introduce them: a YAML or JSON syntax error, a structural violation, a broken reference, or a governance rule your project enforces. Each is underlined on the offending line and listed in the Issues panel. ## Add a section from the outline The outline always shows the five top-level buckets, **Servers**, **Tags**, **Paths**, **Components**, and **Security**, even when the document has none of them yet. Empty ones read "No servers yet" and the like. **Security** is not populated yet, so it reads empty even once your document declares security requirements. Hovering **Servers**, **Tags**, or **Paths** reveals a `+`. Click it and Requestly splices a starter entry into that block and scrolls the editor to it, ready for you to edit. On **Components** the `+` opens a submenu first, so you pick which component category the new entry goes into. > [!NOTE] > > Section insertion writes YAML. On a document stored as JSON the `+` does nothing rather than reformat your file, so switch to YAML first if you want it. ## Move between the outline and the document The outline and the cursor stay in step, in both directions. * **Click an outline row** and the editor scrolls to that node and puts the cursor at its first line. Clicking the same row again scrolls back to it. * **Move the cursor** in the document and the outline highlights the row you are now inside, and expands to reveal it. Either way, the Documentation rail follows: land inside an operation and the rail renders that operation, land inside a component and it renders that component, click the specification's own name and the rail returns to the overview. ## Reference a component with `$ref` Type `$ref:` followed by the first letters of the component's name, and Requestly offers every component you can point at, narrowing the list as you type. Two kinds appear in the same list, labelled in the right-hand column: * **in-spec**, the components defined inside this document under `components:`. Selecting one inserts a JSON pointer such as `'#/components/schemas/Error'`. * **library**, the project's shared [Component Library](/api-client/api-design/component-library) entries. Selecting one inserts the path to that entry, such as `'../../components/schemas/Pet.yaml'`. ![The \$ref autocomplete open in the specification editor, listing in-spec and library components with their category in the detail column](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-ref-autocomplete.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=3672f544240829185128070aa8cdacdd) Completion fires where `$ref` looks like a key at the start of the line, so a `$ref` mentioned mid-sentence in a description does not trigger it. ### Reading and following a reference A reference into the Component Library is drawn as a chip showing the entry's name and category, rather than the raw file path, so you can skim what a document points at. Hover the chip for the target's description and a preview of its body. ![Hovering a \$ref chip in the specification editor shows the referenced component's category, name, description, and a preview of its body](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-ref-chip-tooltip.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=0ca899ae77e74b1929efbe08337f42d6) `Cmd/Ctrl + click` a reference to follow it: * A **library** reference opens that component in its own tab. * An **in-spec** reference scrolls this document to the definition. In-spec references stay as plain text rather than becoming chips. `#/components/schemas/Error` is already short and tells you where the definition lives, and hiding it behind a chip would take that away. Either way, the toolbar's back arrow returns you to the line you followed the reference from. ## Read the documentation preview The rail on the right renders the current selection as documentation: the operation's parameters, request body, and per-status responses, or a component's schema as an expandable tree. References inside the rail are resolved and expanded in place, so you read the real shape instead of a pointer. The rail is a preview, not a second editor. Clicking around in it never changes what the document says. ![The Documentation rail rendering a single operation with its path parameter and its response schema tree](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-documentation-rail.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=08a1b9e17d9d6e2cc51ab8ef5e44386f) The rail also carries a **Versions** tab for the specification's releases, and on any cloud project a **Changelog** tab recording every save. Both are covered in [versions and releases](/api-client/api-design/versions-and-releases). ## Rename or delete a specification Both live on the specification's row in the sidebar, under the `⋯` menu, and renaming is also available by clicking the name in the breadcrumb. A rename changes the specification's name in Requestly and, in a local project, the file it is stored in. It does not rewrite `info.title` inside the document, so update that yourself if you want the two to match. Deleting asks for confirmation first and cannot be undone. # Issues & Governance Source: https://docs.requestly.com/api-client/api-design/issues-and-governance Read the Issues panel of a specification, understand which severities block actions, and suppress a governance rule you do not want to follow. Every time you edit a specification, Requestly re-checks it and reports what it found in the **Issues** panel at the bottom of the spec editor. The panel is the one place that answers three different questions: is my document still valid, does it follow the API rules, and why is a button greyed out. The panel has two tabs, and the difference between them matters: * **Syntax**: the document could not be read, or a `$ref` in it points at something that does not exist. Everything here is an error. * **Governance**: the document reads fine, but a rule about how an API should be described was not satisfied. Findings here carry a severity, and most of them do not block anything. The panel sits below the editor and collapses out of the way with the chevron on its header. Clicking a tab while the panel is collapsed expands it. ## Read the Syntax tab The Syntax tab lists three kinds of problem: * **Parse errors**: the YAML or JSON is malformed. If the specification is saved as JSON, Requestly also rejects YAML-only constructs that plain JSON does not allow, so a file that is nearly-JSON is caught rather than quietly accepted. * **Broken references**: a `$ref` cannot be resolved, either inside the document or against your project's [component library](/api-client/api-design/component-library). The same component referenced from three places produces three rows, each pointing at its own line. * **Structural errors**: the document parses but is not a valid OpenAPI document, for example one that never declares an `info` object. These carry no line number, so clicking the row does not jump anywhere. All three are always errors, and all three block the actions listed under [What blocks and what only warns](#what-blocks-and-what-only-warns). ## Read the Governance tab Governance checks come from the standard OpenAPI rule set, so the rules are the same ones your team probably already runs in CI. ![The Governance tab of the Issues panel listing one path-params error and several warnings, with severity filter chips and a search box above the list](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-issues-governance.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=88c3dd5be879454319b393c1d1193aff) Each row reads left to right: a severity icon, the rule id that fired, the message, and the line it was found on. * **Click the row** to jump the editor to that line. Issues also appear as inline markers in the editor itself, so you can work from either surface. * **Hover the info icon** for the rule's own description, the path inside the document that the rule was looking at, and a **Learn more** link to the rule's reference page. * **Open the three-dot menu** to suppress the rule. See [Suppress a rule](#suppress-a-rule). Above the list, four chips filter by severity and show the count for each: **Errors**, **Warnings**, **Info** and **Hints**. Click a chip to filter by it, click it again to clear. With no chip selected, everything is shown. The search box next to them matches on both the message and the rule id, so typing `operationId` narrows to that rule. > [!TIP] > > The rule ids and the **Learn more** links come from Spectral's OpenAPI ruleset. Searching a rule id such as `path-params` finds the same reference page the link opens. ## What blocks and what only warns This is the part worth getting exactly right, because it decides which buttons you can press. | Severity | Shown as | Blocks Generate Collection, Update Collections and Release version? | | - | - | - | | Error | Red error icon | **Yes.** One error is enough. | | Warning | Amber warning icon | No. | | Info | Blue info icon | No. | | Hint | Green lightbulb | No. | Everything on the **Syntax** tab counts as an error, and so does any **Governance** finding whose severity is Error. Nothing else blocks. A specification with thirty warnings and no errors generates and releases perfectly well. Most governance rules are warnings. The rules that carry Error severity are the ones where the document is genuinely wrong rather than merely unconventional, for example an operation whose path is `/pets/{petId}` but which never declares a `petId` path parameter. > [!WARNING] > > While the check is still running the same actions stay disabled, and hovering one explains that validation is still in progress. The button labels never change. Requestly will not act on a specification it has not finished checking, so give it a moment after a large edit. When an action is blocked, hovering it names how many errors are in the way. Open the Issues panel yourself to see them, and check **both** tabs: a blocked action does not always mean a governance error, and broken references and parse errors live on **Syntax**. ## Suppress a rule If a rule is not one your team follows, turn it off instead of editing your API to satisfy it. **1. Find the rule in the Governance tab** Open the **Issues** panel, switch to **Governance**, and locate any row produced by the rule you want to stop seeing. **2. Open the row's three-dot menu** Click the three-dot button at the right of the row. Two choices appear: * **Suppress for this spec**: the rule stops firing on this specification only. * **Disable project-wide**: the rule stops firing on every specification in this project. ![An Issues panel row with its three-dot menu open, showing Suppress for this spec and Disable project-wide](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-suppress-rule-menu.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=aa88197c573617a35a9f5ab11df5ae36) **3. Confirm the effect** The rule's rows disappear from the list and its counts drop. Suppression is saved immediately and survives a reload. Note that this saves the specification as a whole, so any unsaved edits in the editor are committed at the same time. > [!TIP] > > Suppressing a rule that was reporting an error clears the block. Once the last error is gone, Generate Collection, Update Collections and Release version become available. Suppression is per rule, not per occurrence: you cannot silence one line and keep the rule elsewhere in the same document. Suppressing in either scope silences the rule, and the two lists are kept separate: restoring a rule under **This spec** does not bring back one you disabled project-wide, and the reverse is also true. Restore a rule in the tab it was suppressed from. ## Review and restore suppressed rules Suppressions are easy to forget, so the Governance tab keeps a running count of them. The button with the crossed-out eye, to the left of the search box, shows how many rules are suppressed across both scopes. Click it to open the **Suppressed rules** drawer. ![The Suppressed rules drawer open over the Issues panel, with This spec and Project-wide tabs and a Restore button beside each rule id](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-suppressed-rules-drawer.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=1937fbb577b5c6f2861183aad1127dd8) The drawer splits the list in two tabs, each with its own count: * **This spec**: rules suppressed on the specification you have open. * **Project-wide**: rules suppressed for every specification in the project. Search by rule id to find one in a long list, then click **Restore** to bring the rule back. Restoring re-runs the checks, so any findings that rule was hiding reappear immediately, including errors that will block again. ## Next steps * [Generate and update a collection from a specification](/api-client/api-design/sync-a-collection-from-a-specification), the first action the validation gate protects. * [Release a version of a specification](/api-client/api-design/versions-and-releases), which is blocked by the same errors. * [Create and edit a specification](/api-client/api-design/create-and-edit-a-specification) for the editor surface itself. # API Design Source: https://docs.requestly.com/api-client/api-design/overview Write and edit OpenAPI specifications inside Requestly, with a project-wide library of reusable schemas, parameters, and responses. Most work in the API Client starts from a request you send. API Design starts from the other end: you write the contract first, as an OpenAPI document, and everything else follows from it. The document lives in your project alongside your collections, so the design and the requests you send against it stay in one place. Open it from the **API Design** icon in the API Client sidebar. ![The API Design panel in the API Client sidebar, with an empty Specs section offering New spec and a collapsed Components Library section](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-sidebar-empty.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=305d6ccf186ef98a269ebc3032cf1c61) ## Design a specification or build a collection? Both describe the same API. They are good at different things. | Reach for | When | | - | - | | A **specification** | The contract is the deliverable. You are agreeing on endpoints before anyone implements them, you need the shape reviewed, or you want one definition that generates collections, mocks, and docs. | | A **collection** | Calling the API is the deliverable. You want to send a request, script against the response, write tests, and run the whole thing in CI. | You are not choosing once. A specification can generate a collection you then send requests from, and a collection can be exported as an OpenAPI file. See [sync a collection from a specification](/api-client/api-design/sync-a-collection-from-a-specification) for the link between the two, and [import an OpenAPI spec](/api-client/import-export/import-openapi-spec) to bring an existing file in as either one. ## What a specification is here A specification is an OpenAPI 3.x document you edit as text, in YAML or JSON, with the editor helping you as you type: completion for OpenAPI keys, an outline of the document in the sidebar, a live documentation preview beside it, and problems flagged inline as you introduce them. You can author **OpenAPI 3.1** (the default) and **OpenAPI 3.0**. Swagger 2.0 files can be imported, but only as a collection: they cannot be edited as a specification. There is no AsyncAPI authoring. > [!NOTE] > > Requestly stores the standard document and nothing else. There are no Requestly-only keys added to your file, so what you export is what you wrote. ## How specifications sit in a project Everything under API Design is scoped to one project. * **Specs** are the documents themselves. A project can hold as many as you like. * The **Components Library** is a single shared library per project. Every specification in the project can reference the same schema, parameter, or response instead of repeating it. See [the Component Library](/api-client/api-design/component-library). In a local project, both are ordinary files you can commit: specifications under `specs/`, library entries under `components//`, plus the project's `.requestly/` folder, which holds a metadata file for each of them. Commit `.requestly/` as well: a specification or component whose metadata file is missing does not load and is not reported as broken, so a teammate who clones without it sees nothing. In a team project they sync like the rest of your project, and your role applies. On a read-only role you can open and read every specification and component, but **Save**, rename, and delete are disabled with the reason on hover. ## The sidebar The panel has two sections, a search box across the top, and a `+` button on each section header. * **Specs** lists every specification in the project. Expand one and you get its outline: **Servers**, **Tags**, **Paths**, **Components**, and **Security**. Paths expand into their operations, each with its method badge. Clicking an entry inside a bucket jumps the editor to that line. **Security** stays empty for now even when your document declares security requirements. * **Components Library** lists the project's reusable pieces, grouped by category. It starts **collapsed**, because most of the time you are working in a document rather than browsing the library. Click the header to open it. ![The API Design panel with a specification expanded to show its Servers, Tags, Paths, Components, and Security outline, and operations with method badges](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-sidebar-outline.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=9d703a20e9dddfe6e7159fccb851cbf0) Typing in the search box filters both trees at once and opens both sections while the query is active, so a match in the library is never hidden behind a collapsed header. > [!TIP] > > With more than one project active, the panel shows one collapsible section per project, each with its own Specs and Components Library. ## Create your first specification **1. Open the Specs section** Click the **API Design** icon in the API Client sidebar. If the project has no specifications yet, the **Specs** section shows "No specs yet" with a **New spec** button. **2. Pick an OpenAPI version** Click **New spec** (or the `+` on the **Specs** header) and choose **OpenAPI 3.1 (default)** or **OpenAPI 3.0**. The same choice is available from **+ New → API spec** in the sidebar toolbar. ![The New spec dropdown offering OpenAPI 3.1 (default) and OpenAPI 3.0](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-new-spec-version-menu.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=04ca75880e0c417e4986568dd9337731) **3. Name it** The specification opens in a new tab as a draft, seeded with a minimal valid document, and the name in the breadcrumb is focused. Type a name and press Enter. **4. Save** Press `Cmd/Ctrl + S` or click **Save**. Nothing is written to the project until you save, so a draft you abandon leaves nothing behind. Next: [create and edit a specification](/api-client/api-design/create-and-edit-a-specification) covers the editor itself. ## What you can do with a specification Once a specification exists, the rest of API Design hangs off it. * **Read it as documentation.** The rail beside the editor renders the document as you type: operations, parameters, request and response bodies, and schema trees. * **Keep it clean.** Problems are flagged inline in the editor and collected in an Issues panel, with a governance ruleset you can tune per project. See [issues and governance](/api-client/api-design/issues-and-governance). * **Turn it into requests.** Generate a collection from the specification and keep the two in step as the document changes. See [sync a collection from a specification](/api-client/api-design/sync-a-collection-from-a-specification). * **Cut a version.** Freeze the current document as a named release you can come back to. See [versions and releases](/api-client/api-design/versions-and-releases). * **Publish it for other people to read.** Put a released version on a shareable URL, with public, internal or password access. See [publish API documentation](/api-client/api-design/publish-api-docs). > [!WARNING] > > Deleting a component that specifications still reference breaks those references. Requestly warns you before the delete and then flags every broken `$ref` in the affected documents. # Publish API Documentation Source: https://docs.requestly.com/api-client/api-design/publish-api-docs Publish a collection's API documentation to a shareable URL with public, internal or password access, republish it after a release, and unpublish it again. A collection that is linked to an OpenAPI specification can publish that specification as a documentation site. Requestly hosts the result at a fixed URL, and the reader opens it in a browser without installing anything. Public and password-protected docs need no Requestly account. Internal docs are the exception: they ask the reader to sign in as a member of the project. What gets published is always a **released version** of the specification, never your working document. You pick which release goes live, and it stays live until you pick a different one. ## Before you publish * **A cloud project.** Publishing is not available in local projects. In one, the collection's Documentation tab reads "Publishing is not available in local projects" and offers no publish control. * **A top-level collection.** The collection's Documentation tab appears on root collections only, not on folders inside them. * **A linked specification.** If the collection has none, you can [generate one from the collection itself](#publish-from-a-collection-with-no-specification). * **At least one released version** of that specification. Until one exists, **Publish** stays disabled. See [versions and releases](/api-client/api-design/versions-and-releases). * **Edit access to the collection.** Without it, **Publish** and **Unpublish** stay disabled and their tooltips say you need edit access. ## Publish a collection's documentation **1. Open the collection's Documentation tab** Select the collection in the sidebar, then open the **Documentation** tab in the tab strip beside **Overview**, **Variables**, **Authorization**, **Scripts** and **Runner**. A **Synced from spec** line at the top carries a **Go to source** link. The link opens the specification the docs come from, and only its tooltip names that specification. Once the docs are live, this line disappears. The same link then sits in the top-right of the status card. **2. Choose who can read the docs** Pick one of the three **Visibility** options. They are covered in detail under [visibility modes](#visibility-modes). ![The Documentation tab of a collection showing the Public, Internal and Password visibility options, the Spec version dropdown and the Publish button](https://mintcdn.com/requestly/g_Pk_BuP0kseglPo/images/api-docs-publish-form.light.png?fit=max\&auto=format\&n=g_Pk_BuP0kseglPo\&q=85\&s=47b04ec927f316ff00ad8c4f87578624) **3. Pick the version to serve** Open the **Spec version** dropdown and choose a released version. Each entry shows its name and release date, and the one currently live is marked **(currently live)**. A version released without scrubbing carries a warning icon, and selecting it shows: "This version was released without scrubbing - its content, including any credentials, will be visible to anyone who can access this documentation." Release a scrubbed version instead if that matters to you. **4. Publish** Click **Publish**. The docs go live immediately and a status card appears above the form. **5. Share the URL** The status card shows a **Live** badge and the documentation URL, which has the form `/view//`. Use the copy button to put it on your clipboard, or **View** to open the published page in a new tab. ![The published status card with a Live badge, the documentation URL with a copy button, a View button, the current visibility and version, and Republish and Unpublish buttons](https://mintcdn.com/requestly/g_Pk_BuP0kseglPo/images/api-docs-published-status.light.png?fit=max\&auto=format\&n=g_Pk_BuP0kseglPo\&q=85\&s=de31e3eef68b1d9d071d41b6aae6f88c) > [!NOTE] > > The URL is derived from the project and collection, so it never changes. Republishing a different version reuses the same link, and every bookmark your readers made keeps working. A published collection also carries a small green checked-clipboard icon in the sidebar, with a **Published** tooltip, so you can tell at a glance which collections are live. ## Visibility modes | Mode | Who can read it | What the reader does | | - | - | - | | **Public** | Anyone with the URL | Opens the docs straight away. No account, no sign-in. | | **Internal** | Signed-in members of the project | Signs in first. A signed-in non-member is told "You don't have access to this collection's documentation" and asked to contact the project owner. | | **Password** | Anyone with the password | Enters the password once, then reads the docs. Built for partners and contractors who have no account. | ### Set a password Choose **Password** and the form reveals a password field. The password must be 8 to 128 characters. There are no composition rules, so a passphrase is fine. The password is never stored in a form you can read back. When you republish a collection that is already password-protected, leaving the field blank keeps the current password, and typing a new one replaces it. > [!WARNING] > > Everything in the released version reaches everyone who can open the docs. A password gates the page, not the contents of the snapshot. ## Publish from a collection with no specification A collection that was never linked to a specification shows an empty state reading "Not linked to an API spec yet". You have two ways forward from here. ![The Documentation tab empty state reading Not linked to an API spec yet, with Open API Design and Generate spec from this collection buttons](https://mintcdn.com/requestly/g_Pk_BuP0kseglPo/images/api-docs-no-linked-spec.light.png?fit=max\&auto=format\&n=g_Pk_BuP0kseglPo\&q=85\&s=b64f233d0c76c49923ec28145afd363e) * **Open API Design** takes you to the specification editor, where you write a document and [generate its collection](/api-client/api-design/sync-a-collection-from-a-specification). * **Generate spec from this collection** builds an OpenAPI specification out of the requests you already have, in one step. > [!NOTE] > > **Generate spec from this collection** is disabled when the collection holds no HTTP requests at all. Its tooltip explains why: only HTTP requests can be described by an OpenAPI specification. ### Generate a specification from the collection Click **Generate spec from this collection**, give the specification a title, and confirm with **Generate spec**. ![The Generate spec from this collection dialog with a Spec title field, an explanation of the one-way sync, and a warning listing what will not be in the spec](https://mintcdn.com/requestly/g_Pk_BuP0kseglPo/images/api-docs-generate-spec-modal.light.png?fit=max\&auto=format\&n=g_Pk_BuP0kseglPo\&q=85\&s=c9c0d9b3f48dc07d45a6ed2281c42f45) The dialog counts the HTTP requests it will convert and states the consequence plainly: the generated specification becomes the source of truth. From that point on, edits flow one way. Changes you make in the specification reach the collection when you run **Update Collections**, and changes you make in the collection do not flow back. Under the heading "Some of this collection won't be in the spec", the dialog lists only what you would lose. The block is absent when nothing is lost, and each kind below appears only when your collection holds it: * **Non-HTTP requests.** GraphQL, gRPC, MQTT, WebSocket and Socket.IO requests are skipped, because OpenAPI cannot describe them. Each kind is counted so you know what you are leaving behind. * **Folders**, which flatten into paths. * **Saved examples**, which are not carried over. * **Pre-request and test scripts**, which are not carried over. Once the specification exists, release a version of it and come back to the Documentation tab to publish. ## Keep the published docs current The live version never changes on its own. Releasing a new version of the specification does not move the docs onto it, so a reader is never surprised by a document you were not ready to ship. Requestly tells you when the two have drifted apart: * **A newer release exists.** The status card reads "Newer spec release available", names the newest version, and asks you to select it below and republish. * **You changed the form but did not apply it.** The card reads "You have unpublished changes to the version or visibility", which is the reminder to click **Republish**. To move the docs forward, select the version you want in **Spec version**, adjust visibility if you need to, and click **Republish**. The URL is unchanged. > [!TIP] > > The specification editor tracks this from the other side. Its **Versions** tab has a **Published as docs** section listing every collection publishing from that specification and whether each one is **Current** or **Newer available**. See [versions and releases](/api-client/api-design/versions-and-releases#documentation-status). ## Unpublish Click **Unpublish** beside the primary action and confirm in the dialog titled "Unpublish this collection's docs?". The dialog states the outcome: "Visitors will see a 404 until you re-publish. Your visibility and version settings are kept." The 404 is the response the page requests; what a visitor actually reads is the "Documentation unavailable" page described under [when a reader cannot open the docs](#when-a-reader-cannot-open-the-docs). Confirming with **Unpublish** takes the page down; **Keep published** backs out and changes nothing. Because the settings survive, republishing later is a single click - you do not have to pick the version and the visibility again. > [!NOTE] > > Deleting the collection, or deleting the released version the docs point at, also takes the published page down. The delete confirmation for a version names every collection that will be unpublished. ## What a recipient sees The published page is a standalone reader. It has no Requestly application chrome, no sidebar of your other collections, and nothing editable. It shows the outline of the API on the left and the rendered document on the right. ![The published documentation reader with the endpoint outline grouped by tag on the left and an operation with its parameters, responses and code samples on the right](https://mintcdn.com/requestly/g_Pk_BuP0kseglPo/images/api-docs-reader.light.png?fit=max\&auto=format\&n=g_Pk_BuP0kseglPo\&q=85\&s=bdebb1f58ac27fff7a2c58aa5e53ae83) ### Finding an endpoint * **Endpoints are grouped by tag.** The outline lists one group per tag from your specification, with each operation under it carrying its method badge. A specification that declares `x-tagGroups` nests its tag groups under those super-groups. A specification with no tags falls back to a single flat **Paths** group. A **Servers** group sits above the tag groups and a **Components** group below them. * **Search the outline with `Cmd`/`Ctrl` + `K`.** The shortcut jumps straight to the outline's search field, which filters the tree as the reader types. * **The outline follows the reading position.** Scrolling the document highlights the matching outline row, so a reader deep in a long document always knows where they are. ### Link to a single operation Every operation has its own URL. As a reader moves through the document, the address bar updates with a fragment naming the current section, so copying the URL at any point links to exactly that operation. Opening such a URL scrolls straight there instead of to the top of the page. The fragment is derived from the specification, so it is readable and stable: ```text theme={null} https:///view//#paths./users/{id}.get ``` Component schemas use the same idea, with fragments of the form `#components.schemas.User`. ### Copy a request in six languages Each operation carries a code sample panel with **cURL**, **JavaScript**, **Python**, **Go**, **Java** and **Ruby** tabs. Pick a language, click **Copy**, and the snippet is on the clipboard. The samples are there to be copied and run elsewhere; the reader does not send requests. A request body larger than 50 KB is trimmed in the sample, and the panel says so beneath the snippet. ### Open the specification as .md or .json The reader's header has **.md** and **.json** buttons. Each one opens the released specification in that format in a new tab, so a reader can feed it to another tool or keep a copy. ### How the document is rendered The reader renders the document faithfully rather than summarising it: * **Markdown is rendered.** Descriptions on the API itself, on tags, on operations, on components and on individual schema properties all render as formatted text, so code spans, bold text and links appear as you wrote them. * **`oneOf` and `anyOf` are labelled.** A schema built from alternatives shows each branch under a clear heading instead of collapsing them together. Where the specification declares a discriminator, the reader shows a variant selector and narrows the schema to the type the reader picks. ### When a reader cannot open the docs A reader who cannot open the docs gets a page that says why, as far as it is safe to say so: * **Password docs** show a prompt reading "This documentation is password-protected". A wrong password returns a plain "Incorrect password." with no hint. * **Internal docs** send a signed-out visitor to sign in first. A signed-in visitor who is not a member of the project is told they do not have access and to ask the project owner. * **An unpublished, deleted or mistyped link** shows an outside visitor the same "Documentation unavailable" page in every case. The page does not reveal whether the docs ever existed, so the URL cannot be used to probe for collections. A signed-in member of the owning project is the one exception. That page tells the member the docs are unpublished, and offers an **Open in Requestly** button to go and republish them. ## Next steps * [Versions & Releases](/api-client/api-design/versions-and-releases) to cut the release your docs will serve. * [Sync a collection from a specification](/api-client/api-design/sync-a-collection-from-a-specification) to keep the collection in step with the document you publish. * [Issues & Governance](/api-client/api-design/issues-and-governance) to clear the errors that block a release. # Sync a Collection from a Specification Source: https://docs.requestly.com/api-client/api-design/sync-a-collection-from-a-specification Generate a runnable API collection from an OpenAPI specification, then keep it in step with the spec using Update Collections. A specification describes your API. A [collection](/api-client/api-collections) is what you actually send requests with. API Design connects the two: generate a collection from a specification once, then push later spec changes into it whenever you want. > [!WARNING] > > The sync only runs one way. The specification is the source of truth, and editing the generated collection never changes the specification. Anything you write in the collection that the spec does not describe stays in the collection alone. That is the single most important thing on this page. If you change a path in the collection expecting the spec to follow, it will not, and the next update will flag your request as new. ## Prerequisites * The specification is saved. A brand new, unsaved specification cannot generate a collection yet; the button explains that. * The specification has at least one path. A document with an empty `paths` cannot produce a collection, and the button says so before you click. * The specification has no blocking issues. See [Issues & Governance](/api-client/api-design/issues-and-governance) for which severities block. * Your role can create and update items in the project. A viewer sees the buttons disabled with the reason. ## Generate a collection **1. Open the specification** Switch the API Client sidebar to **API Design** and open the specification from the **Specs** section. **2. Start Generate Collection** In the editor toolbar, click **Generate Collection**. If the specification already has collections linked to it, the toolbar shows a **Collections** button instead: open it and click **+ Generate Collection** inside. You can also start from the sidebar: open the specification's three-dot menu and choose **Generate collection**. ![The Generate collection from spec dialog with a Collection name field and a list of already-linked collections](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-generate-collection-modal.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=698a1b5906d82151387e1f594cabe893) **3. Name the collection and generate** Type a name and click **Generate**. The dialog also lists any collections already linked to this specification, so you can tell whether you are about to create a duplicate. **4. Check the result** A new top-level collection appears in the sidebar. Folders come from your URL path segments, and each operation becomes one request with its method, URL, headers, query parameters, path variables, body and content type already filled in. > [!NOTE] > > Generate always creates a **new** top-level collection. There is no way to point it at a collection you already have, and generated collections are always top level rather than nested inside another collection. One specification can have several linked collections, which is useful when different teams want their own copy. Each one is tracked separately and updated separately. ## Keep a linked collection up to date Once a collection is linked, Requestly watches the specification and works out what has drifted. You do not have to ask it to check. When something has drifted, the toolbar button changes: it reads **Update Collections** with a count of pending changes and picks up a warning icon. Open it to see one row per linked collection. ![The Collections popover listing a linked collection with an amber pending-change count and an enabled Update button](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-collections-panel.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=3d75f6789ea4c514f16b2ccef43491b0) Each row shows the collection's name, an amber count when it has pending changes, and an **Update** button. Click the name to open that collection in a tab. If a row has nothing pending, its Update button is disabled and says "No pending changes". **1. Open the Collections popover** Click **Update Collections** in the spec editor toolbar. **2. Click Update on the collection you want** Requestly opens a preview of exactly what would change in that one collection. Nothing has been written yet. **3. Read the preview** Changes are grouped by kind, and each group has an info icon explaining what happens to your own edits. See [What the preview tells you](#what-the-preview-tells-you). ![The Update preview dialog grouping changes into Added, Updated and In collection not in spec sections, with an Apply button counting the changes](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-update-preview.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=c94699ce515c1137a849b9046fb4af2f) **4. Apply** Click **Apply n changes**. Everything actionable in the preview is applied together; there is no per-row opt out. Requestly confirms how many changes landed. > [!TIP] > > After a successful apply, the toolbar button drops back to **Collections** with no count. That is how you know the collection matches the specification. ## What Update Collections tracks Update applies content changes as well as structural ones, so an edit to a request body or a query parameter in the spec does reach the collection. **Tracked:** * Operations added or renamed, by method and path * Operations moved between folders * An operation's summary or description * Request headers, query parameters, path variables, body and content type * Folder renames, and folder descriptions taken from your OpenAPI tags * The linked collection's own description, taken from the specification's top-level description **Not tracked:** response definitions, security schemes, examples and callbacks. The linked collection's **name** is also never overwritten, because you chose it when you generated the collection. A similar info icon sits next to the toolbar button in the product, so you can check what is tracked without opening a preview. ## What the preview tells you The preview is grouped so you can see the risk before you accept it. Each group's info icon states what survives. | Group | What it means | | - | - | | **Added** | New requests created under the matching path folder. | | **Renamed** | The request's URL is updated in place. Your auth, body, headers and captured responses are preserved. | | **Moved** | The request is re-parented to match the spec's path. Auth, body, headers and captured responses are preserved. | | **Updated** | Spec-side content changed, such as a summary, description, parameter or body. Your auth, scripts and captured responses are preserved. | | **Folders renamed** | The folder name is updated in place. Requests inside it, and their auth and variables, are preserved. | | **Folders updated** | The folder description is updated from the OpenAPI tag. Folder auth, variables and scripts are preserved. | | **Folders removed** | Folders left empty by moved requests are tidied up. | | **In collection, not in spec** (the row also says these are left untouched) | Informational only. These requests have no operation in the specification. | The last row is the one worth reading twice. Requests that exist in the collection but not in the specification are **never** deleted by Apply. They are listed so you know they are there, they are not counted in the change total, and you have to remove them yourself if you do not want them. A request lands in that group for one of two reasons: it really was removed from the specification, or it cannot be expressed in one. Two requests that share the same path and method, such as two query-string variants of the same endpoint, collapse to a single operation, so one of them will always show up here. ## When the specification cannot be synced * **Errors in the specification.** The Update and Generate buttons are disabled and hovering one names how many errors are in the way. Open the [Issues panel](/api-client/api-design/issues-and-governance) to see them, checking both the Syntax and Governance tabs. * **The check has not finished.** Immediately after a large edit the buttons stay disabled until the check completes, and hovering one says validation is still in progress. The labels themselves do not change. * **Unsupported features.** If your specification uses something the collection format cannot represent, the Collections popover lists it under an "unsupported features" note. The rest of the specification still generates and updates normally. * **The specification was deleted while the preview was open.** Apply stops and tells you to reopen the specification. ## Next steps * [Issues & Governance](/api-client/api-design/issues-and-governance) to clear whatever is blocking a sync. * [Versions and releases](/api-client/api-design/versions-and-releases) to pin a snapshot of the specification for downstream consumers. * [API Design overview](/api-client/api-design/overview) for how specifications, components and collections fit together. # Versions & Releases Source: https://docs.requestly.com/api-client/api-design/versions-and-releases Release an immutable snapshot of an OpenAPI specification, where the version number comes from the spec's own info.version field. A specification changes every time you save it. A **release** is the opposite: a fixed, self-contained snapshot of the specification at one moment, which never changes again. Anything downstream that needs a stable reference points at a release rather than at your working document. Releases live in the **Versions** tab of the right-hand rail in the spec editor, alongside the **Documentation** rail. ![The Versions tab of the spec editor rail listing two released versions with their age, notes and size, and a Release version button in the header](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-versions-pane.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=af06da900de6adb6c359096c9263fa41) > [!NOTE] > > On a cloud project the rail also has a **Changelog** tab, which is not the same thing. The changelog records every save automatically; a version is a snapshot you release deliberately, and it has a name you control. ## The version number comes from your specification You never type a version number. Requestly reads it from the `info.version` field of the specification itself, so the number in the release list is the number your API document declares. ```yaml theme={null} openapi: 3.1.0 info: title: Pet Store version: 1.4.0 ``` Releasing the document above produces a version called `1.4.0`. To release again later, edit `info.version`, save, and release. Releasing twice from the same `info.version` is refused with "This info.version is already released. Bump info.version in your spec to release a new version." `info.version` has to be usable as a name: letters, numbers, dots, hyphens and underscores only, between 1 and 64 characters. A value with a space or a `+` in it, such as `1.0.0+build7`, is rejected rather than silently trimmed, and the message tells you which characters are allowed. ## Prerequisites The **Release version** button is disabled until all three of these hold, and its tooltip names whichever one is missing: * **No blocking errors.** A single error on either tab of the [Issues panel](/api-client/api-design/issues-and-governance) blocks the release. Open the panel to find them, checking both tabs. Warnings, info and hints never block. * **No unsaved edits.** A release snapshots saved content, so the tooltip reads "Save your changes before releasing." Save first. * **An `info.version` value.** Without one the tooltip reads "Add an info.version to your spec to release." ## Release a version **1. Open the Versions tab** With the specification open, switch the right-hand rail to **Versions**. **2. Click Release version** Requestly checks the specification, gathers every component the document references, and prepares the snapshot. **3. Confirm the version and add notes** The dialog shows the version read from your specification, marked as coming from `info.version`, and it is not editable here. Release notes are optional and free text: "What changed in this version?" **Scrub sensitive data** is on by default. It replaces credential-shaped values in the snapshot with `` while keeping the shape intact, so a `Bearer` token becomes `Bearer ` and readers can still see that the endpoint expects a bearer token. ![The Release version dialog showing a read-only version taken from info.version, an optional release notes field, and the Scrub sensitive data checkbox](https://mintcdn.com/requestly/-Ov2rg1Fb6ueLIFe/images/api-design-release-version-modal.light.png?fit=max\&auto=format\&n=-Ov2rg1Fb6ueLIFe\&q=85\&s=24ab255860fa55419f87f44175fa00c5) **4. Review anything that survived the scrub** If Requestly still finds token-shaped text after scrubbing, usually inside a description or an example, it shows a **Review before releasing** screen listing each one with where it was found. Cancel to go and clean the document, or click **Release anyway** to accept it. **5. Release** Click **Release**. The new version appears at the top of the list. > [!WARNING] > > Everything in a release reaches everyone who can read that release. Take the review screen seriously: the values it lists are still in the snapshot. ## Work with a released version Each row in the list shows the version name, how long ago it was released, its notes and its size. * **Click the row** to open the version full screen, read only, with the same outline and documentation view as the editor. Every reference is already resolved inside the snapshot, so you are reading exactly what a consumer of that version gets. * **Open the row's menu** for **Copy content to clipboard**, **Download as YAML** and **Download as JSON**. Requestly converts between the two formats for you, so you can download JSON from a YAML specification. * **Delete version** removes it permanently. See [Deleting a version](#deleting-a-version). A release is self-contained. Components your specification pulled in by reference are written into the snapshot itself, which is why the size shown on the row can be larger than your working document. Snapshots are capped at 20 MiB, and a release over roughly 10 MB still succeeds but warns you that large snapshots are slow for anything reading them. ## Documentation status If any collection publishes documentation from this specification, the Versions tab gains a **Published as docs** section below the release list. It has a collapsible header, so you can fold it away when you do not need it. Each row names the collection, the version its documentation is currently serving, and a status: **Current** when it is on the newest release, or **Newer available** when a release has landed since. **Manage** opens that collection's own Documentation tab, where publishing is controlled; see [publish API documentation](/api-client/api-design/publish-api-docs). The section is read only: nothing here changes what is published. Right after you release, a short banner appears at the top of the tab if any published documentation is now behind. **Review** reveals the section above; dismiss it if you do not want to act now. ## Deleting a version Deleting a version is permanent and cannot be undone. Anything pinned to that version loses access to it. The confirmation dialog is worth reading rather than clicking through. If any collection's published documentation points at the version you are deleting, the dialog lists those collections by name and warns that they will be unpublished when you confirm. ## Next steps * [Issues & Governance](/api-client/api-design/issues-and-governance) to clear the errors that block a release. * [Sync a collection from a specification](/api-client/api-design/sync-a-collection-from-a-specification), the other action the same errors block. * [Publish API documentation](/api-client/api-design/publish-api-docs) to put a released version on a shareable URL. * [Create and edit a specification](/api-client/api-design/create-and-edit-a-specification) to change `info.version` and save before releasing again. # CLI Source: https://docs.requestly.com/api-client/cli Run HTTP and GraphQL collections from the command line using the Requestly CLI binary. The Requestly CLI lets you run collections, inspect environments, and list projects directly from your terminal or CI pipeline - no browser or desktop app required. > [!NOTE] > > You don't have to hand-write the pipeline file. [Run on CI/CD](/api-client/run-on-cicd) generates a complete GitHub Actions, GitLab CI, Jenkins, or Azure Pipelines file from the collections you pick in the app. ## Installation Download the binary for your platform, unzip it, and run it directly. The binary is self-contained with no additional dependencies. | Platform | Download | | - | - | | Linux x64 | [binary-linux-x64-1.61.1.zip](https://sdk-assets.browserstack.com/binary-linux-x64-1.61.1.zip) | | Linux arm64 | [binary-linux-arm64-1.61.1.zip](https://sdk-assets.browserstack.com/binary-linux-arm64-1.61.1.zip) | | macOS x64 | [binary-macos-x64-1.61.1.zip](https://sdk-assets.browserstack.com/binary-macos-x64-1.61.1.zip) | | macOS arm64 | [binary-macos-arm64-1.61.1.zip](https://sdk-assets.browserstack.com/binary-macos-arm64-1.61.1.zip) | | Windows x64 | [binary-win-x64-1.61.1.zip](https://sdk-assets.browserstack.com/binary-win-x64-1.61.1.zip) | After downloading, unzip and make the binary executable. This example is for macOS arm64: ```bash theme={null} unzip binary-macos-arm64-1.61.1.zip mv binary-macos-arm64 browserstack-binary chmod +x browserstack-binary ``` The file inside the archive does not always match the download name, so check the table below before you copy the `mv` line. On Linux in particular the archive is named `linux` but the file inside is named `linuxstatic`: | Platform | You download | The archive contains | | - | - | - | | Linux x64 | `binary-linux-x64-1.61.1.zip` | `binary-linuxstatic-x64` | | Linux arm64 | `binary-linux-arm64-1.61.1.zip` | `binary-linuxstatic-arm64` | | macOS x64 | `binary-macos-x64-1.61.1.zip` | `binary-macos-x64` | | macOS arm64 | `binary-macos-arm64-1.61.1.zip` | `binary-macos-arm64` | | Windows x64 | `binary-win-x64-1.61.1.zip` | `binary-win-x64.exe` | To run it as `browserstack-binary` from any directory, move it onto your `PATH`. On macOS and Linux: ```bash theme={null} sudo mv browserstack-binary /usr/local/bin/ ``` On Windows, move `browserstack-binary.exe` into a folder that is on your `Path` (or add its folder to the `Path` environment variable via System Properties → Environment Variables). > [!NOTE] > > Some operating systems block execution of binaries downloaded from the internet by default. Run `chmod +x browserstack-binary` if you see a permission error. > > All examples in this guide assume the binary is on your `PATH`. If you skip the step above, run it with a path prefix (`./browserstack-binary`) from the folder where it lives. All examples in this guide use `browserstack-binary` as the executable name. Rename the file you extracted to match, using the table above to find its real name. ## Invocation ```text theme={null} browserstack-binary requestly [subcommand] [target] [flags] ``` ## Authentication Cloud operations - fetching a collection by cloud ID, listing cloud projects, collections, and environments - require BrowserStack credentials set as environment variables: | Variable | Description | | - | - | | `BROWSERSTACK_USERNAME` | Your BrowserStack username | | `BROWSERSTACK_ACCESS_KEY` | Your BrowserStack access key | Both must be set together. Local filesystem runs, Postman JSON files, and URL-fetch targets do not require credentials. ```bash theme={null} export BROWSERSTACK_USERNAME=your_username export BROWSERSTACK_ACCESS_KEY=your_access_key browserstack-binary requestly collection run --project ``` To find your username and access key, open your [BrowserStack account profile](https://www.browserstack.com/accounts/profile/details). ## Commands ### `collection run` Run a collection or request. The target type is auto-detected - no explicit type flag needed. ```text theme={null} browserstack-binary requestly collection run [flags] ``` #### Target detection The CLI resolves the target in this order: | Target | Detected as | | - | - | | Starts with `http://` or `https://` | URL fetch - downloads JSON and runs it. Must be a valid Postman v2.1 or Requestly collection. | | Directory containing `__requestly.json` | Requestly local project - runs all collections under `apis/`. | | Directory containing `__metadata.json` with `"type": "collection"` | Specific Requestly collection - runs only that collection. | | `.json` file with Postman v2.1 schema (`info._postman_id` or `info.schema` containing `v2.1`) | Postman v2.1 collection file. | | Cloud collection ID (e.g. `abc123-def456`) | Fetches the collection from Requestly cloud. Requires `--project ` plus `BROWSERSTACK_USERNAME` + `BROWSERSTACK_ACCESS_KEY`. | If the target cannot be resolved, the CLI exits with code `1` and a descriptive error message. #### Execution flags | Flag | Short | Default | Description | | - | - | - | - | | `--project ` | | | Cloud project ID. Required for cloud collection-ID targets. Not used for local/file/URL targets. | | `--environment ` | `-e` | | Environment to activate. Accepts: environment name (resolved from a Requestly project's `environments/` directory), file path to a standalone environment JSON, or a cloud environment ID. | | `--env-var ` | | | Override an environment variable. Repeatable. | | `--global-var ` | | | Override a global variable. Repeatable. | | `--iteration-data ` | `-d` | | CSV or JSON data file for data-driven runs. The collection runs once per row (CSV) or object (JSON). | | `--iteration-count ` | `-n` | `1` | Number of times to run the collection. With `-d`, multiplies iterations: total = N x rows. | | `--delay-request ` | | `0` | Pause between consecutive requests (milliseconds). | | `--on-error ` | | `continue` | Behavior on assertion failure. `end`: stop on first failure. `continue`: run to completion, exit `1` if any failed. `ignore`: run to completion, assertion failures do not affect exit code. Request, script and run-level errors still exit `1`. | | `--bail` | | | Shortcut for `--on-error end`. When used with `-d` or `-n`, stops the entire run (all remaining iterations), not just the current one. | | `--timeout-request ` | | `0` | Per-request timeout. `0` = no limit. | | `--script-execution-mode ` | | `safe` | Sandbox engine for scripts. `safe`: an isolated sandbox with no filesystem, process or native-module access. `developer`: full machine access, for collections you trust only. `developer` requires credentials and your organization's permission - see [Script execution mode and your organization's policy](#script-execution-mode-and-your-organizations-policy). | | `--folder ` | | | Run only the named folder within a Postman v2.1 collection. Repeatable. Postman targets only. | | `--insecure` | `-k` | | Disable TLS certificate validation. | | `--verbose` | | | Log detailed request/response info (method, URL, status, headers, timing) for each request. | #### Script execution mode and your organization's policy `--script-execution-mode developer` runs your scripts with full access to the machine, so the CLI checks who you are and what your organization allows before it starts the run. Nothing else about the run changes. A run that passes no mode flag, or passes `--script-execution-mode safe`, runs in Safe mode. It needs no credentials, makes no policy check, and behaves exactly as before. Requesting `developer` is refused, with exit code `1` and a reason on stderr, in three cases: | Refusal | What to do | | - | - | | No credentials are set | Set `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY`, or drop the flag to run in Safe mode. | | Your organization requires Safe mode | Ask an organization Owner or Admin to change the **Script mode** resource, or drop the flag. | | The policy could not be read | Check your credentials and connectivity. The CLI refuses rather than assuming Developer mode is permitted. | > [!NOTE] > > Credentials are required to request Developer mode even when your organization has set no policy at all. A > refused escalation never silently downgrades the run to Safe mode. See [Organization resources](/account/organization-resources) for the policy itself. #### Reporter flags | Flag | Short | Default | Description | | - | - | - | - | | `--reporters ` | `-r` | `cli` | Comma-separated reporters to activate: `cli`, `json`, `junit`, `html`, `tra`. All listed reporters run simultaneously. See [Report to Test Reporting and Analytics](#report-to-test-reporting-and-analytics) for `tra`. | | `--reporter-json-export ` | | `./rq-reports/rq-report.json` | Output path for the JSON report (Newman-compatible schema). | | `--reporter-junit-export ` | | `./rq-reports/rq-report.xml` | Output path for JUnit XML. Compatible with GitHub Actions, GitLab CI, Jenkins, CircleCI, and Bamboo. [Run on CI/CD](/api-client/run-on-cicd) wires this up for you on the first four. | | `--reporter-html-export ` | | `./rq-reports/rq-report.html` | Output path for a self-contained HTML report. | | `--reporter-omit-request-bodies` | | | Remove request bodies from all reporter output. | | `--reporter-omit-response-bodies` | | | Remove response bodies from all reporter output. | | `--reporter-omit-headers` | | | Remove all headers from all reporter output. | | `--reporter-skip-headers ` | | | Remove specific headers by name (comma-separated). | | `--reporter-omit-all` | | | Omit all request bodies, response bodies, and headers. Equivalent to combining the three `--reporter-omit-*` flags. | > [!NOTE] > > Missing export directories are created automatically. If a directory cannot be created, the CLI exits `1` after the run completes - tests still execute. `--reporter-omit-*` flags affect the JSON and HTML reporters regardless of `--verbose`. In terminal output, they suppress the additional headers/bodies that `--verbose` would otherwise show. #### Report to Test Reporting and Analytics The `tra` reporter uploads your run results to BrowserStack Test Reporting & Analytics, so CI runs show up alongside your other BrowserStack test reports instead of only in the pipeline log. It is opt-in. Add `tra` to `--reporters`: ```bash theme={null} export BROWSERSTACK_USERNAME=your_username export BROWSERSTACK_ACCESS_KEY=your_access_key browserstack-binary requestly collection run ./my-project/ -r cli,tra ``` How it behaves: | Behavior | Detail | | - | - | | Credentials | Requires `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY`. If either is missing, the reporter is skipped, a note is printed, and the rest of the run is unaffected. | | When results upload | Once, after the run finishes. Results are not sent per request while the run is in progress. | | What you get | One build per `collection run` invocation. Each [`rq.test()`](/api-client/rq-api-reference/rq-test) assertion becomes one test case in that build. On success the build URL is printed so you can open it. | | Combining reporters | Composable with every other reporter, for example `-r cli,junit,tra`. | | Upload failures | Printed as a warning. They never change the exit code, so a reporting outage cannot fail your pipeline. | | No export path | There is no `--reporter-tra-export` flag. The `tra` reporter uploads instead of writing a file. | > [!NOTE] > > `tra` can only be enabled with the `--reporters` flag. Listing it in a [`.requestlyrc`](#configuration-file) file has no effect, because the reporter resolves your credentials at run time rather than from the config file. #### Global flags | Flag | Short | Description | | - | - | - | | `--color ` | | ANSI color output. Default: `auto` (detects TTY). | | `--help` | `-h` | Show help. | | `--version` | `-v` | Print CLI version and exit. | #### Exit codes | Code | Meaning | | - | - | | `0` | No request, script or run-level error occurred, and all assertions passed (or `--on-error ignore` was set, which suppresses assertion failures only). Includes an empty collection with zero requests. An HTTP 4xx/5xx response on its own is not a failure - it only fails the run if an [`rq.test()`](/api-client/rq-api-reference/rq-test) assertion checks for it. | | `1` | Any of: assertion failures; a request could not be prepared (variable or auth resolution) or failed to send (connection refused, DNS, TLS, proxy); a pre-request or test script threw; a run-level error (`setNextRequest` named a request that doesn't exist, or the execution-loop limit was hit); target not found or unreadable; invalid or unrecognized JSON; URL/cloud fetch failed; missing credentials for a cloud target; a refused `--script-execution-mode developer` request; reporter export write failed. | | `2` | Fatal/uncaught error (e.g. process crash). | *** ### `project list` List all projects the authenticated user is a member of. ```text theme={null} browserstack-binary requestly project list [--output ] ``` | Flag | Default | Description | | - | - | - | | `--output ` | `table` | Output format. `json` is suitable for piping. | Requires `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY`. *** ### `collection list` List collections in a project. ```text theme={null} browserstack-binary requestly collection list --project [--output ] ``` | Flag | Default | Description | | - | - | - | | `--project ` | | **(Required)** Project ID. | | `--output
` | `table` | Output format. | Requires `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY`. *** ### `environment list` List environments in a project (cloud or local). ```text theme={null} browserstack-binary requestly environment list --project [--output ] browserstack-binary requestly environment list [--output ] ``` | Flag | Default | Description | | - | - | - | | `--project ` | | Cloud project ID. Required when targeting a cloud project. | | `--output
` | `table` | Output format. | Pass a local project path as the positional argument to list environments from the filesystem without credentials. *** ### `environment view` Show variable details for a specific environment. ```text theme={null} browserstack-binary requestly environment view --project [--output ] browserstack-binary requestly environment view [--output ] ``` | Flag | Default | Description | | - | - | - | | `--project ` | | Cloud project ID. Required when identifying the environment by cloud ID. | | `--output
` | `table` | Output format. | Pass a local environment file path as the positional argument to inspect it without credentials. *** ## Configuration file Instead of repeating the same flags on every run, commit a `.requestlyrc` file next to your collection. `collection run` picks it up automatically, so your team and your CI pipeline share one set of defaults. Place the file in your target's directory: the directory you pass to `collection run`, or, if you pass a collection file, the directory that file lives in. Two filenames are supported: | Filename | Format | | - | - | | `.requestlyrc` | YAML | | `.requestlyrc.json` | JSON | If both exist, `.requestlyrc` wins. ```yaml .requestlyrc theme={null} environment: staging iteration-count: 3 delay-request: 250 on-error: end reporters: - kind: cli - kind: junit export: ./test-results/junit.xml privacy: omit-response-bodies: true skip-headers: - authorization - cookie ``` ### Supported keys | Key | Type | Description | | - | - | - | | `environment` | string | Environment to activate. Same values as `--environment`. | | `iteration-count` | integer | Times to run the collection. Must be greater than `0`. | | `delay-request` | integer | Pause between requests, in milliseconds. | | `timeout-request` | integer | Per-request timeout, in milliseconds. `0` means no limit. | | `timeout-script` | integer | Script timeout, in milliseconds. | | `on-error` | `end`, `continue`, or `ignore` | Behavior on assertion failure. | | `bail` | boolean | Shortcut for `on-error: end`. | | `insecure` | boolean | Disable TLS certificate validation. | | `reporters` | array | Reporters to activate. Each entry needs a `kind` of `cli`, `json`, `junit`, or `html`. The file-producing kinds (`json`, `junit`, `html`) also need a non-empty `export` path. | | `privacy` | object | Any of `omit-all`, `omit-request-bodies`, `omit-response-bodies`, `omit-headers` (booleans), and `skip-headers` (list of header names). | Numeric values must be whole numbers and cannot be negative. A relative `export` path is resolved from the directory you run the command in, not from the directory holding the `.requestlyrc`. In CI, where those are usually the same directory, this makes no difference. ### Which value wins When the same setting is specified in more than one place, the CLI uses the first one it finds: 1. The flag you passed on the command line. 2. Your `.requestlyrc` file. 3. A run configuration saved with the collection (iteration count and delay only). 4. The built-in default. So a `.requestlyrc` sets your team's baseline, and any flag you pass overrides it for that one run. > [!NOTE] > > The `tra` reporter is the one setting a `.requestlyrc` cannot turn on. A `kind: tra` entry is dropped without a warning, because it is a valid reporter name, so pass `-r tra` on the command line instead. ### If the file has a problem * An **unknown top-level key** prints a warning naming the key, and the run continues. This is usually a typo. * A **malformed file** (invalid YAML or JSON) stops the run and exits `1` before any request is sent. * An **individual value of the wrong type** is ignored, and the CLI falls back to the flag, saved config, or default for that setting. *** ## Telemetry When the CLI fails unexpectedly, it can send a crash report to Requestly so we can find and fix the problem. It sends nothing when a run completes, whether your tests pass or fail, and nothing when you mistype a command. A crash report contains: * The error type, message, and stack trace * The CLI version * Your operating system and Node.js version A report is built only from the error itself, the CLI version, and your operating system and Node.js version. The CLI never adds your requests or responses, your collections, environment variables, credentials, or your machine's name to it. The error message can still quote whatever the failing code put in it, such as a URL or a file path, so before a report is sent, the values in URL query strings, recognizable secrets such as API keys and tokens, email addresses, card numbers, and phone numbers are redacted, and paths under your home directory are shortened to ``. To turn crash reports off, set any of these environment variables to `1` or `true`: | Variable | Notes | | - | - | | `RQ_TELEMETRY_DISABLED` | Requestly's own switch | | `BROWSERSTACK_TELEMETRY_DISABLED` | Same effect, BrowserStack naming | | `DO_NOT_TRACK` | The cross-tool convention many CLIs honor | ```bash theme={null} export RQ_TELEMETRY_DISABLED=1 ``` *** ## Terminal output The default `cli` reporter streams results in real time. Each request prints as it completes: ```text theme={null} Requestly - Running your collection... → Auth Types Demo API Keys GET https://httpbin.org/headers [200 OK, 342ms] ✓ Status is 200 → Basic Authentication GET https://httpbin.org/basic-auth/demo_user/demo_pass [200 OK, 215ms] ✓ Basic auth successful ✕ Response contains token expected response body to contain 'token' ┌─────────────────────────────┬─────────────────────┬─────────────────────┐ │ │ executed │ failed │ ├─────────────────────────────┼─────────────────────┼─────────────────────┤ │ iterations │ 1 │ 0 │ ├─────────────────────────────┼─────────────────────┼─────────────────────┤ │ requests │ 2 │ 0 │ ├─────────────────────────────┼─────────────────────┼─────────────────────┤ │ test-scripts │ 2 │ 0 │ ├─────────────────────────────┼─────────────────────┼─────────────────────┤ │ prerequest-scripts │ 0 │ 0 │ ├─────────────────────────────┼─────────────────────┼─────────────────────┤ │ assertions │ 3 │ 1 │ ├─────────────────────────────────────────────────────────────────────────┤ │ total run duration: 0.6s │ ├─────────────────────────────────────────────────────────────────────────┤ │ total data received: 4.2kB (approx) │ ├─────────────────────────────────────────────────────────────────────────┤ │ average response time: 278ms [min: 215ms, max: 342ms, s.d.: 63ms] │ └─────────────────────────────────────────────────────────────────────────┘ ``` `console.log()` output from scripts appears between the request line and assertions, wrapped in dash-pipe delimiters: ```text theme={null} - | Total posts: 100 | Response time: 622ms - ``` *** ## Examples **Run a local Requestly project:** ```bash theme={null} browserstack-binary requestly collection run ./my-project/ ``` **Run a specific collection within a project:** ```bash theme={null} browserstack-binary requestly collection run ./my-project/apis/Auth-Types-Demo/ ``` **Run a Postman v2.1 file with JUnit output:** ```bash theme={null} browserstack-binary requestly collection run ./postman-collection.json \ -r cli,junit \ --reporter-junit-export results.xml ``` **Run a specific folder from a Postman collection:** ```bash theme={null} browserstack-binary requestly collection run ./postman-collection.json \ --folder "Posts API" \ --folder "Auth Tests" ``` **Run a collection from a URL:** ```bash theme={null} browserstack-binary requestly collection run https://example.com/collection.json ``` **Run a cloud collection with an environment:** ```bash theme={null} browserstack-binary requestly collection run abc123-def456 --project -e production ``` **Data-driven run (3 repetitions of a CSV file):** ```bash theme={null} browserstack-binary requestly collection run ./my-project/ -d test-data.csv -n 3 ``` **Bail on first failure with variable overrides:** ```bash theme={null} browserstack-binary requestly collection run ./my-project/ \ --bail \ --env-var host=localhost \ --env-var port=8080 ``` **All four reporters with sensitive headers stripped:** ```bash theme={null} browserstack-binary requestly collection run ./my-project/ \ -r cli,json,junit,html \ --reporter-json-export reports/run.json \ --reporter-junit-export reports/junit.xml \ --reporter-html-export reports/report.html \ --reporter-skip-headers Authorization,X-Api-Key ``` **CI pipeline (JUnit output, fail fast, credentials from env).** For a full pipeline file rather than a single command, use [Run on CI/CD](/api-client/run-on-cicd): ```bash theme={null} BROWSERSTACK_USERNAME=$BS_USER \ BROWSERSTACK_ACCESS_KEY=$BS_KEY \ browserstack-binary requestly collection run --project \ --bail \ -r cli,junit \ --reporter-junit-export test-results/junit.xml ``` **List projects:** ```bash theme={null} browserstack-binary requestly project list browserstack-binary requestly project list --output json ``` **List collections in a project:** ```bash theme={null} browserstack-binary requestly collection list --project proj-abc123 browserstack-binary requestly collection list --project proj-abc123 --output json ``` **View an environment:** ```bash theme={null} browserstack-binary requestly environment view env-xyz789 --project proj-abc123 browserstack-binary requestly environment view ./my-project/environments/staging.json ``` # Collection Runner Source: https://docs.requestly.com/api-client/collection-runner Learn how to run collections, configure iterations, delays, and environments, reorder or skip requests, view and debug results, and export run summaries **Collection Runner** enables you to execute multiple saved API requests from a collection in one go, sequentially, while leveraging existing variable and scripting features. Think of it as automating a workflow of requests\ (for example: login → create resource → fetch resource) in one run. [YouTube video player](https://www.youtube.com/embed/RtYCIBJPtR0) This documentation covers how to run collections, configure variables, view results, rerun or debug, explore automation options, and export results. ### Running a Collection Follow these steps to run a collection using the Runner: **1. Open Collection Runner** In the Collections sidebar, find the collection you want to execute and click the **Run** icon on menu option next to it. ![Requestly Collection Runner showing how to open and run an API collection from the Collections sidebar or Runner tab.](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-runner/304ede81-76f5-4099-a9d1-27f2a746a432.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=7fedb2a249c17e4e8a01328205367971) *You can also click* ***Runner*** *from collections tab* **2. Configure Options** * **Iterations:** Number of times to execute the full collection * **Delay:** Wait time between requests (milliseconds) ![Requestly Collection Runner settings panel showing configuration options for iterations, delay, and environment selection before running API tests.](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-runner/63aa0b0c-72a3-4a5c-b052-eb2efc6e1472.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=2a85c8cdf1715546a490fe71aedef71a) If you want your collection to run with an environment, select it using the environment selector at the upper left corner, then select the environment you want to use **3. Adjust Request Order or Skip** You can drag to reorder requests or uncheck ones you don’t want to include in this run. ![Requestly Collection Runner interface showing how to reorder or skip specific API requests before executing a test collection.](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-runner/8652b545-82d1-4243-8a1c-5f77292f2806.gif?s=2c3f81ec3cb79bef133fc9c19f240ab3) **4. Start the Run** Click Save and then Run . The Runner will execute each request in order. ![Screenshot of the Requestly Collection Runner showing the Save and Run buttons used to start executing API collections automatically.](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-runner/04897888-950c-4e63-bc87-902aeeec46f9.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=0cb94ff04c615c6a9a193c7f60edf9e2) ### How a Collection Runner Works ![Diagram explaining how Requestly Collection Runner executes API requests, resolves variables, and runs pre-request and test scripts.](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-runner/2cc6558c-8b47-4407-811b-94676c887f91.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=242eea11f1c8124584424333c37a7352) When you execute requests using the **Collection Runner**, here’s how things work: #### Variable Resolution * All `{{variable}}` placeholders resolve based on their **scope**. * **Environment variables** override values from the global scope. * **Collection-level variables** defined earlier are available to all requests within that collection. #### Script Execution * **Pre-request** and **Post-response** scripts execute as usual. * You can **set or modify variables** dynamically during the run. * Use `rq.expect(...)` for writing **test assertions** to validate responses. #### Viewing Run Results ![Requestly Collection Runner Run Summary showing test results, request details, response data, and execution duration.](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-runner/6567c990-ab2d-407d-b452-62fa4b2e500d.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=b82306d8712d991605c6fb44ee6604af) Once the run completes, the Runner displays a detailed **Run Summary**, including: * Total number of requests executed * Tests passed and failed * Total duration and time taken You can click on any request in the summary to view: * Request details - URL, headers, and body * Response data - status, headers, and body * The result of each test assertion ## What's Next? > **[Run with Data Files](/api-client/collection-runner-data-file)** > > Use CSV or JSON data files to parameterize collection runs across multiple inputs. > **[Schedule Runs](/api-client/scheduled-runs)** > > Run a collection automatically on a recurring schedule from the Runner tab's Scheduled sub-tab. > **[Write Tests](/api-client/tests)** > > Add assertions to validate response status, body, and headers on every run. > **[Use Variables](/api-client/environments-and-variables)** > > Set and modify variables dynamically during a run using pre/post scripts. > **[Run on CI/CD](/api-client/run-on-cicd)** > > Generate a GitHub Actions, GitLab CI, Jenkins, or Azure Pipelines file from the Runner's Run in CLI sub-tab. # Run Collections with Custom Data Source: https://docs.requestly.com/api-client/collection-runner-data-file Learn how to use CSV or JSON data files with the Requestly Collection Runner to iterate requests with multiple input values. You can use **custom data files** (CSV or JSON) when running a collection manually in Requestly.\ This enables you to iterate through your requests using multiple sets of input values, without modifying your request parameters each time. > [!NOTE] > > **Note:** This feature is currently available only on the [Requestly Desktop App](https://requestly.com/downloads/desktop/). Use this feature to test APIs with dynamic inputs, such as running the same workflow for multiple users, IDs, or configurations. [https://www.youtube.com/embed/j-oh6pe51Vw?si=RUH0MpYQ3bdTdgJd](https://www.youtube.com/embed/j-oh6pe51Vw?si=RUH0MpYQ3bdTdgJd) ### Using a Data File in Collection Runner Follow these steps to run a collection with custom data: **1. Open Collection Runner** In the Collections sidebar, find the collection you want to execute and click the **Run** icon next to it. ![Requestly Collection Runner interface showing how to open and run an API collection from the Collections sidebar or Runner tab.](https://mintcdn.com/requestly/Ann0jEECfxHAT9FZ/images/DataFileSupportincollectionRunner\(runcollection\).png?fit=max\&auto=format\&n=Ann0jEECfxHAT9FZ\&q=85\&s=97f338c499c852e6a56a995da1655997) **2. Select a Data File** In the Runner configuration panel, click **Select Data File**. > [!NOTE] > > Supports JSON & CSV files (max 100MB) ![Runner configuration panel in Requestly showing the Select Data File option to upload a CSV or JSON file for data-driven API testing.](https://mintcdn.com/requestly/Ann0jEECfxHAT9FZ/images/DataFilesupportinCollectionRunner\(addfile\).png?fit=max\&auto=format\&n=Ann0jEECfxHAT9FZ\&q=85\&s=f51aee821fd18041ed97d202688af600) Once added, Requestly will automatically detect the file type and preview its structure. **3. Preview Data and Map Variables** After selecting the file, a **preview** of your data will appear. * For CSV files: verify column names and types * For JSON files: check object keys and structure Each key or column name should match the variable used in your requests, such as `{{storyId}}`. ![Requestly data preview screen displaying CSV and JSON structures, allowing users to verify columns, keys, and map variables like city or user\_id.](https://mintcdn.com/requestly/Ann0jEECfxHAT9FZ/images/DatafilesupportforCollectionRunner\(preview\).png?fit=max\&auto=format\&n=Ann0jEECfxHAT9FZ\&q=85\&s=859991a0ec9d91ef9c67ad00d664dc5b) **4. Start the Run** Click **Save** and then **Start Run**.\ The Collection Runner will replace variables with data from your file for each iteration. ![Requestly Collection Runner executing an API collection with data variables replaced from the selected CSV or JSON file.](https://mintcdn.com/requestly/Ann0jEECfxHAT9FZ/images/DataSupportinCollectionRunner\(save\&run\).png?fit=max\&auto=format\&n=Ann0jEECfxHAT9FZ\&q=85\&s=3ca18e5c047ee425c1fb561776c0aa35) ### How Data Files Work When you attach a CSV or JSON file to your manual run: * Each **row (CSV)** or **object (JSON)** represents one **iteration** * Variables inside your requests (like `{{storyId}}`) will be replaced with the corresponding values * Requestly automatically cycles through each data set until all iterations are complete ### Supported File Formats #### CSV Format * The first row defines variable names * Each subsequent row represents one iteration * Each row must have the same number of columns **Example:** ```bash theme={null} city,temperature Vancouver,10 Austin,24 London,12 ``` #### JSON Format * Must be an array of key-value objects * Each object defines one iteration **Example:** ```json theme={null} [ { "city": "Vancouver", "temperature": 10 }, { "city": "Austin", "temperature": 24 }, { "city": "London", "temperature": 12 } ] ``` ### Example Use Case For a request like ```bash theme={null} GET https://api.example.com/weather?city={{city}} ``` and a data file containing ```bash theme={null} city Vancouver Austin London ``` Requestly will automatically replace `{{city}}` with each value during the run. ### Accessing Data in Scripts You can access data file values programmatically in your pre-request and post-response scripts using the `rq.iterationData` object. This allows you to implement conditional logic, validate responses, or perform calculations based on the input data. **Example:** ```javascript theme={null} // Pre-request script const city = rq.iterationData.get("city"); console.log(`Testing weather API for: ${city}`); // Post-response script const expectedCity = rq.iterationData.get("city"); const responseData = rq.response.json(); rq.test("Response contains correct city", function() { rq.expect(responseData.city).to.equal(expectedCity); }); ``` # DevTools Source: https://docs.requestly.com/api-client/devtools Inspect script logs, network activity, and cookies from your API requests in a single panel inside the Requestly API Client. DevTools is Requestly's built-in debugger for API requests. It captures console output from your pre and post-request scripts, every outgoing request and its matching response, and the cookies attached to each call. Use it the same way you would use the browser's DevTools, but for the requests you fire from inside Requestly. > [!NOTE] > > **Cookies availability:** Cookie capture in DevTools depends on the cookie jar, a desktop-app feature that is rolling out gradually. If the cookie jar is not enabled for your build, the **Cookies** panel and the per-request Cookies tab do not appear. See [Cookies](/api-client/send-api-request/cookies). ## Open DevTools There are two ways to open DevTools, depending on whether you want to see activity across the whole app or scope it to a single request. ![DevTools panel showing Console and Network tabs at the bottom of the API Client window.](https://mintcdn.com/requestly/vZ8XpJL0wBaPmeVz/images/devtools-panel-overview.light.png?fit=max\&auto=format\&n=vZ8XpJL0wBaPmeVz\&q=85\&s=1fcaf8a690dc6b0440e9c383ad8fd1ec) DevTools panel docked to the bottom of the API Client **Global DevTools** Click the **DevTools** button in the application footer at the bottom of the window. The panel docks to the bottom of the workspace and shows everything that has happened in the current session: every script log, every network request, and every cookie set or sent. Click the **X** in the top-right of the panel to close it. Use this when you want a session-wide view, for example to compare two recent requests or scan logs from a script that ran across several calls. **Per-request Debug tab** Open any HTTP request and send it. In the response area you will see a **Debug** tab next to **Body**, **Headers**, and **Test Results**. The Debug tab shows DevTools scoped to that one request's most recent execution. Use this when you want to inspect what a single request did without scrolling through unrelated activity. It is the fastest path from "this request misbehaved" to "here is the log line that explains why." ## Console tab The Console shows log output produced while a request runs. That includes anything you wrote with `console.log()` or `console.error()` in a pre or post-request script, plus system events Requestly emits (for example, when a script throws an error). ![DevTools Console tab listing script logs with level and source filter dropdowns.](https://mintcdn.com/requestly/vZ8XpJL0wBaPmeVz/images/devtools-console-tab.light.png?fit=max\&auto=format\&n=vZ8XpJL0wBaPmeVz\&q=85\&s=1b5a9ea28ef77806789057c874235eb4) Console tab with log level and source filters The toolbar at the top of the panel gives you four controls: * **Search**. Filters the visible log lines by substring match. Useful when you want to find a specific value you logged. * **Level filter**. Toggle **Info**, **Warnings**, and **Errors**. By default all three are on. Turn off a level to hide those entries. * **Source filter**. Toggle between **Users** (logs your scripts produced), **System** (errors and lifecycle events from Requestly itself), and **Network requests** (one-line summaries of each request the runtime made). All three are on by default. * **Clear**. Empties the panel. Note that clear wipes both the Console and Network tabs at once, since they share a single store. > [!TIP] > > Logs from your pre and post-request scripts are tagged so you can find them quickly. Type `#script` into the search box to show only your own log output and hide everything else. ## Network tab The Network tab lists every request the runtime sent on your behalf, including requests fired by `rq.sendRequest` from inside scripts and requests made by the collection runner. Each row shows the method, status code, URL, timestamp, response time, and response size. ![DevTools Network tab listing captured requests with the detail tabs open on the right.](https://mintcdn.com/requestly/vZ8XpJL0wBaPmeVz/images/devtools-network-tab.light.png?fit=max\&auto=format\&n=vZ8XpJL0wBaPmeVz\&q=85\&s=344088f7a0663cf73bb6aa3e54237561) Network tab with the request list and detail view ### Filter the request list The toolbar at the top of the panel offers three filters: * **Search**. Matches against the URL, so you can locate a specific endpoint without scrolling. * **Status**. Multi-select: **2xx Success**, **3xx Redirect**, **4xx Client Error**, **5xx Server Error**, and **No status (failed)**. The last option captures requests that never received a response, for example because of a network error or DNS failure. * **Method**. Multi-select: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD. Filters combine with AND. A request shows up only if it matches the search text AND the active status set AND the active method set. ### Inspect a single request Click any row in the list to open a side panel with detail tabs: * **Headers**. Request and response headers, side by side. * **Payload**. Query string, path parameters, and request body. Multipart and form-encoded bodies are decoded so you can read each field. * **Response**. The response body rendered in the response viewer. JSON and XML are pretty-printed and syntax-highlighted, with collapsible sections. Image responses render as the actual picture, and other binary responses show a **Binary response** placeholder with the response size instead of unreadable characters. * **Info**. TLS handshake details for HTTPS requests: the TLS version and cipher suite, the server certificate (subject, issuer, and expiry), and the client certificate that was sent, if any. This tab only appears for HTTPS requests. See [SSL Certificates](/api-client/send-api-request/ssl-certificates) for how to configure custom CA and client certificates. * **Cookies**. The cookies attached to the request and any cookies set by the response. Only appears when at least one cookie is involved. See [Cookies](/api-client/send-api-request/cookies) for how the cookie jar works end-to-end. * **Variables**. Every variable that was referenced anywhere in the request, with the scope it resolved from (environment, collection, runtime, or global) and the value it resolved to. > [!TIP] > > Headers and Payload have a **Show resolved values** toggle in the top-right. With it off, you see your request as you wrote it, including `{{variable}}` placeholders. With it on, you see the exact bytes that went over the wire after every variable was substituted. Flip the toggle when a request is failing and you suspect a variable resolved to the wrong value. ## Retention DevTools keeps the most recent activity in memory and drops older entries once the panel fills up. The defaults are tuned to hold a long debugging session without slowing the app down: * Up to **25,000** console log lines. * Up to **10,000** network requests. * Up to **5,000** system events and **5,000** cookies. Once a category is full, the oldest entries fall off as new ones come in. Activity is cleared when you reload the app, so if you want to keep a log around, copy it before closing. ## What's Next? > **[Pre & Post Scripts](/api-client/scripts)** > > Write JavaScript that runs around your requests and shows up in the Console > **[Tests](/api-client/tests)** > > Assert on response data and watch the results in the Test Results tab > **[Cookies](/api-client/send-api-request/cookies)** > > Manage the cookie jar that DevTools observes on every request # Variables and Environment Source: https://docs.requestly.com/api-client/environments-and-variables Learn how to use variables and environments in Requestly to manage dynamic values like API keys, base URLs, and tokens across your API requests. Variables in Requestly’s API Client let you store and reuse dynamic values, like API keys, base URLs, and user IDs, across your API requests. They help you avoid hardcoding, make your collections more modular, and simplify switching between different environments like development, staging, and production. A **variable** is a named placeholder you define once and reference anywhere in your API collections using the `{{variable_name}}` syntax. When you run a request, Requestly replaces each `{{variable}}` with its actual value based on its scope. Example: `https://{{base_url}}/users/{{user_id}}` If you've defined `base_url = api.example.com` and `user_id = 123`, the request resolves to - `https://api.example.com/users/123` > [!TIP] > > +TIP: Hover over any `{{variable}}` in your request to preview its resolved value instantly. ### Explore Variable Types and Features [Global Variables](/api-client/environments-and-variables/global-variables) Use values that apply across all requests and collections. [Environment Variables](/api-client/environments-and-variables/environment-variables) Define values based on your working environment (e.g., dev, staging, prod). [Runtime Variables](/api-client/environments-and-variables/runtime-variables) Temporary values that last only for the current session, ideal for tokens or session IDs. They aren’t synced and can auto-clear after use. [Collection & SubCollection Variables](/api-client/environments-and-variables/collection-and-subcollection-variables) Scope variables to specific collections or groups of requests. [Variable Precedence](/api-client/environments-and-variables/variable-precedence) Understand how Requestly resolves variable conflicts when the same name exists in multiple scopes. [Using Variables in API Requests](/api-client/environments-and-variables/using-variables-in-api-requests) Learn where and how to use variables in your API request URLs, headers, bodies, and scripts. [Set a Response Value as a Variable](/api-client/environments-and-variables/set-response-value-as-variable) Capture a value out of a response body into a variable by right-clicking the selection, with no script to write. # Collection & SubCollection Variables Source: https://docs.requestly.com/api-client/environments-and-variables/collection-and-subcollection-variables **Collection** and **SubCollection Variables** in Requestly let you define scoped values that are only available within a specific collection or a nested sub-group of requests. These variables are ideal when you want to manage shared data for a group of related requests, without affecting global or environment-level variables. They help you build modular, reusable collections and make it easy to organize values related to a particular service, API module, or test scenario. If both a collection and subcollection define a variable with the same name, **SubCollection variables take precedence** during execution. > [!NOTE] > > That precedence applies to **reading** a variable. A script that *writes* one with `rq.collectionVariables.set()` targets the **root collection** by default, so the value is visible to every request in the collection, including requests in other sub-collections. Pass `{ level: "current" }` to write to the sub-collection instead. See [rq.collectionVariables](/api-client/rq-api-reference/rq-collection-variables#which-collection-a-script-writes-to). [https://www.youtube.com/embed/F\_rmwdHhPwE](https://www.youtube.com/embed/F_rmwdHhPwE) ## **How to Create Collection Variables** ### **Step 1: Access the Collections Tab** > [!TIP] > > **Sub-collection** variables can be created and take precedence over their parent collection variables. If a variable in the sub-collection shares the same key as one in the parent collection, the sub-collection variable will be used during request execution. Click on the **Collection Name** to open **Collection Overview** and switch to **Variables** tab. ![](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-and-subcollection-variables/f0951c1a-0475-485e-8b5b-1e7652a3cbde.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=cc8bd1e0b45260c5c146d7bbcfa1fbae) ### **Step 2: Add Variables** Add variables in the table by specifying the following details: * **Key:** The name of the variable that you will be referencing when sending requests. Note, an environment cannot have keys with the same name. * **Type:** The type of value the variable will store. It can be a **string**, **number**, **boolean**, **secret** (a masked value), or **array** (a list of values). See [Entering an array value](/api-client/environments-and-variables/environment-variables#entering-an-array-value) for how to type a list. * **Initial value (synced):** Initial values will be synced across the project. These values will be used by default if no user-defined Current value is set for the variable. * **Current value (local):** Current values are user-defined entries that are not synced across the project. These values will override the defined Initial values. If the current value is empty or left blank, then the initial value of the variable will be used. ![](https://mintcdn.com/requestly/I3ka5JRtv_yeHtHG/images/collection-and-subcollection-variables/f13a65d4-2344-4751-9a3c-062251962b4c.png?fit=max\&auto=format\&n=I3ka5JRtv_yeHtHG\&q=85\&s=4e174398fc4b7ddd64946cc914e11926) # Dynamic Variables Source: https://docs.requestly.com/api-client/environments-and-variables/dynamic-variables Dynamic variables are built in values that are generated automatically at request execution time. They remove the need for manual inputs or custom scripts when you need commonly used data like timestamps, random values, or unique identifiers. Unlike environment, collection, or global variables which you define yourself, dynamic variables are available out of the box and always generate a fresh value when a request runs. > [!NOTE] > > Requestly uses [**Faker.js**](https://fakerjs.dev/) to generate realistic data for dynamic variables. They are accessed using the special `$` prefix syntax: ``` {{$variableName}} ``` ## Using dynamic variables You can use dynamic variables anywhere in a request including the URL, headers, query params, and body. **Request Body** Use dynamic variables like `{{$randomFirstName}}`, `{{$randomLastName}}`, and `{{$randomEmail}}` to create unique user data for each request: ![](https://mintcdn.com/requestly/PlDkUIN-okisELMt/images/dynamic-variables/dynamic-variables-generate-random-user-data.png?fit=max\&auto=format\&n=PlDkUIN-okisELMt\&q=85\&s=44cd8ba002b9fe005bca84584e16f684) **URL Parameters** Dynamic variables are great for generating unique query parameters or path segments: ![](https://mintcdn.com/requestly/PlDkUIN-okisELMt/images/dynamic-variables/dynamic-variables-url-with-random-query-parameter.png?fit=max\&auto=format\&n=PlDkUIN-okisELMt\&q=85\&s=f4968a73fa22040a32872935a88d16ea) **Headers** You can also use dynamic variables in headers to generate unique values for each request: ![](https://mintcdn.com/requestly/PlDkUIN-okisELMt/images/dynamic-variables/dynamic-variables-headers-with-dynamic-values.png?fit=max\&auto=format\&n=PlDkUIN-okisELMt\&q=85\&s=0918cdee54e79f75d21d465c5faeb134) **Script** When using dynamic variables in scripts, call them as functions with the `rq.$` prefix: ![](https://mintcdn.com/requestly/PlDkUIN-okisELMt/images/dynamic-variables/dynamic-variables-in-pre-request.png?fit=max\&auto=format\&n=PlDkUIN-okisELMt\&q=85\&s=113e8a62ec16606d08633c580e32b3e4) > [!NOTE] > > **Script syntax:** When using dynamic variables in scripts, call them as functions: `rq.$variableName()` instead of the template syntax `{{$variableName}}`. ## Variable precedence When the same variable name is defined as both a dynamic variable and a user-defined variable (environment, collection, or global), the **user-defined variable takes precedence**. ### Precedence order **User-defined variables** (Runtime → Environment → SubCollection → Collection → Global) **>** **Dynamic variables** **Example :** If you define an environment variable named `$randomUUID`: ```javascript theme={null} rq.environment.set("$randomUUID", "123e4567-e89b-12d3-a456-426614174000"); ``` And then use `{{$randomUUID}}` in your request, it will resolve to `"123e4567-e89b-12d3-a456-426614174000"` (your custom value), **not** the dynamic UUID value. > [!TIP] > > **Best practice:** Never use the `$` prefix (e.g., `{{$randomUUID}}`) for user-defined variables. ## Use arguments with dynamic variables Some dynamic variables support optional arguments to customize their output. > [!NOTE] > > For a complete list of variables that support arguments and their available options, see the [Variables with arguments](#variables-with-arguments) section below. ### Syntax ``` {{$variableName arg1 arg2 ...}} ``` **Example:** ```json theme={null} { "id": "{{$randomAlphaNumeric 10}}", "email": "{{$randomEmail 'John' 'Doe'}}", "age": "{{$randomInt 18 65}}", "price": "{{$randomPrice 10 100 2 '$'}}" } ``` > [!NOTE] > > **Script syntax:** When using dynamic variables in scripts, call them as functions: `rq.$variableName(arg1,arg2 ...)` ## Supported dynamic variables Requestly provides a comprehensive set of built-in dynamic variables organized by category. ### Common | Variable | Description | Example | | - | - | - | | `{{$guid}}` | uuid-v4 style guid | `f47ac10b-58cc-4372-a567-0e02b2c3d479` | | `{{$timestamp}}` | Current UNIX timestamp in seconds | `1739404800` | | `{{$isoTimestamp}}` | Current ISO timestamp at zero UTC | `2026-02-13T14:25:30.177Z` | | `{{$randomUUID}}` | A random 36-character UUID | `a3bb189e-8bf9-3888-9912-ace4e6543002` | ### Text, Numbers and Colors | Variable | Description | Example | | - | - | - | | `{{$randomAlphaNumeric}}` | A random alpha-numeric character | `t` | | `{{$randomBoolean}}` | A random boolean value | `FALSE` | | `{{$randomInt}}` | A random integer between 0 and 10000 | `472` | | `{{$randomColor}}` | A random human readable color | `blue` | | `{{$randomHexColor}}` | A random hex value | `#2f8a45` | | `{{$randomAbbreviation}}` | A random abbreviation | `HTTP` | ### Internet and IP Addresses | Variable | Description | Example | | - | - | - | | `{{$randomIP}}` | A random IPv4 address | `192.168.45.233` | | `{{$randomIPV6}}` | A random IPv6 address | `2001:0db8:85a3:0000:0000:8a2e:0370:7334` | | `{{$randomMACAddress}}` | A random MAC address | `aa:bb:cc:dd:ee:ff` | | `{{$randomPassword}}` | A random 15-character alpha-numeric password | `8kP2mX9qL4nB5wV3` | | `{{$randomLocale}}` | A random two-letter language code (ISO 639-1) | `fr` | | `{{$randomUserAgent}}` | A random user agent | `Mozilla/5.0 ...` | | `{{$randomProtocol}}` | A random internet protocol | `https` | ### Names | Variable | Description | Example | | - | - | - | | `{{$randomFirstName}}` | A random first name | `Sarah` | | `{{$randomLastName}}` | A random last name | `Johnson` | | `{{$randomFullName}}` | A random first and last name | `Michael Anderson` | | `{{$randomNamePrefix}}` | A random name prefix | `Ms.` | | `{{$randomNameSuffix}}` | A random name suffix | `Jr.` | ### Profession | Variable | Description | Example | | - | - | - | | `{{$randomJobArea}}` | A random job area | `Security` | | `{{$randomJobDescriptor}}` | A random job descriptor | `Chief` | | `{{$randomJobTitle}}` | A random job title | `Senior Data Analyst` | | `{{$randomJobType}}` | A random job type | `Engineer` | ### Phone, Address and Location | Variable | Description | Example | | - | - | - | | `{{$randomPhoneNumber}}` | A random ten-digit phone number | `555-987-6543` | | `{{$randomPhoneNumberExt}}` | A random phone number with extension | `555-456-7890 x321` | | `{{$randomCity}}` | A random city name | `Riverside` | | `{{$randomStreetName}}` | A random street name | `Oak Avenue` | | `{{$randomStreetAddress}}` | A random street address | `456 Elm Drive` | | `{{$randomCountry}}` | A random country | `Canada` | | `{{$randomCountryCode}}` | A random two-letter country code (ISO 3166-1 alpha-2) | `US` | | `{{$randomLatitude}}` | A random latitude coordinate | `-23.5475` | | `{{$randomLongitude}}` | A random longitude coordinate | `151.2095` | ### Images | Variable | Description | Example | | - | - | - | | `{{$randomAvatarImage}}` | A random avatar image | `https://example.com/avatar/512x512` | | `{{$randomImageUrl}}` | A URL of a random image | `https://example.com/images/640/480` | | `{{$randomAbstractImage}}` | A URL of a random abstract image | `https://loremflickr.com/640/480/abstract` | | `{{$randomAnimalsImage}}` | A URL of a random animal image | `https://loremflickr.com/640/480/animals` | | `{{$randomBusinessImage}}` | A URL of a random stock business image | `https://loremflickr.com/640/480/business` | | `{{$randomCatsImage}}` | A URL of a random cat image | `https://loremflickr.com/640/480/cats` | | `{{$randomCityImage}}` | A URL of a random city image | `https://loremflickr.com/640/480/city` | | `{{$randomFoodImage}}` | A URL of a random food image | `https://loremflickr.com/640/480/food` | | `{{$randomNightlifeImage}}` | A URL of a random nightlife image | `https://loremflickr.com/640/480/nightlife` | | `{{$randomFashionImage}}` | A URL of a random fashion image | `https://loremflickr.com/640/480/fashion` | | `{{$randomPeopleImage}}` | A URL of a random image of a person | `https://loremflickr.com/640/480/people` | | `{{$randomNatureImage}}` | A URL of a random nature image | `https://loremflickr.com/640/480/nature` | | `{{$randomSportsImage}}` | A URL of a random sports image | `https://loremflickr.com/640/480/sports` | | `{{$randomTransportImage}}` | A URL of a random transportation image | `https://loremflickr.com/640/480/transport` | | `{{$randomImageDataUri}}` | A random image data URI | `data:image/svg+xml;charset=UTF-8...` | ### Finance | Variable | Description | Example | | - | - | - | | `{{$randomBankAccount}}` | A random 8-digit bank account number | `78945612` | | `{{$randomBankAccountName}}` | A random bank account name | `Savings Account` | | `{{$randomCreditCardMask}}` | A random masked credit card number | `1234` | | `{{$randomBankAccountBic}}` | A random BIC (Bank Identifier Code) | `DEUTDEFF` | | `{{$randomBankAccountIban}}` | A random 15-31 character IBAN | `GB82WEST12345698765432` | | `{{$randomTransactionType}}` | A random transaction type | `payment` | | `{{$randomCurrencyCode}}` | A random 3-letter currency code (ISO-4217) | `EUR` | | `{{$randomCurrencyName}}` | A random currency name | `US Dollar` | | `{{$randomCurrencySymbol}}` | A random currency symbol | `€` | | `{{$randomBitcoin}}` | A random bitcoin address | `1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa` | ### Business | Variable | Description | Example | | - | - | - | | `{{$randomCompanyName}}` | A random company name | `TechStart Solutions` | | `{{$randomCompanySuffix}}` | A random company suffix | `LLC` | | `{{$randomBs}}` | A random phrase of business-speak | `streamline innovative platforms` | | `{{$randomBsAdjective}}` | A random business-speak adjective | `dynamic` | | `{{$randomBsBuzz}}` | A random business-speak buzzword | `optimize` | | `{{$randomBsNoun}}` | A random business-speak noun | `solutions` | ### Catchphrases | Variable | Description | Example | | - | - | - | | `{{$randomCatchPhrase}}` | A random catchphrase | `Innovative scalable methodology` | | `{{$randomCatchPhraseAdjective}}` | A random catchphrase adjective | `Robust` | | `{{$randomCatchPhraseDescriptor}}` | A random catchphrase descriptor | `cloud-based` | | `{{$randomCatchPhraseNoun}}` | A random catchphrase noun | `framework` | ### Databases | Variable | Description | Example | | - | - | - | | `{{$randomDatabaseColumn}}` | A random database column name | `userId` | | `{{$randomDatabaseType}}` | A random database type | `varchar` | | `{{$randomDatabaseCollation}}` | A random database collation | `utf8_unicode_ci` | | `{{$randomDatabaseEngine}}` | A random database engine | `InnoDB` | ### Dates | Variable | Description | Example | | - | - | - | | `{{$randomDateFuture}}` | A random future datetime | `2027-11-05T18:30:22.000Z` | | `{{$randomDatePast}}` | A random past datetime | `2023-08-14T15:45:33.000Z` | | `{{$randomDateRecent}}` | A random recent datetime | `2026-02-07T10:20:15.000Z` | | `{{$randomWeekday}}` | A random weekday | `Monday` | | `{{$randomMonth}}` | A random month | `September` | ### Domains, Emails and Usernames | Variable | Description | Example | | - | - | - | | `{{$randomDomainName}}` | A random domain name | `test-site.net` | | `{{$randomDomainSuffix}}` | A random domain suffix | `org` | | `{{$randomDomainWord}}` | A random unqualified domain name | `sample` | | `{{$randomEmail}}` | A random email address | `sample@gmail.com` | | `{{$randomExampleEmail}}` | A random email address from an example domain | `alex.johnson@example.org` | | `{{$randomUserName}}` | A random username | `techuser2024` | | `{{$randomUrl}}` | A random URL | `https://demo-website.io` | ### Files and Directories | Variable | Description | Example | | - | - | - | | `{{$randomSemver}}` | A random semantic version number | `3.12.4` | | `{{$randomFileName}}` | A random file name (includes uncommon extensions) | `report_2024.pdf` | | `{{$randomFileType}}` | A random file type (includes uncommon file types) | `video` | | `{{$randomFileExt}}` | A random file extension (includes uncommon extensions) | `csv` | | `{{$randomCommonFileName}}` | A random file name | `presentation.pptx` | | `{{$randomCommonFileType}}` | A random, common file type | `image` | | `{{$randomCommonFileExt}}` | A random, common file extension | `jpg` | | `{{$randomFilePath}}` | A random file path | `/var/www/html/index.html` | | `{{$randomDirectoryPath}}` | A random directory path | `/opt/apps` | | `{{$randomMimeType}}` | A random MIME type | `image/jpeg` | ### Stores | Variable | Description | Example | | - | - | - | | `{{$randomPrice}}` | A random price between 0.00 and 1000.00 | `247.99` | | `{{$randomProduct}}` | A random product | `Shoes` | | `{{$randomProductAdjective}}` | A random product adjective | `Premium` | | `{{$randomProductMaterial}}` | A random product material | `Cotton` | | `{{$randomProductName}}` | A random product name | `Ergonomic Wooden Chair` | | `{{$randomDepartment}}` | A random commerce category | `Electronics` | ### Grammar | Variable | Description | Example | | - | - | - | | `{{$randomNoun}}` | A random noun | `network` | | `{{$randomVerb}}` | A random verb | `generate` | | `{{$randomIngverb}}` | A random verb ending in -ing | `processing` | | `{{$randomAdjective}}` | A random adjective | `efficient` | | `{{$randomWord}}` | A random word | `system` | | `{{$randomWords}}` | Some random words | `quick brown fox jumps high` | | `{{$randomPhrase}}` | A random phrase | `Try to compress the TCP protocol...` | ### Lorem Ipsum | Variable | Description | Example | | - | - | - | | `{{$randomLoremWord}}` | A random word of lorem ipsum text | `ipsum` | | `{{$randomLoremWords}}` | Some random words of lorem ipsum text | `dolor sit amet` | | `{{$randomLoremSentence}}` | A random sentence of lorem ipsum text | `Sed ut perspiciatis unde omnis iste natus.` | | `{{$randomLoremSentences}}` | A random 2 to 6 sentences of lorem ipsum text | `Nemo enim ipsam voluptatem...` | | `{{$randomLoremParagraph}}` | A random paragraph of lorem ipsum text | `Lorem ipsum dolor sit amet...` | | `{{$randomLoremParagraphs}}` | 3 random paragraphs of lorem ipsum text | `Voluptatem rem magnam...` | | `{{$randomLoremText}}` | A random amount of lorem ipsum text | `Temporibus autem quibusdam...` | | `{{$randomLoremSlug}}` | A random lorem ipsum URL slug | `lorem-ipsum-dolor` | | `{{$randomLoremLines}}` | 1 to 7 random lines of lorem ipsum | `Sed ut perspiciatis unde...` | ## Variables with arguments The following dynamic variables support optional arguments for customization. ### Common > **\$guid** > > **Arguments:** `version` (`4`|`7`), `refDate` > > ```javascript theme={null} > {{$guid 7}} > {{$guid 4 "2026-01-01"}} > ``` > **\$randomUUID** > > **Arguments:** `version` (`4`|`7`), `refDate` > > ```javascript theme={null} > {{$randomUUID 7}} > {{$randomUUID 4 "2026-01-01"}} > ``` ### Text, Numbers and Colors > **\$randomAlphaNumeric** > > **Arguments:** `length | (min max)`, `casing` (`upper`|`lower`|`mixed`), `exclude` > > ```javascript theme={null} > {{$randomAlphaNumeric 5}} > {{$randomAlphaNumeric 3 8 "upper"}} > ``` > **\$randomBoolean** > > **Arguments:** `probability` (`0-1`) > > ```javascript theme={null} > {{$randomBoolean 0.8}} > ``` > **\$randomInt** > > **Arguments:** `max | (min max)` > > ```javascript theme={null} > {{$randomInt 100}} > {{$randomInt 1 100}} > {{$randomInt 0 100}} > ``` > **\$randomHexColor** > > **Arguments:** `format` (`hex`|`css`|`binary`), `includeAlpha` (`true`|`false`), `prefix`, `casing` (`upper`|`lower`|`mixed`) > > ```javascript theme={null} > {{$randomHexColor "css"}} > {{$randomHexColor "hex" "true" "#" "upper"}} > ``` ### Internet and IP Addresses > **\$randomIP** > > **Arguments:** `cidrBlock | network` > > ```javascript theme={null} > {{$randomIP "192.168.0.0/16"}} > ``` > **\$randomMACAddress** > > **Arguments:** `separator` > > ```javascript theme={null} > {{$randomMACAddress "-"}} > ``` > **\$randomPassword** > > **Arguments:** `length`, `memorable` (`true`|`false`), `pattern`, `prefix` > > ```javascript theme={null} > {{$randomPassword 20}} > {{$randomPassword 12 "true"}} > ``` ### Names > **\$randomFirstName** > > **Arguments:** `gender` (`male`|`female`) > > ```javascript theme={null} > {{$randomFirstName "male"}} > ``` > **\$randomLastName** > > **Arguments:** `gender` (`male`|`female`) > > ```javascript theme={null} > {{$randomLastName "female"}} > ``` > **\$randomFullName** > > **Arguments:** `gender` (`male`|`female`) > > ```javascript theme={null} > {{$randomFullName "male"}} > ``` > **\$randomNamePrefix** > > **Arguments:** `gender` (`male`|`female`) > > ```javascript theme={null} > {{$randomNamePrefix "female"}} > ``` ### Phone, Address and Location > **\$randomPhoneNumber** > > **Arguments:** `style` (`human`|`national`|`international`) > > ```javascript theme={null} > {{$randomPhoneNumber "international"}} > ``` > **\$randomStreetAddress** > > **Arguments:** `useFullAddress` (`true`|`false`) > > ```javascript theme={null} > {{$randomStreetAddress "true"}} > ``` > **\$randomCountryCode** > > **Arguments:** `variant` (`alpha-2`|`alpha-3`|`numeric`) > > ```javascript theme={null} > {{$randomCountryCode "alpha-3"}} > ``` > **\$randomLatitude** > > **Arguments:** `max | (min max)`, `precision` > > ```javascript theme={null} > {{$randomLatitude 50}} > {{$randomLatitude -10 50 4}} > ``` > **\$randomLongitude** > > **Arguments:** `max | (min max)`, `precision` > > ```javascript theme={null} > {{$randomLongitude 100}} > {{$randomLongitude -100 100 4}} > ``` ### Images > **\$randomImageUrl** > > **Arguments:** `width`, `height` > > ```javascript theme={null} > {{$randomImageUrl 800 600}} > ``` > **\$randomImageDataUri** > > **Arguments:** `width`, `height`, `color`, `type` (`svg-uri`|`svg-base64`) > > ```javascript theme={null} > {{$randomImageDataUri 200 200 "blue" "svg-base64"}} > ``` ### Finance > **\$randomBankAccount** > > **Arguments:** `length` (default `8`) > > ```javascript theme={null} > {{$randomBankAccount 10}} > ``` > **\$randomCreditCardMask** > > **Arguments:** `issuer` > > ```javascript theme={null} > {{$randomCreditCardMask "visa"}} > ``` > **\$randomBankAccountBic** > > **Arguments:** `includeBranchCode` (`true`|`false`) > > ```javascript theme={null} > {{$randomBankAccountBic "true"}} > ``` > **\$randomBankAccountIban** > > **Arguments:** `formatted` (`true`|`false`), `countryCode` > > ```javascript theme={null} > {{$randomBankAccountIban "true" "DE"}} > ``` > **\$randomBitcoin** > > **Arguments:** `type` (`legacy`|`segwit`|`bech32`), `network` (`mainnet`|`testnet`) > > ```javascript theme={null} > {{$randomBitcoin "segwit" "mainnet"}} > ``` ### Dates > **\$randomDateFuture** > > **Arguments:** `years`, `refDate` > > ```javascript theme={null} > {{$randomDateFuture 5}} > {{$randomDateFuture 2 "2025-01-01"}} > ``` > **\$randomDatePast** > > **Arguments:** `years`, `refDate` > > ```javascript theme={null} > {{$randomDatePast 3}} > {{$randomDatePast 1 "2024-06-01"}} > ``` > **\$randomDateRecent** > > **Arguments:** `days`, `refDate` > > ```javascript theme={null} > {{$randomDateRecent 7}} > {{$randomDateRecent 30 "2026-01-01"}} > ``` > **\$randomWeekday** > > **Arguments:** `abbreviated` (`true`|`false`), `context` (`true`|`false`) > > ```javascript theme={null} > {{$randomWeekday "true"}} > ``` > **\$randomMonth** > > **Arguments:** `abbreviated` (`true`|`false`), `context` (`true`|`false`) > > ```javascript theme={null} > {{$randomMonth "true"}} > ``` ### Domains, Emails and Usernames > **\$randomEmail** > > **Arguments:** `firstName`, `lastName`, `provider`, `allowSpecialCharacters` (`true`|`false`) > > ```javascript theme={null} > {{$randomEmail "John"}} > {{$randomEmail "John" "Doe" "gmail.com"}} > ``` > **\$randomExampleEmail** > > **Arguments:** `firstName`, `lastName`, `allowSpecialCharacters` (`true`|`false`) > > ```javascript theme={null} > {{$randomExampleEmail "John" "Doe"}} > ``` > **\$randomUserName** > > **Arguments:** `firstName`, `lastName` > > ```javascript theme={null} > {{$randomUserName "John" "Doe"}} > ``` > **\$randomUrl** > > **Arguments:** `protocol` (`http`|`https`), `appendSlash` (`true`|`false`) > > ```javascript theme={null} > {{$randomUrl "https" "true"}} > ``` ### Files and Directories > **\$randomFileName** > > **Arguments:** `extensionCount | (min max)` > > ```javascript theme={null} > {{$randomFileName 2}} > {{$randomFileName 1 3}} > ``` > **\$randomFileExt** > > **Arguments:** `mimeType` > > ```javascript theme={null} > {{$randomFileExt "image/jpeg"}} > ``` ### Stores > **\$randomPrice** > > **Arguments:** `max | (min max)`, `dec`, `symbol` > > ```javascript theme={null} > {{$randomPrice 500}} > {{$randomPrice 10 100 2 "$"}} > ``` ### Grammar > **\$randomNoun** > > **Arguments:** `length | (min max)`, `strategy` (`fail`|`closest`|`shortest`|`longest`|`any-length`) > > ```javascript theme={null} > {{$randomNoun 5}} > {{$randomNoun 3 8 "closest"}} > ``` > **\$randomVerb** > > **Arguments:** `length | (min max)`, `strategy` (`fail`|`closest`|`shortest`|`longest`|`any-length`) > > ```javascript theme={null} > {{$randomVerb 5}} > {{$randomVerb 3 8 "closest"}} > ``` > **\$randomAdjective** > > **Arguments:** `length | (min max)`, `strategy` (`fail`|`closest`|`shortest`|`longest`|`any-length`) > > ```javascript theme={null} > {{$randomAdjective 5}} > {{$randomAdjective 3 8 "closest"}} > ``` > **\$randomWord** > > **Arguments:** `length | (min max)`, `strategy` (`fail`|`closest`|`shortest`|`longest`|`any-length`) > > ```javascript theme={null} > {{$randomWord 5}} > {{$randomWord 3 8 "closest"}} > ``` > **\$randomWords** > > **Arguments:** `count | (min max)` > > ```javascript theme={null} > {{$randomWords 3}} > {{$randomWords 2 5}} > ``` ### Lorem Ipsum > **\$randomLoremWord** > > **Arguments:** `length | (min max)`, `strategy` (`fail`|`closest`|`shortest`|`longest`|`any-length`) > > ```javascript theme={null} > {{$randomLoremWord 5}} > {{$randomLoremWord 3 8 "closest"}} > ``` > **\$randomLoremWords** > > **Arguments:** `count | (min max)` > > ```javascript theme={null} > {{$randomLoremWords 5}} > {{$randomLoremWords 3 7}} > ``` > **\$randomLoremSentence** > > **Arguments:** `wordCount | (min max)` > > ```javascript theme={null} > {{$randomLoremSentence 10}} > {{$randomLoremSentence 5 12}} > ``` > **\$randomLoremSentences** > > **Arguments:** `count | (min max)`, `separator` > > ```javascript theme={null} > {{$randomLoremSentences 3}} > {{$randomLoremSentences 2 5}} > ``` > **\$randomLoremParagraph** > > **Arguments:** `sentenceCount | (min max)` > > ```javascript theme={null} > {{$randomLoremParagraph 5}} > {{$randomLoremParagraph 3 7}} > ``` > **\$randomLoremParagraphs** > > **Arguments:** `count | (min max)`, `separator` > > ```javascript theme={null} > {{$randomLoremParagraphs 5}} > {{$randomLoremParagraphs 2 4}} > ``` > **\$randomLoremSlug** > > **Arguments:** `count | (min max)` > > ```javascript theme={null} > {{$randomLoremSlug 5}} > {{$randomLoremSlug 2 4}} > ``` > **\$randomLoremLines** > > **Arguments:** `count | (min max)` > > ```javascript theme={null} > {{$randomLoremLines 3}} > {{$randomLoremLines 2 5}} > ``` ## What's Next? > **[Environment Variables](/api-client/environments-and-variables/environment-variables)** > > Store and manage auth tokens securely with variables > **[Runtime Variables](/api-client/environments-and-variables/runtime-variables)** > > Use temporary variables for request execution # Environment Variables Source: https://docs.requestly.com/api-client/environments-and-variables/environment-variables **Environment Variables** in Requestly allow you to configure API requests based on different environments, such as **Development**, **Staging**, or **Production**. They help you manage environment-specific values like base URLs, tokens, or credentials without manually editing each request when switching contexts. [https://www.youtube.com/embed/0m00eSkuDcc](https://www.youtube.com/embed/0m00eSkuDcc) ### Why Use Environment Variables? Environment variables let you: * Switch between Dev, Staging, and Prod configurations easily * Avoid editing request details manually for each environment * Keep secrets scoped to the environment where they’re needed * Enable environment-specific behavior in scripts and tests Example use cases: * `{{base_url}}` points to `https://dev.api.com` in development and `https://api.com` in production * Different `{{auth_token}}` for each environment ## **How to Create Environment Variables** ### **Step 1: Access the Environments Tab** Click on the **Environments** tab in the side menu. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/environment-variables/acbc49e8-3d19-404f-944c-450bf66b98f8.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=f5cd4d2ba791d21c5078402ae0d0bb50) ### **Step 2: Select an Environment** Select the environment you want to add variables to. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/environment-variables/30c3ea2f-5bc2-4523-97e2-ed61318bf2e6.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=5da77cdcd432eef645fccffd8da50a36) ### **Step 3: Add Variables** Add variables in the table by specifying the following details: * **Key:** The name of the variable that you will be referencing when sending requests. Note, an environment cannot have keys with the same name. * **Type:** The type of value the variable will store. It can be a **string**, **number**, **boolean**, **secret** (a masked value), or **array** (a list of values). * **Initial value (synced):** Initial values will be synced across the project. These values will be used by default if no user-defined Current value is set for the variable. * **Current value (local):** Current values are user-defined entries that are not synced across the project. These values will override the defined Initial values. If the current value is empty or left blank, then the initial value of the variable will be used. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/environment-variables/8c5dd425-186d-4953-8304-87032f9f62ab.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=7bd52bb679d18281aab0b86d47e1ed0b) ### **Step 4: Switch Environments** To switch environments, use the dropdown on the top bar of the API Client’s sidebar. Select the desired environment to ensure that the variables associated with it are used in your API requests. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/environment-variables/cad0bf2f-265e-4d8a-80a8-878f24278746.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=881bdde47cb4353d46020632468946ab) ## Entering an array value Choose **array** as the type when a variable should hold a list of items instead of a single value. Type the items into the value field and Requestly parses them into a list when you save: * `1, 2, 3` becomes a list of numbers. * `a, b, c` becomes a list of strings. * Wrap an item in quotes to keep it a string: `"1", "2"` stays a list of the strings `1` and `2`. * Paste exact JSON to control each item's type precisely, for example `[1, "2", true]`. * A single value with no comma becomes a one-item list, and an empty value becomes an empty list. When you reference an array variable inline with `{{variable_name}}`, it renders as the JSON text of the list, for example `["a","b"]`. In scripts, an array variable is returned as a real array. See [rq.environment](/api-client/rq-api-reference/rq-environment#working-with-array-variables) for reading and writing array values in scripts. # Global Variables Source: https://docs.requestly.com/api-client/environments-and-variables/global-variables Learn about global variables in requestly **Global Variables** in Requestly are shared values accessible across all requests, environments, and collections in your project. They are ideal for constants or secrets that don’t change frequently, like API keys, common headers, or service base URLs. Using global variables makes your API collections more reusable, consistent, and easier to update across your project. [https://www.youtube.com/embed/XlEvZ4LIfDs](https://www.youtube.com/embed/XlEvZ4LIfDs) ## **How to Create Global Variables** ### **Step 1: Access Global Variables** Click on the **Environments** icon in the side menu. The first item in the list is labeled as "Global variables." ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/global-variables/00d3b176-4a5e-4c9e-97a4-609bb5227742.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=27d1d0c7396aa0349f21739c9b2d9451) ### **Step 2: Add Variables** Add variables in the table by specifying the following details: * **Key:** The name of the variable that you will be referencing when sending requests. Note, global variables cannot have duplicate keys. * **Type:** The type of value the variable will store. It can be a **string**, **number**, **boolean**, **secret** (a masked value), or **array** (a list of values). See [Entering an array value](/api-client/environments-and-variables/environment-variables#entering-an-array-value) for how to type a list. * **Initial value (synced):** Initial values will be synced across the project. These values will be used by default if no user-defined Current value is set for the variable. * **Current value (local):** Current values are user-defined entries that are not synced across the project. These values will override the defined Initial values. If the current value is empty or left blank, then the initial value of the variable will be used. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/global-variables/eb07a0bd-0a44-490b-bd94-94c8c58e73fa.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=92bb4e83fd1eccd2f8e4375bd74dec37) # Runtime Variables Source: https://docs.requestly.com/api-client/environments-and-variables/runtime-variables Runtime variables in Requestly are **temporary variables** that last until the session is closed. Unlike environment or collection variables, they are available globally across all projects. > [!TIP] > > Runtime variables are the only type of variables that work **across multiple projects**. You can choose whether variables should **persist** it’s value after restarting the app . ## Why use runtime variables? Runtime variables are designed to give you flexibility when testing APIs across different projects. Some common use cases include: * **Quick testing**: Store temporary values like access tokens or session IDs while debugging. * **Cross-project usage**: Share the same variable across multiple local projects without redefining it each time. * **Persistence control**: Choose whether the variable should survive after restarting the app or clear automatically for a fresh start. > [!WARNING] > > Runtime variables are **not synced to the cloud**. They only exist locally on your device. If you switch machines or reinstall the app, these variables will not carry over. ## Creating a runtime variable **1. Open Requestly and Go to runtime variables.** From the sidebar, click on **Runtime variables**. ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/runtime-variables/7126d4f7-a436-49aa-b0c0-3139af0be69f.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=bb198e913469404e1ed519e73609bc86) **2. Create a new Variable** In the variables table, click **+ Add More** and enter the variable details: * **Key** - The variable name (e.g., `session_id`). * **Value** - The value you want to store. * **Type** - Select from **String**, **Number**, **Boolean**, **Secret**, or **Array** (a list of values). See [Entering an array value](/api-client/environments-and-variables/environment-variables#entering-an-array-value) for how to type a list. * **Persistent** - Toggle whether the variable should be saved across app restarts. * **Yes** → Keeps its value after restarting the app. * **No** → Clears itself automatically on restart. ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/runtime-variables/94304f29-becc-4dd6-8789-1ed8c7b0206b.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=92051f7a9a6d168344f29acdf9dbf454) ## Using runtime variables **Method 1: Insert variables directly in requests** You can use runtime variables just like environment or collection variables. Wrap the variable name in double curly braces `{{ }}`: `https://api.example.com/users/{{session_id}}` **Method 2: Set variables in scripts**\ You can define or update runtime variables in the **Scripts** tab using the `rq.variables` object. ```javascript theme={null} rq.variables.set("token", "12345"); rq.variables.get("token"); ``` Two things worth knowing about that object: * **`set` always writes to the runtime scope**, but **`get` reads from every scope**. `rq.variables.get("token")` returns the runtime value if there is one, and otherwise falls back to a data file column, the active environment, the collection, or globals. See [rq.variables](/api-client/rq-api-reference/rq-variables) for the full search order. * **A value set from a script is temporary.** It lasts for the session and is not saved back to the runtime variables list above, so a reload restores whatever you typed there yourself. Use environment, collection, or global scope for a value that should persist. # Set a Response Value as a Variable Source: https://docs.requestly.com/api-client/environments-and-variables/set-response-value-as-variable Capture a value straight out of a response body into an environment, collection, or global variable by right-clicking the selection, with no script to write. A login call returns a token and your next request needs it. Rather than writing a post-response script for that, select the value in the response body, right-click it, and choose **Set as variable**. Requestly saves the selected text to a variable you name, in the scope you pick, ready to use as `{{variable_name}}`. ## Where you can use it The action lives in the response panel of: * HTTP requests * GraphQL requests * Saved examples of either Other protocol clients, the Dev Tools network panel, and scheduled-run results do not offer it. ## Capture a value **1. Send the request** Send the request and open the **Body** tab of the response panel. **2. Select the value you want** Select the text in the response body. The action needs a text view of the body. A picture, a binary placeholder, or an HTML preview blocks the selection. Switch the format selector above the body to **Raw** first. In a formatted JSON body, a double-click selects the value without its surrounding quote characters. Dragging across the quotes takes them with it, which is also fine: Requestly cleans the selection up for you when it fills the picker. See [Quoted JSON strings are saved without their quotes](#quoted-json-strings-are-saved-without-their-quotes). **3. Right-click the selection** Right-click anywhere inside the selection. A short menu opens with **Copy** and **Set as variable**. Choose **Set as variable**. ![A selected token in a JSON response body with the right-click menu open, showing Copy and Set as variable](https://mintcdn.com/requestly/qL6H9DS5yJKdl_V6/images/set-as-variable-menu.light.png?fit=max\&auto=format\&n=qL6H9DS5yJKdl_V6\&q=85\&s=436f065e78dd5387b7acb190fdd1337d) **4. Name the variable and pick a scope** The picker opens with your selection already in **Current value**. * **Name**: type a new name, or pick an existing one from the list for that scope to overwrite it. The list matches on any part of a name, not just the start. * **Current value**: edit the captured text if you need to. For **String** and **Number** the field accepts line breaks, so a whole JSON object survives an edit intact. **Secret** masks the value in a single-line field, and **Boolean** replaces it with a true/false list. * **Type**: **String**, **Number**, **Boolean**, or **Secret**. * **Scope**: **Environment**, **Collection**, or **Global**. ![The Set as variable picker with the Name, Current value, Type, and Scope fields filled in, above the Cancel and Save buttons](https://mintcdn.com/requestly/qL6H9DS5yJKdl_V6/images/set-as-variable-picker.light.png?fit=max\&auto=format\&n=qL6H9DS5yJKdl_V6\&q=85\&s=cf9664fdf602405691e01a09c43b2085) **5. Save** Click **Save**. A confirmation names the variable and the scope it went to. **Save** stays disabled until the variable has a name. **Save** is also disabled while the selection is too large, or while no scope is available. > [!TIP] > > **Copy** in the same menu copies exactly what you selected, quote characters included. ## Where the captured value is saved Every Requestly variable holds two values: an **Initial value (synced)**, which your project shares with your team, and a **Current value (local)**, which stays on the device that set it. [Environment variables](/api-client/environments-and-variables/environment-variables) explains both in full. **Set as variable** writes your capture to the **Current value** only. The picker has no **Initial value** row for exactly this reason. The captured text is never sent to your team and never written to the shared value, because a bearer token is the main reason to capture a response value in the first place. ![The environment variables table showing the captured token in the Current value column with the Initial value column empty](https://mintcdn.com/requestly/qL6H9DS5yJKdl_V6/images/set-as-variable-saved-value.light.png?fit=max\&auto=format\&n=qL6H9DS5yJKdl_V6\&q=85\&s=6c79369399c53d0a12d2e94fd00a5703) Two things follow from that: * A teammate who opens the same project sees the variable name, but not your captured value. * On your other devices the variable exists with an empty value until you capture it there too. > [!NOTE] > > To share a captured value on purpose, open the variables table and type it into the **Initial value** column yourself. ## Choose a scope | Scope | Where the value is stored | | - | - | | **Environment** | The environment currently selected in the API client sidebar | | **Collection** | The collection that directly contains this request | | **Global** | The project's global variables | The picker offers only the scopes it can write to. **Environment** is missing when no environment is selected. **Collection** is missing for a request that does not sit inside a collection. **Global** is missing until the project has a global environment. When no scope at all is available, the picker shows a message and **Save** stays disabled. > [!NOTE] > > Runtime variables are not offered here. To set one from a response, use a post-response script - see [Runtime variables](/api-client/environments-and-variables/runtime-variables). ## Quoted JSON strings are saved without their quotes When your selection is exactly one JSON string, Requestly fills the picker with the string itself: the wrapping quotes are removed and escape sequences are resolved. A token therefore never gets saved with quote characters wrapped around it. | You select | The picker fills in | | - | - | | `"eyJhbGciOiJIUzI1NiJ9"` | `eyJhbGciOiJIUzI1NiJ9` | | `"say \"hi\""` | `say "hi"` | | `"caf\u00e9"` | `café` | | `{"a":1}` | `{"a":1}` | | `12345` | `12345` | Anything that is not exactly one JSON string is filled in verbatim, as the last two rows show. The value field stays editable either way, so you always see what **Save** will store. ## Overwrite an existing variable Choosing a name that already exists in the selected scope is an overwrite, not an error. The picker warns you that saving replaces the variable's current value, and **Save** stays enabled. An overwrite: * replaces the **Current value** with your capture * leaves the **Initial value** exactly as it was, so your team's shared value is never wiped * keeps the variable a **Secret** when it already was one, so a masked variable is never unmasked by a capture ## The capture happens once **Set as variable** stores the text that was on screen when you right-clicked. It is a one-time capture, not a live link to the response, so sending the request again leaves the variable exactly as it is. > [!NOTE] > > For a value that has to refresh on every run, such as a token that expires, use a post-response script instead. See [rq.environment](/api-client/rq-api-reference/rq-environment) and [Scripts](/api-client/scripts). ## Limits * A name made only of spaces does not count as a name, and **Save** stays disabled. * A selection over 100,000 characters is refused rather than shortened. Select a smaller part of the body, or use **Copy**. * The menu appears only over a real selection. Right-click with nothing selected, or with only whitespace selected, and the default context menu appears instead. * The capture takes the characters shown in the current view. If you switch the body to **Hex** or **Base64** and select there, you capture those characters rather than the decoded text. * A save can fail when you lack permission to save variables to this project. The picker stays open with a message, so you can try again. # Using Variables in API Requests Source: https://docs.requestly.com/api-client/environments-and-variables/using-variables-in-api-requests Once you've defined variables in Requestly, whether global, environment, collection, or subcollection, you can reference them directly in your API requests. This allows you to dynamically inject values into URLs, headers, request bodies, scripts, and more. ## **Use Variables in API Requests** ### **Step 1: Create or Open a Request** Create or open an existing request in the **API Client**. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/using-variables-in-api-requests/51b2389d-2186-42d7-99b8-a1fb295df6bb.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=5e68dcb615ae96c7edc9639fcf21dd4b) ### **Step 2: Replace Static Values** Replace static values with your environment variables using the `{{variable_name}}` syntax. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/using-variables-in-api-requests/f597030e-3b81-4656-8267-182280d2ee76.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=a9f3dfa3cc2a667dd8a294078d9790f2) ### **Step 3: View Variable Values** Hover over a variable to see its resolved value. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/using-variables-in-api-requests/0f1df5b5-d0e1-4cd5-b270-3f6ac6e40507.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=7f5b3a24daf1cd147f1d4c8f6713b2a3) ## **Test Your Setup** ### **Step 1: Execute the Request** Click **Send** to execute the request. ### **Step 2: Verify Resolved Values** Check the resolved values in the **Request Preview** to ensure that variables are substituted correctly. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/using-variables-in-api-requests/9c19eb9d-51f8-4a32-b8db-77fcd3d27a2a.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=a566dea9ed790acdca3ffeb1a486bf75) > [!TIP] > > If a variable isn't resolving, verify that the variable name matches exactly (case-sensitive) and is present in the selected environment. ## **Array variables** When a variable holds an [array value](/api-client/environments-and-variables/environment-variables), referencing it inline with `{{variable_name}}` renders the JSON text of the list. For example, an array variable holding `a` and `b` resolves to `["a","b"]` in a URL, header, or body. To work with individual items, read the variable in a script, where it is returned as a real array. See [rq.environment](/api-client/rq-api-reference/rq-environment#working-with-array-variables) for reading array variables in scripts. ## **Reading the same variables in a script** Everything above resolves `{{variable_name}}` inside the request itself. From a pre-request or post-response script, read the same values with `rq.variables`: ```javascript theme={null} const baseUrl = rq.variables.get("base_url"); // searches every scope const url = rq.variables.replaceIn("{{base_url}}/users/{{user_id}}"); ``` `rq.variables.get` uses the same scope order the request does, so a script and a `{{reference}}` in the URL bar always agree on which value wins. `rq.variables.set` writes a temporary value for the current session. > [!NOTE] > > `replaceIn` resolves stored variables only. A dynamic variable such as `{{$guid}}` comes back as literal text, so call `rq.$guid()` in the script instead. See [rq.variables](/api-client/rq-api-reference/rq-variables) for the full reference. ## **Composite variables** Composite variables allow you to reference one variable inside another variable's value. This is useful when you want to build dynamic values from other variables. ### **How it works** Define a variable that references another variable using the `{{variable_name}}` syntax: | Variable Name | Value | | - | - | | `base_url` | `api.example.com` | | `api_endpoint` | `https://{{base_url}}/v1` | When `api_endpoint` is resolved, it becomes `https://api.example.com/v1`. ### **Example: Building dynamic URLs** You can chain multiple variables together: | Variable Name | Value | | - | - | | `env` | `staging` | | `region` | `us-east` | | `base_url` | `{{env}}.{{region}}.api.example.com` | | `full_url` | `https://{{base_url}}/users` | The `full_url` resolves to `https://staging.us-east.api.example.com/users`. ### **Circular dependency handling** If you create circular references (e.g., `var_a = {{var_b}}` and `var_b = {{var_a}}`), Requestly detects this and leaves the variables unresolved to prevent infinite loops. > [!NOTE] > > Autocompletion and syntax highlighting for variable references inside the variables table is not currently supported. # Variable Precedence Source: https://docs.requestly.com/api-client/environments-and-variables/variable-precedence Variable precedence in Requestly defines how a variable value is resolved when the same variable name exists in multiple scopes. The value is picked based on scope priority, ensuring the most relevant context is always applied. ## Precedence order > Runtime Variables → Data File (iteration) Variables → Environment Variables → SubCollection Variables → Collection Variables → Global Variables → Dynamic Variables During a Collection Runner data-file run, the per-iteration variables from the CSV or JSON sit just below Runtime Variables. This lets a script override a column for one run, which is the usual way to refresh a token that the data file only seeds. > [!NOTE] > > **Dynamic variables** are built-in variables (like `{{$timestamp}}`, `{{$randomUUID}}`, etc.) that have the lowest precedence. If you define a custom variable with the same name, your custom value will be used. ## How it works * **Runtime variables** have the highest priority, including over a data file column of the same name. If a runtime variable with the same name exists, it overrides all other scopes for the duration of the session. * **Data file variables** come next during a Collection Runner run, and override environment, collection, and global values. * **Environment variables** are checked next and override SubCollection, Collection, and Global variables. * **SubCollection variables** apply only within that SubCollection and override Collection and Global variables. * **Collection variables** apply to all requests in the collection unless overridden by a higher scope. * **Global variables** act as the final fallback when the variable is not found in any other scope. This model makes it easy to reuse variables globally while still allowing precise overrides for environments, collections, or temporary runtime use cases. The same order applies whether the value is resolved for a `{{name}}` reference in a request or read from a script with [`rq.variables.get`](/api-client/rq-api-reference/rq-variables), so the two never disagree. ## Developer style explanation ```javascript theme={null} if (variable_name in runtime_variables) { // Check runtime return runtime_variables[variable_name]; } else if (variable_name in environment_variables) { // Check environment return environment_variables[variable_name]; } else if (variable_name in subcollection_variables) { // Check sub-collection return subcollection_variables[variable_name]; } else if (variable_name in collection_variables) { // Check collection return collection_variables[variable_name]; } else if (variable_name in global_variables) { // Check global return global_variables[variable_name]; } else if (is_dynamic_variable(variable_name)) { // Check dynamic variables return generate_dynamic_value(variable_name); // e.g., $timestamp, $randomUUID } else { return null; // Variable not found in any scope } ``` > [!NOTE] > > When using the `$` prefix (e.g., `{{$timestamp}}`), the system skips user-defined variable lookups and directly generates the dynamic value. ## Example scenario Assume the variable `{{base_url}}` is defined in multiple scopes: | Scope | Value | | - | - | | Global | `https://global.api.com` | | Collection | `https://collection.api.com` | | SubCollection | `https://sub.api.com` | | Environment | `https://env.api.com` | | Runtime | `https://runtime.api.com` | If you send a request inside a **SubCollection** with an active **Environment**, and a **runtime variable** with the same name exists, `{{base_url}}` resolves to: `https://runtime.api.com` If the runtime variable is removed, the value falls back to the **environment variable**, followed by SubCollection, Collection, and finally Global based on availability. ## Dynamic variables precedence example Assume you want to use a timestamp in your request: **Scenario 1: Using `{{timestamp}}`** (without `$` prefix) | Scope | Value (if defined) | | - | - | | Environment | `"2024-01-15"` | | Dynamic | Current timestamp (e.g., `1613360320`) | Result: `{{timestamp}}` resolves to `"2024-01-15"` (your custom environment variable) **Scenario 2: Using `{{$timestamp}}`** (with `$` prefix) Result: `{{$timestamp}}` **always** resolves to the current Unix timestamp (e.g., `1613360320`), regardless of whether you have a custom `timestamp` variable defined. **Best Practice:** ```javascript theme={null} // In pre-request script // This uses your custom variable if defined, otherwise falls back to dynamic const myTimestamp = "{{timestamp}}"; // This always generates a fresh dynamic timestamp const freshTimestamp = rq.$timestamp(); ``` > [!TIP] > > Use the `$` prefix (`{{$variableName}}` or `rq.$variableName()`) when you explicitly want to use a dynamic variable, even if a custom variable with the same name exists. # Create Request & Response Examples Source: https://docs.requestly.com/api-client/examples Save, manage, and reuse examples in Requestly. Create snapshots of your API requests with different configurations for quick reuse. Examples are a pairing of a request and its corresponding response. Each example captures the complete state of an API call, including the request details (method, URL, parameters, headers, and body) and the response details (status code, body, and headers). You can attach multiple examples to a single request, all organized under that parent request in the sidebar. This makes it easy to navigate between different scenarios without duplicating or modifying the original request. Having multiple examples for one request helps you represent how an API behaves in different situations. For instance, you can save examples for successful responses, error states like 400 or 404, or cases where the response data changes. ## Why Use Examples * **Test multiple scenarios**\ Save different configurations like valid inputs, edge cases, and error states, and switch between them instantly. * **Collaborate with your team**\ Examples are shared within your project so others can view and use the exact configurations. * **Retain request and response data**\ Each example stores both the request and its response, making it easy to revisit past executions. ## Save a request & responses as an example You can create an example from any HTTP or GraphQL request that has been sent at least once. Examples are not limited to those two protocols. Right-click a [gRPC](/api-client/send-api-request/grpc-request), [WebSocket](/api-client/send-api-request/websocket-request), [Socket.IO](/api-client/send-api-request/socketio-request) or [MQTT](/api-client/send-api-request/mqtt-request) request in the sidebar and choose **Add Example** to snapshot its configuration. The steps below use the **Save** dropdown, which HTTP, GraphQL, gRPC and MQTT requests have. WebSocket and Socket.IO requests have no such dropdown item, so the sidebar **Add Example** is the only route for those two. > [!NOTE] > > WebSocket, Socket.IO and MQTT hold an open connection rather than returning a single response, so their examples capture the request side only. **1. Open a request** Navigate to an existing API request in your project or send a new request. **2. Save as example** Click the **Save** dropdown in the request view and select **Save as example**. \ This stores the current configuration including URL, method, headers, parameters, and body. ![Save Examplesinrequestly](https://mintcdn.com/requestly/JKGigZziFcip1RUm/images/SaveExamplesinrequestly.png?fit=max\&auto=format\&n=JKGigZziFcip1RUm\&q=85\&s=4fa59a78a2576858fe354388673c0e0d) **3. View the example** The example opens in a new tab. The parent request in the sidebar expands to show the newly created example beneath it. ![View Examples](https://mintcdn.com/requestly/JKGigZziFcip1RUm/images/ViewExamples.png?fit=max\&auto=format\&n=JKGigZziFcip1RUm\&q=85\&s=f9c14056ed28f2d1539e782559257aac) > [!TIP] > > You can also save examples from the request's context menu in the sidebar by right-clicking the request and selecting the save option. ## Manage examples in the sidebar Examples appear as collapsible children under their parent request in the sidebar. Click the expand arrow next to any request to reveal its examples. ### Open an example Click on an example in the sidebar to open it in a new tab. The example loads with the saved request configuration and response data. ![Openanexample(1)](https://mintcdn.com/requestly/ngLDafOW0LQ7Vo0B/images/Openanexample\(1\).png?fit=max\&auto=format\&n=ngLDafOW0LQ7Vo0B\&q=85\&s=4c7978793af1a8864067386d9bceb178) ### Rename an example Right-click the example in the sidebar and select **Rename**, or double-click the example name. Type the new name and press **Enter** to save. ![Renameanexample](https://mintcdn.com/requestly/JKGigZziFcip1RUm/images/Renameanexample.png?fit=max\&auto=format\&n=JKGigZziFcip1RUm\&q=85\&s=b587a2b55acc1ec82a964fe42469293e) ### Duplicate an example Right-click the example in the sidebar and select **Duplicate**. A copy of the example is created under the same parent request. ![Duplicateanexample](https://mintcdn.com/requestly/JKGigZziFcip1RUm/images/Duplicateanexample.png?fit=max\&auto=format\&n=JKGigZziFcip1RUm\&q=85\&s=b33c88f0200617358b102efe7ba284b8) ### Delete an example Right-click the example in the sidebar and select **Delete**. Confirm the action in the prompt that appears. ![Deleteanexample](https://mintcdn.com/requestly/JKGigZziFcip1RUm/images/Deleteanexample.png?fit=max\&auto=format\&n=JKGigZziFcip1RUm\&q=85\&s=0d5c801aff5c307d542ca8ee91575028) > [!WARNING] > > Deleting an example is permanent and cannot be undone. ## Use an example as a template When viewing a saved example, click **Try it** in the URL bar to open a new draft request pre-filled with the example's configuration (URL, method, headers, parameters, and body). This lets you start a new request based on an existing example without modifying the original. The example's saved response is not carried into the draft. ![Useanexampleasatemplate](https://mintcdn.com/requestly/JKGigZziFcip1RUm/images/Useanexampleasatemplate.png?fit=max\&auto=format\&n=JKGigZziFcip1RUm\&q=85\&s=e84ae3de8a9b7857d9b3feb4e4b7bf67) ## What's next? > **[API Collections](/api-client/api-collections)** > > Organize your requests into collections and folders > **[Variables](/api-client/environments-and-variables)** > > Use variables to make requests reusable across environments > **[Scripts & Tests](/api-client/scripts)** > > Add pre-request scripts and tests to automate your workflow # Switch and create branches Source: https://docs.requestly.com/api-client/git/branches Open the branch picker from the Requestly sidebar to switch branches, create one, resolve uncommitted changes during a switch, and delete a branch you no longer need. Requestly shows the branch you are on in the sidebar status bar, and puts the whole branch list one click behind it. You can switch, create, and delete branches without a terminal. Git applies to [local projects](/api-client/git/overview#requirements) only, so the **Git** tab is hidden while a team project is active. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Open the branch picker The status bar at the bottom of the sidebar shows the current branch name, on every tab and not only on the **Git** tab. Click the branch name to open the **Branches** window. The window holds three parts, top to bottom: * A **Search branches** box. * The branch list. * A **Create branch** row. > [!NOTE] > > The branch name is not clickable while a merge or a rebase is in progress. Finish the merge first, then switch. ## Read the branch list Each row is one branch. | What you see | What it means | | - | - | | A green check at the left | The branch you are on. The row is not clickable, and it carries no delete action. | | A **DEFAULT** tag | The branch is named `main` or `master`. It is a marker, not an action. | | A trash icon on hover | Deletes that branch. See [Delete a branch](#delete-a-branch). | Type in **Search branches** to narrow the list by name. A search that matches nothing reads "No branches match." ![The Branches window listing four local branches, with a check beside main, a DEFAULT tag next to it, a search box above, and a Create branch row below](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-branch-picker.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=58196ce35a05079735f6780a7d3fe0c2) > [!NOTE] > > The list holds your local branches. A branch that exists only on the remote does not appear, and Requestly does not check one out. Pull instead, to bring the remote's commits into the branch you are on. ## Switch to another branch **1. Open the Branches window** Click the branch name in the sidebar status bar. **2. Pick the branch** Click the row you want. With a clean working tree, Requestly switches and closes the window. **3. Resolve uncommitted changes** With staged or unstaged changes in the tree, the **Uncommitted changes** dialog opens first. Choose how to handle them, as described below. While a switch runs, the window stays open and its controls are disabled. It closes on its own once the switch succeeds. ### When the working tree is not clean Switching would lose changes you have not committed, so Requestly asks first. The dialog reads "Switching to `` would lose your current changes. Stash them or discard?" and offers three buttons. | Button | What it does | | - | - | | **Stash & switch** | Stashes your changes, including untracked files, then switches. The stash is recorded as "WIP before switching to ``" and appears in the [Stashes section](/api-client/git/stashes) of the Git panel. | | **Discard** | Throws the uncommitted changes away and switches, in one step. | | **Cancel** | Leaves you on the current branch with your changes intact. | ![The Uncommitted changes dialog asking whether to stash or discard before switching to feature slash pet-search, with Cancel, Discard, and Stash and switch buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-checkout-dirty-modal.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=01c1cb7f35da4a5d2cd125a4f745244d) > [!WARNING] > > **Discard** cannot be undone. Git keeps no copy of uncommitted work, so use **Stash & switch** whenever you may want the changes back. ## Create a branch **1. Open the composer** Click **Create branch** at the bottom of the **Branches** window. **2. Name the branch** Type the name. Requestly checks it as you type and blocks **Create** until the name is valid. **3. Decide whether to switch** **Check out after creating** is selected by default, so the new branch becomes the current one. Clear it to create the branch and stay where you are. **4. Create** Click **Create**. The new branch starts from the commit you are on, and the window closes. ![The Branches window with the create composer open at the bottom, a new branch name typed in, the Check out after creating box selected, and Cancel and Create buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-branch-create-composer.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=222e3a5b2ac020ee5b7254eb9071dd95) ### Names Requestly refuses | What the field shows | Why | | - | - | | "Branch names cannot contain spaces." | The name holds a space. | | "Invalid branch name." | The name holds a character Git refuses (`~`, `^`, `:`, `?`, `*`, `[`, `\`), contains `..`, starts or ends with `/`, or ends with `.lock`. | | "A branch with that name already exists." | The repository already has that branch. The composer stays open so you can rename and retry. | ## Delete a branch **1. Reveal the delete action** Hover the branch you want to remove. The trash icon appears at the right of the row. The branch you are on has none, so switch away from a branch before deleting it. **2. Confirm** The **Delete branch** dialog asks "Delete branch ``? This can't be undone." Click **Delete**. ![The Delete branch dialog asking to delete the release slash v1 branch and warning that it cannot be undone, with Cancel and Delete buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-branch-delete-confirm.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=a5542614a4a3cb1ef37781115d55c430) **3. Force the delete if Git refuses** A branch holding commits that are not merged anywhere else cannot be deleted normally. The dialog becomes **Branch not fully merged** and offers **Force delete**, which removes the branch and its unmerged commits with it. > [!WARNING] > > **Force delete** discards the commits that live only on that branch. Merge or push them first if you want to keep them. The deleted branch leaves the list straight away, so you can delete several in one visit. ## Next steps > **[Browse history and diffs](/api-client/git/history-and-diffs)** > > Read a branch's commits on a graph, and open a read-only diff for a commit or a file. > **[Stage and commit changes](/api-client/git/commit-changes)** > > Read the change list, stage or discard files, and write a commit. # Stage and commit changes Source: https://docs.requestly.com/api-client/git/commit-changes Read the Git change list in the Requestly sidebar, stage or discard files by request or by collection, and record a commit without leaving the app. Every edit you make to a collection, a request, or an environment in a local project writes a file. The **Git** panel lists those files, lets you choose which ones go into the next commit, and records the commit for you. Git applies to [local projects](/api-client/git/overview#requirements) only, so the **Git** tab is hidden while a team project is active. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Read the change list Open the **Git** tab. When the working tree holds changes, the panel shows the commit box, then up to two collapsible sections. * **Changes (N)** lists the files you have edited but not staged. * **Staged (N)** lists the files that will go into the next commit. Each header carries one bulk action. **Changes** has **Stage all**, and **Staged** has **Unstage all**. A section appears only when it holds at least one file, so a fully staged tree shows **Staged** alone. The API Client sidebar also shows a badge on the **Git** tab icon. It counts every changed file in the project, staged and unstaged together. ![The Git panel with a typed commit message, a Staged section of seven files, and a Changes section of sixty-three files](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-panel-dirty.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=79694e550a00ff83447a095d1ccfea5e) ### The change tree Files are not a flat list. Requestly groups them the way you already think about them: a collection holds requests, and a request holds the files that store it. Expand a collection to see its requests, and expand a request to see its files. Files that live outside the collections folder, such as the project's own configuration, sit as their own rows at the top level of the tree, not inside a group. > [!TIP] > > Stage, unstage, and discard work at every level. Acting on a request folder covers every changed file inside it, so you can stage a whole request in one click. Hover a file row to reveal its actions. Collection and request rows keep their actions visible, so a whole group is always one click away. ![The Changes section grouped as a tree, with the Pets and Store collections holding requests, each request holding its files, and stage and discard icons on a hovered row](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-change-tree.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=e4678ad0451321a697412603ea2f0bbb) | Action | Where it appears | What it does | | - | - | - | | Plus icon | **Changes** rows | Stages the file, request, or collection. | | Minus icon | **Staged** rows | Unstages it again. | | Undo arrow | **Changes** rows | Discards the change. See [Discard a change](#discard-a-change). | > [!WARNING] > > Discarding a file Git has never tracked **deletes it from disk**, because there is no earlier version to restore. Click a file name to open its [diff](/api-client/git/history-and-diffs#open-a-diff) in a tab. From **Changes** the diff compares your working copy against what is staged. From **Staged** it compares what is staged against the last commit. ### Status letters A letter at the right of each file row states what changed. The letters are close to `git status --short`, with one difference: a file Git has never tracked reads as `U` here rather than `??`. | Letter | Meaning | | - | - | | `M` | Modified | | `A` | Added | | `D` | Deleted | | `R` | Renamed | | `U` | Untracked, or unmerged during a merge | A file that a merge left conflicted also carries a **conflict** badge next to its letter. See [Resolve merge conflicts](/api-client/git/resolve-conflicts). ## Discard a change Discarding throws away work that is not committed, and Git cannot bring it back. **1. Click the undo arrow** Find the file, request, or collection in **Changes** and click its undo arrow. **2. Read the confirmation** A dialog opens, headed **Discard changes to ``?**. For a single file it warns "This permanently discards your uncommitted changes to this file. It can't be undone." For a request or a collection it names the number of files instead, so you can see how wide the discard reaches. ![The Discard changes confirmation dialog for the List pets request, warning that it discards uncommitted changes to three files, with Cancel and Discard buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-discard-confirm.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=a43534347a8d501e5fef9f76133abe8e) **3. Confirm** Click **Discard** to throw the changes away, or **Cancel** to keep them. > [!WARNING] > > Discarding a request or a collection discards every changed file inside it. Check the file count in the dialog before you confirm. ## Write a commit **1. Stage what belongs in the commit** Stage individual files, or click **Stage all** on the **Changes** header. Staged files move to the **Staged** section. **2. Describe the change** Type a message in the **Commit message** box at the top of the panel. The box grows as you type. **3. Commit** Click **Commit changes**. Requestly records the commit on the current branch and clears the message box. If you click **Commit changes** with nothing staged, Requestly warns "No staged changes to commit. Stage a file first." and records nothing. Git refuses an empty commit, so stage at least one file first. Once the working tree is clean, the panel shows **Working tree clean** with the note "All changes are committed. New edits to collections, environments, and requests show up here to stage and commit." ## Next steps > **[Push and pull](/api-client/git/push-and-pull)** > > Send your commits to the remote and bring your teammates' work in. > **[Git overview](/api-client/git/overview)** > > The panel states, the sidebar status bar, and the messages Requestly shows. # Connect a project to Git Source: https://docs.requestly.com/api-client/git/connect-a-project Initialize a Git repository inside an existing local project, or clone a repository into a new local project, from the Requestly desktop app. There are two ways to put a local project under version control. Initialize a repository inside a project you already have, or clone an existing repository into a new project. Both start in the desktop app, and neither needs a terminal. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Prerequisites * A [local project](/collaboration/local-workspace). The **Git** tab does not appear while a team project is active. * The `git` command installed on your machine. ## Initialize an existing local project Use this path when the project already holds the collections you want to track. **1. Open the Git tab** Open the local project, then click **Git** in the API Client sidebar. **2. Initialize the repository** The panel shows the **No git repo** empty state, described as "Version-control your collections, environments, and requests." Click **Initialize git**. Requestly creates the repository in the project folder and names the first branch `main`. ![The Git panel before a repository exists, showing the No git repo empty state with an Initialize git button above the Commits, Stashes, Remotes, and Sync rows](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-panel-no-repo.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=b4a7423edee55d31e291766dc9a09780) **3. Make the first commit** The panel switches to the change list, with every project file waiting under **Changes**. Stage what you want to track and write a commit. See [Stage and commit changes](/api-client/git/commit-changes). **4. Add a remote** A new repository has no remote yet, so the **Sync** section reads "Add a remote to push your commits." Click **Set a remote** to open the [Remotes tab](/api-client/git/remotes) and add one. The **Sync** section and its **Set a remote** button are in the panel from the start, before any repository exists. Click the button before you initialize and the Remotes tab reads "Repository not initialized", so run the steps in order. > [!NOTE] > > Requestly leaves an existing Git identity alone, and fills a missing one from a connected GitHub account. With no GitHub account connected Requestly sets nothing, so Git falls back to whatever identity your machine already has; if your machine has none, set one with `git config --global user.name` and `git config --global user.email`. ## Clone a repository Use this path when the collections already live in a repository, for example one a teammate pushed. **1. Open the project switcher** Click the project name at the top left of the app. **2. Start a new local project** In the **Local projects** section, click **Add project**. If you have no local projects yet, the section shows a **Create a local project** button instead. Either one opens the **Add a local project** dialog with three options. **3. Choose Clone from Git** Select **Clone from Git**, described as "Clone a GitHub, GitLab, or URL repository into a new local project." Then click the **Clone from Git** button. ![The Add a local project dialog with three options, Clone from Git selected, and Cancel and Clone from Git buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-add-local-project-clone-option.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=e3161f44972f3b0911aecee06fe350f1) **4. Enter the repository URL** On the **Paste URL** tab, pick **HTTPS** or **SSH** and paste the repository URL. The toggle is guidance only, and the field accepts either kind. * **HTTPS**: Requestly injects the saved credential for that host. If none is saved, it asks you to [connect the account](/api-client/git/providers-and-authentication). * **SSH**: Git uses your own system SSH keys, so Requestly needs no credential. A URL that is neither raises "Invalid Git remote URL. Use an HTTPS or SSH URL." under the field. ![The Clone from Git dialog on the Paste URL tab, with an HTTPS repository URL, a chosen destination folder, and Back and Clone buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-clone-paste-url.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=9a7a1371a20134b41faa01ed83573f07) **5. Choose the destination folder** The second field is empty, with **Destination folder** as its placeholder text rather than a label above it. Click **Choose…** beside it and pick a folder in the system dialog. The placeholder gives way to the path you picked. Requestly never fills this in for you. **6. Clone** Click **Clone**. The dialog shows **Cloning…** while Git runs. Do not close the dialog during a clone. You can also browse the repositories of a GitHub or GitLab account instead of pasting a URL. Each provider adds its own tab to the same dialog, **Browse my GitHub repos** and **Browse my GitLab repos**. Picking a repository fills the URL field for you, and you still choose the destination folder. A tab whose account is not connected yet offers to connect it there and then. See [Providers and authentication](/api-client/git/providers-and-authentication). ### What happens after a clone Requestly looks for a Requestly project inside the repository it just cloned. | What Requestly finds | What happens | | - | - | | A `__requestly.json` file at the repository root | Requestly registers that folder as a project and opens it. | | A `__requestly.json` file in a subfolder | Requestly registers the shallowest matching subfolder and opens it. | | No `__requestly.json` anywhere | Requestly keeps the cloned files and offers to set up a project in them. | In the last case the dialog keeps its **Clone from Git** title and swaps its body for a panel headed "This repository isn’t a Requestly project yet". Click **Create new project here** and name the project. Requestly scaffolds it inside the cloned folder, and Git stays bound to the repository you cloned, so the remote, push, and pull keep working. Click **Cancel** to leave the files on disk and register nothing. ![The Clone from Git dialog reporting that the cloned repository is not a Requestly project yet, showing the cloned folder path with Cancel and Create new project here buttons](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-clone-no-project.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=3d5f6d6e3d725c30a3f80352476835f4) ## Next steps > **[Stage and commit changes](/api-client/git/commit-changes)** > > Read the change list, stage or discard files, and write a commit. > **[Push and pull](/api-client/git/push-and-pull)** > > Fetch from the remote, read the ahead and behind counts, and sync your work. # Browse history and diffs Source: https://docs.requestly.com/api-client/git/history-and-diffs Expand the Commits section of the Requestly Git panel to read a branch's history on a commit graph, and open a read-only diff tab for a commit or a changed file. The **Git** panel carries the current branch's history, and every commit and changed file in it opens as a read-only diff tab beside your requests. Reading what changed never leaves the app. Git applies to [local projects](/api-client/git/overview#requirements) only, so the **Git** tab is hidden while a team project is active. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Open the Commits section **Commits** is the first of the three sections below the file area of the **Git** panel, above **Stashes** and **Remotes**. Click its header to expand it, and click again to collapse. The number at the right of the header is how many commits the current branch's history holds. It renders only once the branch has at least one commit, so a branch with none shows the **Commits** header on its own. Requestly loads the history when you expand the section, so a collapsed section costs nothing. > [!NOTE] > > The three sections are hidden while a merge is in progress, because the panel gives the whole file area to resolving the conflict. ## Read the commit graph Expanded, the section draws the history as a graph, newest commit at the top. Each row is one commit. | Part of a row | What it shows | | - | - | | The dot and the coloured line at the left | Where the commit sits in the branch structure. A merge shows its lines joining. | | The short id | The first characters of the commit id, in a quiet monospace type. | | The message | The commit's first line. A long message is cut with an ellipsis, so hover it to read the whole thing. | | A green up arrow at the right | The commit is not on the remote yet. Hover it for "Pending to push". | > [!TIP] > > Rows work from the keyboard. Tab to a commit, then press Enter or Space to open its diff. ![The expanded Commits section showing a count of five in its header and five commit rows, each with a graph dot, a short id, a message, and an up arrow](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-commits-graph.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=138d55e4c382999a96ee59235bda7c22) Scroll the section to load older commits, fifty at a time, up to five hundred loaded at once. The history reloads on its own after you commit or pull while the section is open. Collapsing drops the loaded commits, and expanding again starts from the newest. ### When the section has nothing to show | What you see | What it means | | - | - | | "No commits yet" | The repository has no commits. Stage some files and write the first one, and the history starts here. | | An error message and a **Retry** button | The history could not be read. Click **Retry**. | ![The expanded Commits section on a branch with no commits, its header carrying no number and its body reading No commits yet](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-commits-empty.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=0f05c857095c9984a7f5540ee9eb3d1d) ## Open a diff Three places in the **Git** panel open a diff, and each one opens a tab beside your requests. | Where you click | What the diff shows | | - | - | | A commit in the **Commits** section | Every file that commit changed. | | A file name under **Changes** | Your working copy against what is staged. | | A file name under **Staged** | What is staged against the last commit. | A stash in the **Stashes** section opens the same kind of tab, for the files that stash captured. See [Stash changes](/api-client/git/stashes). The tab is named after what it holds: `Diff · 1a2b3c4` for a commit, and `Diff · ` for a single file. Several diffs can stay open at once, and closing the tab is how you dismiss one. ![A commit diff tab stacking one collapsible section per changed file, each headed with the file path and an A chip, with every line shown as an addition](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-diff-commit-tab.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=b7279de3bc2746ea588f8c0215960afe) > [!NOTE] > > A merge commit's diff shows what the merge brought in, measured against the branch it was merged into. Plain Git prints nothing at all for a merge commit, so this is the more useful answer. ## Read a diff A diff tab stacks one section per file. Each section starts with a header carrying the file path and a one-letter chip, and holds the line-by-line comparison below it. Click the header to collapse a file you have finished with. The chip uses the same letters as the change list, described under [Status letters](/api-client/git/commit-changes#status-letters). Hover it for the full word. One letter differs: a file Git has never tracked shows the letter `A` here, because a diff has nothing earlier to compare it against, though its tooltip still reads Untracked. | The file | What the comparison shows | | - | - | | Modified | The removed and added lines together, in one column. | | Added | Every line as an addition. | | Deleted | Every line as a removal. | | Binary, or larger than Requestly renders | A note in place of the comparison. Requestly does not load the content of such a file. | ![A single-file diff tab for a query params file, headed with its path and an M chip, showing the removed and added lines in one column beside the Git panel](https://mintcdn.com/requestly/K-Ztz5uJVTElPvBt/images/git-diff-file-tab.light.png?fit=max\&auto=format\&n=K-Ztz5uJVTElPvBt\&q=85\&s=8f3eca607d9b3bd64de0b4fab6f424a0) A diff is read-only. Nothing you do in the tab changes a file, stages anything, or touches a commit. ### When a diff has nothing to show A commit that changed no files reads "No file changes in this commit." A diff that cannot be read shows the reason and a **Retry** button. The [Git overview](/api-client/git/overview#messages-you-may-see) lists the messages Requestly can show, with what each one means. ## Next steps > **[Push and pull](/api-client/git/push-and-pull)** > > Send the commits carrying an up arrow to the remote, and bring your teammates' work in. > **[Switch and create branches](/api-client/git/branches)** > > Open the branch picker to switch, create, or delete a branch. # Overview Source: https://docs.requestly.com/api-client/git/overview Version-control a local project with Git from inside the Requestly desktop app: stage, commit, push, and pull your collections without leaving the editor. In a local project your collections, environments, and requests are plain files on disk. Requestly can track those files with Git for you. You stage, commit, push, and pull from a panel in the sidebar, so you do not need a terminal or a second Git client. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Requirements * The Requestly desktop app on macOS, Windows, or Linux. * A [local project](/collaboration/local-workspace). Git does not apply to team projects, whose data lives in the cloud rather than on your disk. The **Git** tab is hidden while a team project is active. * The `git` command installed on your machine. Requestly runs your own `git` binary rather than bundling one. ## Where Git lives in the app ### The Git tab The API Client sidebar shows a **Git** tab whenever a local project is active. A badge on the tab icon counts the files with changes. In multi-project view the badge adds up the changed files across every open local project. ![The API Client sidebar with the Git tab selected, a count badge on its icon, and the Git panel listing three changed files](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-sidebar-badge.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=f80de38084b3f2e703f2b2fef455cb3a) ### The Git panel Open the **Git** tab to see the panel for the active project. The project name sits at the top. Below it, the panel shows one of four states. | State | What you see | | - | - | | No repository yet | The **No git repo** empty state, with an **Initialize git** button. | | Clean | **Working tree clean**. Every change is committed. | | Changes pending | The commit box, then the **Staged (N)** and **Changes (N)** sections. | | Merge in progress | The [conflict resolution surface](/api-client/git/resolve-conflicts) replaces everything else in the panel. | In the first three states the **Commits**, **Stashes**, and **Remotes** rows sit below the file area, followed by the collapsible **Sync** section. All four are there before you initialize anything, so even the **No git repo** panel shows the whole stack. A merge in progress hides all four and gives the panel's whole height to the conflict. **Sync** has one exception. It is hidden on a repository you have just initialized, and comes back as soon as you make the first commit or add a remote. ![The Git panel on a clean working tree, showing the Working tree clean message above the Commits, Stashes, Remotes, and Sync rows](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-panel-clean.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=b93df333462cc9dc73a66bdeadde0061) ### The status bar A status bar sits at the bottom of the sidebar on every tab, not only on the **Git** tab. It shows: * The current branch name. Click it to open the [branch picker](/api-client/git/branches). * An amber dot when the working tree holds uncommitted changes. * The number of commits to push and to pull, next to an up arrow and a down arrow. Hover them for "N to push" and "N to pull". * A chevron that opens the **Sync** controls. On the **Git** tab the chevron expands the inline **Sync** section. On any other tab it opens the same controls in a small popover. Hover the branch name for a summary such as `On branch main · uncommitted changes`. While a merge or a rebase is in progress, the bar shows `(locked)` in place of the counts, and the branch picker does not open. ![The sidebar status bar showing the branch name main, an amber dot for uncommitted changes, the push and pull counts, and the Sync chevron](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-status-bar.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=20953b6b1d5fc7c936bf8f9e7d738c71) ### Multi-project view Git acts on one project at a time. In multi-project view the panel is informational only: * With no pending changes it shows **Git isn't available in multi-project view** and a **Switch project** button. * With one project holding changes it shows **Uncommitted changes in ``**, a **Changes** list, and an **Open ``** button. * With several projects holding changes it shows **Uncommitted changes in N projects** and a **Switch project** button. The **Changes** list is read-only. Each row still draws its plus and undo icons, but they are greyed out and do nothing here. Open a single project to stage, commit, push, or pull. ![The Git panel in multi-project view, with an Uncommitted changes banner, two file rows whose plus and undo icons are greyed out, and an Open Petstore API button](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-multi-project-one-dirty.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=c7f26e291b0dd9869f850a9907382749) ## What Requestly tracks Requestly tracks the project folder as it sits on disk. That includes your collections and requests under `apis/`, your environments, the project's `__requestly.json` marker, and any API Design files the project holds. The change list groups files by the collection and request they belong to. Files that live outside `apis/`, such as the project's own configuration, appear as their own rows at the top level of the change list. > [!WARNING] > > Requestly tracks everything in the project folder and does not create a `.gitignore` for you, so add one yourself for anything you do not want on the remote. Keep secrets in [Vault](/api-client/vault/vault) rather than in environment values. ## Messages you may see Git failures appear as a toast in the corner of the app. Some toasts carry an action button that fixes the problem in one click. | Message | What it means | What to do | | - | - | - | | "Git is not installed. Install Git, then restart Requestly." | Requestly could not find a `git` binary on your machine. | Click **Download Git**, install it, then restart Requestly. | | "Network error. Check your connection and try the operation again." | The fetch, pull, or push could not reach the remote. | Check your connection, then run the operation again. | | "Remote has commits you don't have locally. Pull first, then push." | Someone else pushed commits you do not have yet. | Click **Pull first**, resolve anything Git reports, then push. | | "The local project and the remote have unrelated histories (started separately). Merge them to combine both." | You initialized the project locally and then linked it to a remote that already had its own commits. | Click **Merge anyway** to combine both histories. Requestly never does this on its own. | | "Commit or stash your local changes before pulling." | The working tree is dirty, so the pull would overwrite your edits. | Commit the changes, or stash them, then pull. | | "Another git operation is in progress. Try again in a moment." | Two Git operations overlapped. | Wait for the first one to finish, then retry. | | "That remote URL isn’t supported. Use an https\:// or ssh remote URL." | The remote URL uses a transport Requestly refuses. | Enter an `https://` or `ssh` URL instead. | | "Your saved token for this remote was rejected. Update the token and try again." | The stored access token expired or was revoked. | Click **Update token** and enter a current one. | | "Resolve the remaining conflicts before continuing the merge." | The merge still has files you have not resolved. | Resolve every conflicted file, then continue. | > [!NOTE] > > A missing credential raises its own message with an **Add token** action. That action opens the credential form for the remote's host. ### While connecting an account Connecting a GitHub or GitLab account reports its failures in the dialog or panel you are working in, not as a toast. See [Providers and authentication](/api-client/git/providers-and-authentication) for the flows these belong to. | Message | What it means | What to do | | - | - | - | | "That token didn't work. Check it's correct and not expired." | The provider rejected the token you pasted. | Paste a current token, or create a new one. | | "This token is missing the required scope." | The token is valid but lacks a scope Requestly needs. The provider's own scope advice follows the message. | Create a token with the scopes named, then paste that one. | | "Could not validate the token. Try again." | The check could not complete. | Click **Validate & save** again. | | "Too many attempts right now. Try again in a moment." | The provider is rate-limiting the checks. | Wait a moment, then retry. | | "Couldn't reach the provider. Check your connection and try again." | The request to the provider failed. | Check your connection, then retry. | | "Sign-in is not set up for this provider yet. Use a personal access token instead." | Sign-in is unavailable for that provider in this build. | Connect with a personal access token. | | "Device sign-in is disabled for this app. Use a personal access token instead." | The provider has device sign-in switched off. | Connect with a personal access token. | | "The sign-in code expired. Get a new code to try again." | The code lapsed before you approved it. | Click **Get a new code**. | | "The sign-in was declined on the provider page." | The request was rejected on the provider's website. | Start the sign-in again and approve it. | | "The sign-in session ended. Try again." | The sign-in stopped before it finished. | Click **Try again**. | | "Something went wrong. Try again, or check your connection if it persists." | The provider answered in a way Requestly did not expect. | Retry. If it repeats, check your connection. | ### While browsing repositories The **Browse my GitHub repos** and **Browse my GitLab repos** tabs of the clone dialog report their own failures above the list. Each message names the provider whose tab you are on, so the GitLab tab shows the GitLab wording of the same message. | Message | What it means | What to do | | - | - | - | | "Your GitHub token is missing a required scope. Reconnect with the right scope." | The saved token cannot read your repository list. | Reconnect the account with a token carrying the scopes the provider asks for. | | "GitHub rate limit reached. Try again in a moment." | The provider is rate-limiting the listing. | Wait a moment, then search again. | | "Couldn't reach GitHub. Check your connection and try again." | The request to the provider failed. | Check your connection, then retry. | | "Could not load repositories. Try again." | The listing failed for another reason. | Retry. Paste the repository URL if it keeps failing. | When no credential is saved, the tab shows a connect prompt instead of an error. ### While browsing branches, commits, and diffs These report in the window, section, or tab you are working in, not as a toast. | Message | What it means | What to do | | - | - | - | | "Branch names cannot contain spaces." | The branch name you typed holds a space. | Remove the spaces. **Create** stays disabled until the name is valid. | | "Invalid branch name." | The name holds a character Git refuses, or a shape it refuses such as `..`, a leading or trailing `/`, or a `.lock` ending. | Use letters, digits, hyphens, underscores, and slashes between segments. | | "A branch with that name already exists." | The repository already has that branch. | Rename and create again. The composer stays open. | | "Could not create the branch." | The create failed for another reason. | Try again. If it repeats, check that the repository is not mid-merge. | | "Could not load commits. Check your connection and try again." | The **Commits** section could not read the history. | Click **Retry** on the section. | | "Could not load the diff. Check your connection and try again." | A diff tab could not read the file. | Click **Retry** in the tab. | ### While stashing, resolving conflicts, and editing remotes These report in the section, tab, or window you are working in, not as a toast. | Message | What it means | What to do | | - | - | - | | "Enter a valid git remote URL (HTTPS or SSH)." | The URL in the **Add remote** or **Edit remote URL** window is not a shape Requestly accepts. | Correct it. **Add** and **Save** stay disabled until the URL is valid. | | "Could not load the conflict" | A conflict editor tab could not read its file. The reason follows the heading. | Close the tab and open the file from the panel again. | | "Could not load the conflicted file. Check your connection and try again." | The request for the file's contents failed. | Close the tab and open the file again. | | "File too large to resolve here" | The file is binary, or larger than Requestly renders. | Click **Keep current version** to resolve the whole file with your copy. | > [!NOTE] > > A stash that applies with conflicts raises no toast. The conflicted file lands in the **Changes** list with a **conflict** badge. See [Stash changes](/api-client/git/stashes#when-an-apply-hits-conflicts). ## Next steps > **[Connect a project to Git](/api-client/git/connect-a-project)** > > Initialize a repository in an existing local project, or clone one into a new project. > **[Stage and commit changes](/api-client/git/commit-changes)** > > Read the change list, stage or discard files, and write a commit. > **[Push and pull](/api-client/git/push-and-pull)** > > Fetch from the remote, read the ahead and behind counts, and sync your work. > **[Providers and authentication](/api-client/git/providers-and-authentication)** > > Connect a GitHub or GitLab account, pick sign-in or a token, and reconnect when one is rejected. > **[Switch and create branches](/api-client/git/branches)** > > Open the branch picker to switch, create, or delete a branch, and handle a switch with uncommitted changes. > **[Browse history and diffs](/api-client/git/history-and-diffs)** > > Read the commit graph, and open a read-only diff for a commit or a changed file. > **[Stash changes](/api-client/git/stashes)** > > Park uncommitted work, apply it back later, drop it, and resolve an apply that conflicts. > **[Resolve merge conflicts](/api-client/git/resolve-conflicts)** > > Work through a merge that stopped on conflicting files, finish it, or abort it. > **[Manage remotes](/api-client/git/remotes)** > > See the repository your project pushes to, add one, correct its URL, or remove it. # Providers and authentication Source: https://docs.requestly.com/api-client/git/providers-and-authentication Connect a GitHub or GitLab account to the Requestly desktop app, sign in by OAuth or a personal access token, browse your repositories, and reconnect when a credential is rejected. Pushing and pulling over HTTPS needs a credential for the remote's host. Requestly stores one per host and hands it to Git for you. Connect an account once, and clone, push, and pull work without a terminal prompt. Git applies to [local projects](/api-client/git/overview#requirements) only, so the **Git** tab is hidden while a team project is active. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Which accounts you can connect Requestly connects two providers: **GitHub** on `github.com` and **GitLab** on `gitlab.com`. Each keeps its own credential, and each host holds exactly one credential at a time. Self-managed GitLab and GitHub Enterprise hosts are not offered as connectable accounts. Clone those over SSH instead: Git uses your own system SSH keys, so Requestly stores nothing. > [!NOTE] > > Only HTTPS remotes need a saved credential. An SSH remote never asks you for one, and never prompts your operating system for keychain access. ## Open the Git providers page Your connected accounts live in **App Settings → Git providers**, in the same settings group as **SSL certificates** and **Vault**. The page is headed "Git providers", with the line "Manage the git accounts you've connected for HTTPS push and pull." > [!NOTE] > > This page does not need a local project open. It appears whenever Git is available in the desktop app, unlike the **Git** tab in the API Client sidebar, which appears only while a local project is active. ## Read the connected accounts list The page shows a **Connected accounts** section with the note "Each provider keeps its own credential. Select one to view or manage it." Each provider sits on its own row with a radio button, its name, and its live status at the right. | Status | What it means | | - | - | | **Not connected** | No credential is saved for that host. | | **Connected as @``** | A credential is saved, and Requestly knows the account it belongs to. | | **Connected** | A credential is saved, but no username was recorded with it. | Select a provider to open its panel below the list. The panel is where you connect, switch method, or remove the credential. ## Connect an account Both providers accept two methods: sign in with OAuth, or paste a personal access token. An unconnected provider shows them as two tabs, **Personal access token** and a sign-in tab named for the provider: **Sign in with GitHub OAuth** or **Sign in with GitLab OAuth**. ### Sign in with OAuth Signing in avoids creating and pasting a token. Requestly shows you a short code, you approve it on the provider's website, and the app picks the result up on its own. **1. Start the sign-in** On the provider's panel, open the **Sign in with GitHub OAuth** or **Sign in with GitLab OAuth** tab and click the button of the same name. A dialog opens and reports that it is contacting the provider. **2. Read the code** The dialog shows a short code in large type, above the line "Waiting for you to approve in the browser…". A countdown reads "Code expires in ``". Keep the dialog open. **3. Approve it on the provider** Click **Copy code & open GitHub** or **Copy code & open GitLab**. Requestly copies the code and opens the provider's device page in your browser. Compare the code on that page against the one in the dialog, then approve the sign-in. **4. Let Requestly finish** The dialog closes on its own once the provider reports the approval. The provider's panel now shows an **OAuth · signed in** badge and your username. > [!TIP] > > If the countdown runs out, the dialog reads "This code has expired" and offers **Get a new code**. Click it to start a fresh code rather than reopening the dialog. ### Connect with a personal access token Use a token when you prefer to control the scopes yourself, or when sign-in is unavailable for the provider. **1. Open the token tab** On the provider's panel, open the **Personal access token** tab. It reads "Paste a personal access token to connect this account." **2. Create the token** Click **Create a token on GitHub** or **Create a token on GitLab**. Requestly opens the provider's token page in your browser. Grant the scopes in the table below, then copy the token. **3. Paste and save** Paste the token into the field and click **Validate & save**. Requestly checks the token against the provider before it saves anything. A token that fails the check is never stored. ### Token scopes | Provider | Scopes the token needs | Field hint | | - | - | - | | GitHub | `repo` | `ghp_...` | | GitLab | `read_api` and `write_repository` | `glpat-...` | How each provider is checked differs, and it is worth knowing where a mistake surfaces. * **GitHub.** A classic token without the `repo` scope is rejected as you save it. A fine-grained token does not report its scopes, so Requestly accepts it and a missing permission surfaces later, when a clone or push fails. * **GitLab.** Requestly checks for `read_api` and rejects a token without it. It does not check `write_repository` at save time, so a read-only token connects successfully and then fails on your first push. ## Switch how you connect A host holds one credential, so choosing the other method replaces the one you have. A connected account carries a secondary link under its badge: **Use a personal access token instead** on a signed-in account, and **Sign in with GitHub OAuth instead** or **Sign in with GitLab OAuth instead** on a token account. Clicking it asks you to confirm, in a dialog headed "Switch how you connect to ``?". > [!WARNING] > > The replacement happens only once the new method connects. If you cancel the new sign-in or the new token fails validation, your existing credential stays in place. ## Disconnect or forget an account The action on a connected panel depends on how you connected. | Button | Shown when | What it does | | - | - | - | | **Disconnect** | You signed in with OAuth | Removes the saved sign-in from this machine. On GitLab, Requestly also asks GitLab to revoke the token. | | **Forget** | You pasted a token | Removes the saved token from this machine. The token itself stays valid on the provider. | Both ask you to confirm first, and both leave your repositories and commits untouched. They remove only the stored credential, so the next HTTPS push or pull asks you to connect again. > [!WARNING] > > Disconnecting a GitHub account clears it on this machine only. The authorization stays listed in your GitHub account settings until you revoke it there yourself. ## Where Requestly keeps your credentials Your token or sign-in stays on your own machine, inside the desktop app's encrypted store, protected by your operating system's keychain. It is never sent to Requestly's servers and never appears in a project file. * Requestly reads the credential only while running a Git command against an HTTPS remote, and passes it to that one command. It is never written into the repository's Git configuration, so a teammate who clones your project never receives it. * The keychain prompt appears the first time you open the **Git providers** page, or the first time you run an HTTPS Git command. It does not appear when the app launches. * When no keychain is available, the account reads **Saved for this session only** instead of **Saved**. That credential is lost when you quit, and you connect again on the next start. * A GitLab sign-in is renewed for you before a Git command runs, so a signed-in GitLab account keeps working without any action from you. ## Browse your repositories when cloning Once an account is connected, you can pick a repository from a list instead of pasting its URL. Every provider adds its own tab to the **Clone from Git** dialog, **Browse my GitHub repos** and **Browse my GitLab repos**, described in [Connect a project to Git](/api-client/git/connect-a-project). An unconnected provider shows "Connect GitHub to browse your repos", or the same line naming GitLab, on that tab, with **Sign in with GitHub** or **Sign in with GitLab** and **Use a personal access token** buttons. Both connect the account without leaving the dialog, and the list loads as soon as they succeed. A connected provider shows: * A **Search repositories** box. Typing filters the repositories that account can reach on the provider. * One row per repository, with a lock icon on private ones, the `owner/repo` name, when it was last updated, and a **Clone** button. * A **Load more** button under the list when the account has more repositories than the page holds. * "No repositories found" when nothing matches your search. Clicking **Clone** on a row fills the repository's HTTPS URL into the **Paste URL** tab. You still choose the destination folder yourself, and then start the clone from there. ## When Requestly asks you to reconnect A push, pull, or fetch fails when no credential is saved for the remote's host, or when the saved one is rejected. The toast that reports it carries an action: **Add token** when nothing is saved, and **Update token** when the stored credential was rejected. **1. Click the action on the toast** Requestly opens the credential surface for that remote's host, headed "Connect to ``" or "Reconnect to ``". A rejected token reads "Your saved token for this remote was rejected. Paste a new personal access token to continue." **2. Reconnect** If the host is connected by sign-in, Requestly offers to sign in again rather than asking for a token. Otherwise, paste a new token and confirm. **3. Let the operation retry** Requestly runs the failed push, pull, or fetch again for you as soon as the credential is saved, and closes the dialog. You do not repeat the action yourself. > [!NOTE] > > This prompt appears only for remotes on `github.com` and `gitlab.com`. Any other HTTPS host has no saved-credential path in Requestly, so use an SSH remote for it. If the sign-in fails partway, the dialog shows what went wrong and offers both **Try again** and **Use a personal access token instead**. The [Git overview](/api-client/git/overview#messages-you-may-see) lists every message you can meet, with what each one means. ## Next steps > **[Connect a project to Git](/api-client/git/connect-a-project)** > > Initialize a repository in an existing local project, or clone one into a new project. > **[Push and pull](/api-client/git/push-and-pull)** > > Fetch from the remote, read the ahead and behind counts, and sync your work. # Push and pull Source: https://docs.requestly.com/api-client/git/push-and-pull Use the Sync section of the Requestly Git panel to fetch from the remote, read the ahead and behind counts, and push or pull a local project's commits. Once a local project has commits and a remote, the **Sync** section moves work between your machine and the remote. It is the only place you need for fetch, pull, and push. Git applies to [local projects](/api-client/git/overview#requirements) only, so the **Git** tab is hidden while a team project is active. > [!NOTE] > > Git requires the **desktop app**. [Download Requestly](https://requestly.com/downloads). ## Open the Sync section **Sync** is the last section of the **Git** panel, below **Commits**, **Stashes**, and **Remotes**. Click its header to expand or collapse it. The same controls are reachable from any sidebar tab. The status bar at the bottom of the sidebar carries a chevron on the right. On the **Git** tab it expands the inline **Sync** section. On every other tab it opens the same controls in a small popover, so you never have to switch tabs to push. ![A diff tab open on the Collections tab, with the Sync popover above the status bar showing origin slash main, Fetch, the behind and ahead counts, and Pull and Push buttons](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-sync-popover.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=4ee8496b0af83020fd6fef284c433e09) > [!NOTE] > > **Sync** is hidden in two cases: a repository you have just initialized, with no commits and no remote yet, and a repository with a merge in progress. It comes back once you commit, add a remote, or finish the merge. ## Add a remote first A repository you initialized in Requestly has no remote yet. **Sync** then reads "Add a remote to push your commits." and offers one action, **Set a remote**, which opens the [Remotes tab](/api-client/git/remotes). The same nudge is what the panel shows before you have a repository at all, so it is not a sign that the initialization worked. A repository you cloned already has its remote, so **Sync** is ready to use. ![The Sync section of the Git panel with no remote set, reading Add a remote to push your commits above a Set a remote button](https://mintcdn.com/requestly/eF9SdqtaJHfrCNE2/images/git-sync-no-remote.light.png?fit=max\&auto=format\&n=eF9SdqtaJHfrCNE2\&q=85\&s=65532240b59519d555b642f21c176da1) ## Read the sync state With a remote configured, **Sync** shows four things. | What you see | What it tells you | | - | - | | The upstream name, such as `origin/main` | The branch your commits go to. Before the first push it reads `origin`, because the branch has no upstream yet. | | "Last fetched `
{{#each users}} {{/each}}
NameEmail
{{name}}{{email}}
`; rq.visualizer.set(template, { users: rq.response.json() }); ``` > [!NOTE] > > Each call to `set()` replaces the previous visualization. If it runs more than once, including across a pre-request and a post-response script, the last call to run wins. ## Viewing the visualization After a post-response script calls `rq.visualizer.set()`, a **Visualize** button appears beside the format selector in the response **Body** area. Send the request, then click **Visualize** to switch the body view to your rendered visualization. ![A rendered table visualization in the response Body area, with the Visualize button active beside the format selector](https://mintcdn.com/requestly/N1-D_l3TIcV8SSC5/images/rq-visualizer/visualize-rendered.light.png?fit=max\&auto=format\&n=N1-D_l3TIcV8SSC5\&q=85\&s=c372fc4f69c6168f4ebec7df3cd72955) Until a script sets a visualization, the **Visualize** button stays disabled. Hover it to see how to turn it on. When the visualization is showing, two more actions appear beside it: * **Refresh** re-renders the current visualization without sending the request again. Use it to re-run a chart's animation or reload the visualization from its captured data. * **View Script** opens the post-response **Scripts** tab, where your `rq.visualizer.set()` call lives. Switching the format selector back to Raw, Hex, or Base64 returns the body to its normal view. ## Reading your data inside the visualization There are two ways to get your `data` into the rendered output: 1. **Handlebars expressions.** Anything in `{{ ... }}` renders against the `data` you passed to `set()`. This is the simplest path for tables and text. 2. **`rq.getData`.** Call it inside a ` `; rq.visualizer.set(template, { labels: ["Mon", "Tue", "Wed"], values: [12, 19, 7], }); ``` ## rq.visualizer.clear() Removes the current visualization and returns the **Visualize** button to its disabled state. Use it to hide a stale visualization when the response does not warrant one. **Parameters:** none. ```jsx theme={null} // Post-response script if (rq.response.code !== 200) { rq.visualizer.clear(); } ``` ## How the visualization is isolated Your visualization runs in a sandboxed frame that is separated from the rest of Requestly. Inside it you can load scripts from a CDN and use inline event handlers, but the frame cannot read or change the app around it, your cookies, or your other data. If a CDN script fails to load, the failure stays contained in the frame and does not affect Requestly. ## When something goes wrong If your template cannot be compiled (for example a Handlebars syntax error), or your `data` cannot be turned into JSON (for example it contains a circular reference or a `BigInt`), Requestly shows a short **Template error** message in place of the visualization instead of a blank body. A **View Script** button sits next to the message so you can jump straight to the script and fix it. ## Using Postman visualizer scripts If you import a Postman collection whose scripts call `pm.visualizer.set()`, Requestly translates them to `rq.visualizer.set()` automatically, so your visualizations work without editing the script. Inside the visualization, `pm.getData` works alongside `rq.getData`, so Postman visualization templates render unchanged. ## Related Documentation * [Pre-request & Post-response Scripts](/api-client/scripts) * [Scripts Reference Overview](/api-client/rq-api-reference/overview) * [rq.response Object](/api-client/rq-api-reference/rq-response) * [rq.test Object](/api-client/rq-api-reference/rq-test) * [Import from Postman](/api-client/import-export/import-from-postman) # Run on CI/CD Source: https://docs.requestly.com/api-client/run-on-cicd Generate a ready-to-commit GitHub Actions, GitLab CI, Jenkins, or Azure Pipelines file that runs your collections with the Requestly CLI. **Run on CI/CD** turns the collections you already run in the app into a pipeline file you can commit. You pick the collections, the CI provider, the runner's operating system, and which reports you want, and Requestly writes the whole file: downloading the CLI, running each collection in order, and wiring the results into your provider's own test reporting. Nothing runs inside Requestly. The output is a text file you copy into your repository, and every command in it is a [Requestly CLI](/api-client/cli) invocation you could have typed yourself. > [!NOTE] > > **Availability:** Run on CI/CD is rolling out gradually, so if the **Run in CLI** sub-tab is missing from a collection's Runner tab, contact support to confirm it is enabled for your account. CLI runs are not available for browser-based projects: open the project in the desktop app, or use a cloud project. ## Open the generator **1. Open the collection's Runner tab** In the Collections sidebar, select the collection you want to run in CI, then open its **Runner** tab. **2. Switch to the Run in CLI sub-tab** The Runner tab has three sub-tabs: **Manual**, **Scheduled**, and **Run in CLI**. **Manual** is the on-demand [Collection Runner](/api-client/collection-runner) and **Scheduled** holds this collection's [Scheduled Runs](/api-client/scheduled-runs). Select **Run in CLI**. This sub-tab shows the single command that runs this one collection from your terminal. A cloud project also shows the two environment variables the command needs; a local project needs none. ![The Run in CLI sub-tab of a collection's Runner tab, showing the generated CLI command and the Run on CI/CD section at the bottom.](https://mintcdn.com/requestly/EsE_M9m9tAS3x-EQ/images/cicd-run-in-cli-panel.light.png?fit=max\&auto=format\&n=EsE_M9m9tAS3x-EQ\&q=85\&s=74a2e09d4bd1a1679913e7e0762a9b49) **3. Select Configure command** At the bottom of the sub-tab, under **Run on CI/CD**, select **Configure command**. The generator opens as its own tab with this collection already filled in as the first row. There is one generator tab per project. Opening it from another collection's Runner adds that collection to the list rather than opening a second tab. ## Configure the file The generator is a form on the left and a live preview on the right. There is no **Generate** button: every edit rewrites the file on the right immediately. ![The Run on CI/CD generator, with the collections table, provider, operating system, and reports controls on the left and the generated pipeline file previewed on the right.](https://mintcdn.com/requestly/EsE_M9m9tAS3x-EQ/images/cicd-generator.light.png?fit=max\&auto=format\&n=EsE_M9m9tAS3x-EQ\&q=85\&s=d1f825e567ab22695c84a4c6df6d9391) ### Collections to run The **Collections to run** table is the list of targets the pipeline executes, in order. Each row picks one collection and, optionally, one environment. * **Add collection** appends a row. * Drag a row by its grip, or use **Move up** / **Move down** in the row's **More actions** (…) menu, to change the order. The order is the execution order. * The same collection can appear more than once as long as each row picks a different environment. An exact repeat is refused with "This collection is already in the list with that environment." * The list can never be emptied. Removing the last row is refused with "A pipeline needs at least one collection to run." Iterations and inter-request delay are not set here. Each row carries the iteration count and delay already saved in that collection's run configuration in the [Collection Runner](/api-client/collection-runner), so the pipeline and the app agree. Values at their defaults are left out of the command entirely. If a row names a collection that has since been deleted, the preview is withheld rather than quietly generating a smaller pipeline. The preview shows **No file to generate** with a button that jumps straight to the broken row. In a local project the preview is also withheld when a collection's folder cannot be determined, or when the folder name contains a quote, `$`, a backtick, or a backslash. Reopen the project, or rename the folder, then the preview returns. ### CI/CD provider Pick the system that will run the file. Each option also names the path the file belongs at in your repository: | Provider | Save the file as | | - | - | | GitHub Actions | `.github/workflows/api-tests.yml` | | GitLab CI | `.gitlab-ci.yml` | | Jenkins | `Jenkinsfile` | | Azure Pipelines | `azure-pipelines.yml` | The same path is shown above the preview as **Save as**, so you can copy the file and know where it goes without switching back to the form. ### Operating system for CI/CD This is the machine your pipeline runs on, not your own laptop. It decides which CLI build the install block downloads, which shell verbs it uses, and which runner the file targets. On GitLab the runner tag is a GitLab.com SaaS tag; on self-managed GitLab, swap it for your own runner's tag. The options are **Linux x64** (the default, and the standard runner image on all four providers), **Linux arm64**, **macOS x64**, **macOS arm64**, and **Windows x64**. ### Reports **Reports** selects which reporters every target runs with: | Report | What it produces | | - | - | | Terminal output | The run log in your CI console. Always on and cannot be turned off. | | JSON report | Machine-readable results, kept as a build artifact. | | JUnit report | The format CI providers read as test results. | | HTML report | A browsable report, kept as a build artifact. | | BrowserStack Test Reporting & Analytics | Uploads results to BrowserStack. Writes no file. | Nothing but Terminal output is selected to begin with. Pick at least JUnit if you want results in your provider's test view; the examples below all have JUnit selected. ![The Reports multi-select in the Run on CI/CD generator, open to show the five report options with their descriptions and the locked Terminal output entry.](https://mintcdn.com/requestly/EsE_M9m9tAS3x-EQ/images/cicd-generator-reports.light.png?fit=max\&auto=format\&n=EsE_M9m9tAS3x-EQ\&q=85\&s=8c2275392309827a2cd0e0a7297f6632) Terminal output is locked on for a reason: naming any reporter on the CLI replaces the default set instead of adding to it, so a run configured for files only would write its reports and print nothing at all, leaving a green build with an empty log. Test Reporting & Analytics is available in cloud projects only. In a local project the option is locked from the moment the generator opens, and the form explains why: the results would land in Test Reporting as a standalone build with no link back to this collection. Each file reporter writes one file per target, named after the target's position in the list: `rq-reports/1-checkout.xml`, `rq-reports/2-payments.xml`, and so on. That numbering is what stops two targets overwriting each other's report. ## Credentials A pipeline that runs cloud collections authenticates with two environment variables, `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY`. The generated file references them by name and never contains a credential value, so it is safe to commit. You add the values in your CI provider before the first run: | Provider | Where to add them | | - | - | | GitHub Actions | Repository **Settings → Secrets and variables → Actions** | | GitLab CI | Project **Settings → CI/CD → Variables**, masked. Use the exact names above. | | Jenkins | **Manage Jenkins → Credentials**, as two "Secret text" entries with the IDs `browserstack-username` and `browserstack-access-key` | | Azure Pipelines | Pipeline **Edit → Variables**, each marked secret | On Jenkins the credential IDs are lowercase and hyphenated, not the variable names. The access key is your personal BrowserStack credential, so anyone who can run the pipeline runs as you. In a local project the generator says **No credentials needed** instead: the collections come off the checked-out repository, so the file references no secret and there is nothing to configure in your provider. ## Copy and commit Use the copy control in the preview toolbar to put the whole file on the clipboard, then save it at the path shown in the **Save as** label and commit it. The preview is read-only and searchable, so you can review the file before you take it. ## What the generated file looks like Every file installs the CLI, runs each target in order, and collects whatever report files you selected. GitHub, Jenkins, and Azure install once and collect once at the end; GitLab makes each target its own job, so it installs the CLI and attaches its reports per job. ```yaml GitHub Actions theme={null} name: API tests on: [push] env: # Raise this one line to upgrade the CLI. RQ_CLI_VERSION: 1.61.1 jobs: run: runs-on: ubuntu-latest steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Install Requestly CLI run: | curl -fsSL --retry 5 -O https://sdk-assets.browserstack.com/binary-linux-x64-$RQ_CLI_VERSION.zip unzip -q binary-linux-x64-$RQ_CLI_VERSION.zip mv binary-linuxstatic-x64 browserstack-binary chmod +x browserstack-binary ./browserstack-binary requestly --version # Target 1 — Collection: Checkout · Environment: production - name: Checkout / production run: | ./browserstack-binary requestly collection run 34a9-checkout --project pj_8812 --environment env_prod --iteration-count 3 --delay-request 250 -r cli,junit --reporter-junit-export rq-reports/1-checkout.xml env: BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} # Target 2 — Collection: Payments · Environment: staging # `if: !cancelled()` runs this target even if target 1 failed. The job still # fails if any target failed — every target runs, the build gates on the # aggregate. Cancelling the run still stops the targets that have not started. - name: Payments / staging if: '!cancelled()' run: | ./browserstack-binary requestly collection run 7f21-payments --project pj_8812 --environment env_stg -r cli,junit --reporter-junit-export rq-reports/2-payments.xml env: BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} # GitHub stores this report as a build artifact but does not render it — an # uploaded artifact is not a test report. To see results in the run summary, # either add a JUnit reporting action from the GitHub Marketplace (we # deliberately do not pick one for you — vetting a third-party action is your # call), or write your own summary to $GITHUB_STEP_SUMMARY. - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: always() with: name: rq-reports path: rq-reports/*.xml if-no-files-found: warn ``` ```yaml GitLab CI theme={null} stages: - api-tests variables: # Raise this one line to upgrade the CLI. RQ_CLI_VERSION: '1.61.1' # Set these as MASKED CI/CD variables in Settings › CI/CD › Variables. BROWSERSTACK_USERNAME: $BROWSERSTACK_USERNAME BROWSERSTACK_ACCESS_KEY: $BROWSERSTACK_ACCESS_KEY # Each target below is its own job in the one stage, so they all run independently # and the pipeline fails if any of them fails. GitLab reaches run-all-then-gate with # no explicit condition — there is nothing here to switch off. # Target 1 — Collection: Checkout · Environment: production api-tests-1: stage: api-tests image: ubuntu:latest # Each job runs in its own container, so each one installs the CLI. before_script: - curl -fsSL --retry 5 -O https://sdk-assets.browserstack.com/binary-linux-x64-$RQ_CLI_VERSION.zip - unzip -q binary-linux-x64-$RQ_CLI_VERSION.zip - mv binary-linuxstatic-x64 browserstack-binary - chmod +x browserstack-binary - ./browserstack-binary requestly --version script: - ./browserstack-binary requestly collection run 34a9-checkout --project pj_8812 --environment env_prod --iteration-count 3 --delay-request 250 -r cli,junit --reporter-junit-export rq-reports/1-checkout.xml artifacts: when: always reports: junit: rq-reports/*.xml # Target 2 — Collection: Payments · Environment: staging api-tests-2: stage: api-tests image: ubuntu:latest # Each job runs in its own container, so each one installs the CLI. before_script: - curl -fsSL --retry 5 -O https://sdk-assets.browserstack.com/binary-linux-x64-$RQ_CLI_VERSION.zip - unzip -q binary-linux-x64-$RQ_CLI_VERSION.zip - mv binary-linuxstatic-x64 browserstack-binary - chmod +x browserstack-binary - ./browserstack-binary requestly --version script: - ./browserstack-binary requestly collection run 7f21-payments --project pj_8812 --environment env_stg -r cli,junit --reporter-junit-export rq-reports/2-payments.xml artifacts: when: always reports: junit: rq-reports/*.xml ``` ```groovy Jenkins theme={null} pipeline { agent any environment { // Raise this one line to upgrade the CLI. RQ_CLI_VERSION = '1.61.1' BROWSERSTACK_USERNAME = credentials('browserstack-username') BROWSERSTACK_ACCESS_KEY = credentials('browserstack-access-key') } stages { stage('Install Requestly CLI') { steps { sh ''' curl -fsSL --retry 5 -O https://sdk-assets.browserstack.com/binary-linux-x64-$RQ_CLI_VERSION.zip unzip -q binary-linux-x64-$RQ_CLI_VERSION.zip mv binary-linuxstatic-x64 browserstack-binary chmod +x browserstack-binary ./browserstack-binary requestly --version ''' } } stage('Checkout / production') { steps { // Target 1 — Collection: Checkout · Environment: production // EVERY target is wrapped, target 1 included. A bare `sh` that exits non-zero // aborts its stage AND the rest of the pipeline, so without this the first // failure would hide every target after it. The build still gates on the // aggregate: `buildResult` reddens it. // ALL THREE arguments are load-bearing. `stageResult` defaults to SUCCESS, so // dropping it reports a GREEN stage over a failed collection. `catchInterruptions` // defaults to TRUE, which swallows an ABORT too — cancelling would not cancel. catchError(buildResult: 'FAILURE', stageResult: 'FAILURE', catchInterruptions: false) { sh ''' ./browserstack-binary requestly collection run 34a9-checkout --project pj_8812 --environment env_prod --iteration-count 3 --delay-request 250 -r cli,junit --reporter-junit-export rq-reports/1-checkout.xml ''' } } } stage('Payments / staging') { steps { // Target 2 — Collection: Payments · Environment: staging catchError(buildResult: 'FAILURE', stageResult: 'FAILURE', catchInterruptions: false) { sh ''' ./browserstack-binary requestly collection run 7f21-payments --project pj_8812 --environment env_stg -r cli,junit --reporter-junit-export rq-reports/2-payments.xml ''' } } } } post { always { junit allowEmptyResults: true, testResults: 'rq-reports/*.xml' } } } ``` ```yaml Azure Pipelines theme={null} trigger: [main] pool: vmImage: ubuntu-latest variables: # Raise this one line to upgrade the CLI. RQ_CLI_VERSION: 1.61.1 steps: - script: | curl -fsSL --retry 5 -O https://sdk-assets.browserstack.com/binary-linux-x64-$(RQ_CLI_VERSION).zip unzip -q binary-linux-x64-$(RQ_CLI_VERSION).zip mv binary-linuxstatic-x64 browserstack-binary chmod +x browserstack-binary ./browserstack-binary requestly --version displayName: Install Requestly CLI # Target 1 — Collection: Checkout · Environment: production - script: | ./browserstack-binary requestly collection run 34a9-checkout --project pj_8812 --environment env_prod --iteration-count 3 --delay-request 250 -r cli,junit --reporter-junit-export rq-reports/1-checkout.xml displayName: Checkout / production env: BROWSERSTACK_USERNAME: $(BROWSERSTACK_USERNAME) BROWSERSTACK_ACCESS_KEY: $(BROWSERSTACK_ACCESS_KEY) # Target 2 — Collection: Payments · Environment: staging # `condition: succeededOrFailed()` runs this target even if target 1 failed. # The job still fails, because a failed task fails the job — every target runs, # the build gates on the aggregate. Cancelling the run still stops the rest. - script: | ./browserstack-binary requestly collection run 7f21-payments --project pj_8812 --environment env_stg -r cli,junit --reporter-junit-export rq-reports/2-payments.xml displayName: Payments / staging condition: succeededOrFailed() env: BROWSERSTACK_USERNAME: $(BROWSERSTACK_USERNAME) BROWSERSTACK_ACCESS_KEY: $(BROWSERSTACK_ACCESS_KEY) # With @requestly/cli 1.1.6 and earlier, a request that fails at TRANSPORT (an # unreachable host, a DNS failure) reddens the build through the run's exit code, # but does not show up in the Tests tab below: the report carries a suite with no # test-case children for it, and Azure recomputes a run from its children. For # those, the build log is the source of truth. Later releases add an # test case for it, so it does show up. - task: PublishTestResults@2 condition: always() inputs: testResultsFormat: JUnit testResultsFiles: rq-reports/*.xml testRunTitle: Checkout, Payments # failTaskOnMissingResultsFile defaults to false — a missing report warns. ``` > [!TIP] > > The CLI version appears on exactly one line, as `RQ_CLI_VERSION`. Raise it there to upgrade every target at once; the [CLI page](/api-client/cli#installation) lists the versions available. ### Every target runs, then the build gates on the aggregate A failing collection does not stop the ones after it. Each provider reaches that behavior in its own way: GitHub uses `if: '!cancelled()'`, Azure uses `condition: succeededOrFailed()`, Jenkins wraps each stage in `catchError`, and GitLab gets it for free because each target is a separate job. > [!NOTE] > > Every target runs even when an earlier one fails, and the build still fails if any target failed. Cancelling the pipeline still stops the targets that have not started. ### Where the results show up How the JUnit report is surfaced depends on the provider: | Provider | JUnit handling | | - | - | | GitLab CI | Published as test results through `artifacts:reports:junit`. | | Jenkins | Published by a `junit` step in the pipeline's `post` block. | | Azure Pipelines | Published by `PublishTestResults@2`, with the run titled after the collections in the file. | | GitHub Actions | Uploaded as a build artifact only. | JSON and HTML reports are kept as build artifacts on every provider. Test Reporting & Analytics uploads instead of writing a file, so it produces no artifact step at all. > [!WARNING] > > GitHub stores the JUnit report as an artifact but does not render it as a test report. To see results in the run summary, add a JUnit reporting action from the Marketplace or write your own summary to `$GITHUB_STEP_SUMMARY`. With `@requestly/cli` 1.1.6 and earlier, a request that fails at the transport layer (an unreachable host, a DNS failure) reddens the build through the run's exit code but does not appear in the Azure **Tests** tab. For those, read the build log. Later releases report it as an errored test case, so it appears in the Tests tab. ## Local projects When your project is a local, Git-backed project, the generated file targets collections by path inside your checkout instead of by cloud ID. Three things change: * The file declares an `RQ_PROJECT_DIR` variable, defaulting to `.` (the checkout root). Change it if the Requestly project lives in a subfolder. * Each target's positional argument becomes `"$RQ_PROJECT_DIR/"`, quoted so folder names with spaces still resolve to one path. * Environments are matched by name rather than by ID, because the CLI reads local environments from their filenames. ```yaml Local target, GitHub Actions theme={null} env: # Path to your Requestly project inside the checkout. Spaces are fine. # '.' is the checkout root; change it if the project sits in a subfolder. # Assumes the project directory is committed to the checked-out repository. RQ_PROJECT_DIR: '.' # ... - name: Checkout / production run: | ./browserstack-binary requestly collection run "$RQ_PROJECT_DIR/collections/checkout" --environment production --iteration-count 3 --delay-request 250 -r cli,junit --reporter-junit-export rq-reports/1-checkout.xml ``` The pipeline reads the project straight out of the repository, so it needs no BrowserStack credentials. Commit the project directory alongside the pipeline file. ## What's Next? > **[Requestly CLI](/api-client/cli)** > > Every flag the generated file uses, plus the `.requestlyrc` file for shared defaults. > **[Collection Runner](/api-client/collection-runner)** > > Set the iterations and delay each target inherits, and check the run before you commit it. > **[Write Tests](/api-client/tests)** > > Add the assertions that decide whether your pipeline passes or fails. # Scheduled Runs Source: https://docs.requestly.com/api-client/scheduled-runs Run a collection automatically on a recurring schedule in the cloud, then review run history and per-request results. A **Scheduled Run** executes a collection automatically on a recurring schedule in the cloud, so your requests keep running without anyone pressing a button. Where the [Collection Runner](/api-client/collection-runner) runs a collection on demand, a Scheduled Run runs it on a cadence you choose (for example every hour, or once a day) and keeps a history of every run so you can catch regressions over time. Each Scheduled Run belongs to a single collection. You create and manage Scheduled Runs from that collection's **Runner** tab, review a full run history, and drill into any individual run to see per-request results, assertions, and console output. ## Prerequisites > [!NOTE] > > Scheduled Runs are available on **team projects** only. Local projects and personal cloud projects show an explanatory screen with a link to switch to a team project instead. > [!WARNING] > > Only **HTTP** and **GraphQL** requests run on a schedule. WebSocket, Socket.IO, MQTT, and gRPC requests cannot run on a schedule and are skipped. In the request selection list they appear locked, and a note reminds you which requests will not run. ## Finding Scheduled Runs **1. Open the collection's Runner tab** Open the collection you want to schedule, then select the **Runner** tab. **2. Switch to the Scheduled sub-tab** The Runner tab has sub-tabs for **Manual**, **Scheduled**, and **Run in CLI**. **Manual** is the on-demand [Collection Runner](/api-client/collection-runner), and **Run in CLI** is the entry point to [Run on CI/CD](/api-client/run-on-cicd). Select **Scheduled** to see the Scheduled Runs for this collection. **3. Review the inventory** Each Scheduled Run appears as a row showing its name, schedule, the outcome of its most recent run, and a strip of colored squares summarizing recent runs. If the collection has no Scheduled Runs yet, you see an empty state with a **Create Scheduled Run** button. ![The Scheduled sub-tab of a collection's Runner tab, listing scheduled runs with their cadence, latest outcome, and a recent-run history strip.](https://mintcdn.com/requestly/vjnhS3B0BGT7YK2O/images/scheduled-runs/inventory.light.png?fit=max\&auto=format\&n=vjnhS3B0BGT7YK2O\&q=85\&s=b1a2680f3ffd09911e115211f93521bd) ## Creating a scheduled run Select **Create Scheduled Run** to open the configuration pane. It has two areas: a request-selection list on the left, and the schedule settings on the right. ![The scheduled-run configuration pane: request selection on the left, and name, environment, and schedule settings on the right.](https://mintcdn.com/requestly/vjnhS3B0BGT7YK2O/images/scheduled-runs/config.light.png?fit=max\&auto=format\&n=vjnhS3B0BGT7YK2O\&q=85\&s=82263932acf8bbf45c02a3856c886311) **1. Name the run** Give the Scheduled Run a name that describes its purpose, such as "Nightly smoke run". **2. Choose an environment** Pick the environment the run should use, or leave it as **No environment**. > [!NOTE] > > One scheduled run targets one environment. To run another environment, create a separate scheduled run. **3. Set the schedule** Choose a frequency (**Hour**, **Day**, **Week**, or **Month**) and how often it should run under **Run every**. For example, a frequency of **Hour** with an interval of `6` runs the collection every six hours. Use the **Start active** toggle to decide whether the run begins firing immediately after you create it, or starts paused. **4. Select and order the requests** In the left panel, choose which requests to include and drag to reorder them. Requests that cannot run on a schedule are shown locked and are skipped. By default the whole collection runs in its natural order. **5. Configure retries (optional)** Under **Retry on failure**, set **Retries per request** (0 to 10) and a **Backoff** strategy (None, Fixed, Linear, or Exponential). The backoff option is only enabled once you set at least one retry. > [!NOTE] > > Each retry counts as a separate request-attempt against your quota. **6. Create the run** Select **Create scheduled run**. The new run appears in the inventory and begins firing on its schedule (unless you started it paused). Scheduled Runs execute in Requestly's cloud region, not on your machine, so they keep running when the app is closed. ### Redaction Scheduled Runs always redact a fixed set of sensitive headers from the results they capture, so credentials are never stored in run history. This set is shown read-only in the config pane and cannot be changed. > [!NOTE] > > These request and response headers are always redacted in captured results: `Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`, and `Proxy-Authorization`. ## Managing scheduled runs Each row in the inventory has an **Edit** button, a **View runs** button, and an overflow (`⋮`) menu with lifecycle actions: * **Run now** triggers an immediate on-demand run without changing the schedule. The run is dispatched to the cloud and appears in the run history shortly after it finishes, not instantly. * **Pause** stops a run from firing on its schedule; **Resume** starts it again. A paused run shows a **Paused** badge in its row. * **Delete** removes the Scheduled Run after an explicit confirmation. Deleting stops the schedule and removes the run definition, but past run history is retained. * **Edit** reopens the configuration pane so you can change the name, environment, schedule, request selection, or retry settings. ## Viewing run history Select **View runs** on any row to open its run history: a list of every run the schedule has produced, newest first. Each entry shows the outcome, when the run started, what triggered it, and how long it took, along with a short failure summary when a run did not succeed. Use the **search** box to filter by run ID, run status, failure text, or trigger source, and the outcome filter to narrow the list to one of: **Succeeded**, **Failed**, **Timeout**, **Infra error**, or **Skipped**. Use **Load more** to page through older runs. ![The run-history list for a scheduled run, showing each run's outcome, start time, trigger source, and duration, with search and outcome filters.](https://mintcdn.com/requestly/vjnhS3B0BGT7YK2O/images/scheduled-runs/history.light.png?fit=max\&auto=format\&n=vjnhS3B0BGT7YK2O\&q=85\&s=a9bcce6337e8c523f8720979176271b2) > [!NOTE] > > Run history lists finalized runs only and refreshes on its own periodically. A run you just triggered with **Run now** appears once it finishes, so give it a moment and the list will update. A run that is still in progress is shown but cannot be opened until it completes. ## Inspecting a run Select any finished run to open its drill-down view. The header shows the run's overall outcome, a **Re-run** button that dispatches a fresh on-demand run, and a failure summary when the run failed. ![The per-run drill-down: the request list on the left, and run metrics with Headers, Payload, Response, and Tests tabs plus a console section on the right.](https://mintcdn.com/requestly/vjnhS3B0BGT7YK2O/images/scheduled-runs/detail.light.png?fit=max\&auto=format\&n=vjnhS3B0BGT7YK2O\&q=85\&s=59fc724a3fff08223c315b57f5c68155) The body is a two-pane layout: * The **left pane** lists every request attempt in the run, in order. Each row shows the method, name, and URL, the response status and time, and markers for failed requests, failed assertions, and retry attempts (attempts past the first are labeled). * The **right pane** shows metrics for the run (when it ran, its duration, the number of tests, the average response time, and what triggered it) and, for the request you select, a tabbed detail view: * **Headers** - the request and response headers. * **Payload** - the request body. * **Response** - the response body. A marker appears when a large body was truncated. * **Tests** - the assertions for that request, with pass, fail, and error counts. Below the panes, the **Console** section shows the console output captured for the selected request. Headers, bodies, and console output are fetched on demand as you open each request, and reflect the redaction described above. ## Running as a deploy gate Scheduled Runs are built for recurring, unattended monitoring. To run a collection as a pass or fail gate inside a CI pipeline instead, use the [Requestly CLI](/api-client/cli), which runs the same collection from your terminal and returns a non-zero exit code when an assertion fails. To get that pipeline file without writing it yourself, use [Run on CI/CD](/api-client/run-on-cicd), which generates a ready-to-commit GitHub Actions, GitLab CI, Jenkins, or Azure Pipelines file from the collections you pick. ## What's Next? > **[Collection Runner](/api-client/collection-runner)** > > Run a collection on demand and inspect the results before you schedule it. > **[Write Tests](/api-client/tests)** > > Add assertions so each scheduled run validates status, body, and headers. > **[Run from the CLI](/api-client/cli)** > > Run collections from your terminal or CI pipeline as a deploy gate. # Code Snippets in Scripts Source: https://docs.requestly.com/api-client/script-snippets Use built-in code snippets to quickly insert common patterns into your pre-request and post-response scripts in Requestly. The script editor includes a library of ready-to-use code snippets for common scripting tasks - writing tests, reading and setting variables, and logging request or response details. Instead of typing these patterns from scratch, you can browse, search, and insert them with a single click. ## Opening the snippets panel In any pre-request or post-response script editor, click the **Snippets** button in the toolbar above the editor. A panel opens with a search box at the top and a categorized list of snippets below. ![Snippets popover open in the post-response script editor showing categorized code snippets including Tests and Response body checks](https://mintcdn.com/requestly/r5FII4VivlH8sQbn/images/script-snippets-panel.light.png?fit=max\&auto=format\&n=r5FII4VivlH8sQbn\&q=85\&s=da73f5aa91c6fcd95d03217cd0cea989) The snippets shown adapt to the active script phase. For example, response assertions only appear when you are editing a post-response script - they are hidden in the pre-request editor where `rq.response` is not available. ## Searching for a snippet Type in the search box to filter snippets by name. The list narrows to matches as you type. Clear the search to return to the full list. ## Inserting a snippet Click any snippet name to insert its code at the current cursor position in the editor. The panel stays open so you can insert multiple snippets in one session. *** ## Available snippets ### Tests These snippets are available in **post-response scripts only**. #### Status code | Snippet | Code inserted | | :- | :- | | Status code: Code is 200 | `rq.test("Status code is 200", () => { rq.response.to.have.status(200); });` | | Status code: Code name has string | Checks `rq.response.statusText` includes `"OK"` | | Status code: Successful POST request | Asserts `rq.response.status` is one of `[201, 202]` | #### Response body | Snippet | What it tests | | :- | :- | | Response body: Contains string | Body includes a given string | | Response body: JSON value check | A specific JSON field equals an expected value | | Response body: Is equal to a string | Entire body equals an exact string | | Response body: Is valid JSON | Body is parseable JSON | | Response body: JSON schema validation | Body matches a JSON Schema object you define | | Response body: Is an array | Body is an array | | Response body: Has property | Body object has a specific property key | Example - JSON schema validation: ```javascript theme={null} const schema = { type: "object", properties: { id: { type: "number" }, name: { type: "string" }, }, required: ["id", "name"], }; rq.test("Response matches schema", () => { rq.response.to.have.jsonSchema(schema); }); ``` #### Response headers | Snippet | What it tests | | :- | :- | | Response headers: Content-Type check | Response includes a `content-type` header | #### Response time | Snippet | What it tests | | :- | :- | | Response time is less than 200ms | `rq.response.responseTime` is below 200 | *** ### Variables These snippets are available in **both pre-request and post-response scripts**. #### Get a variable | Snippet | Code inserted | | :- | :- | | Get a variable | `rq.variables.get("variable_key");` | | Get a global variable | `rq.globals.get("variable_key");` | | Get an environment variable | `rq.environment.get("variable_key");` | | Get a collection variable | `rq.collectionVariables.get("variable_key");` | #### Set a variable | Snippet | Code inserted | | :- | :- | | Set a variable | `rq.variables.set("variable_key", "variable_value");` | | Set a global variable | `rq.globals.set("variable_key", "variable_value");` | | Set an environment variable | `rq.environment.set("variable_key", "variable_value");` | | Set a collection variable | `rq.collectionVariables.set("variable_key", "variable_value");` | A common pattern is to extract a token from a response and store it for use in subsequent requests: ```javascript theme={null} // Post-response script on your login endpoint const body = rq.response.json(); rq.environment.set("authToken", body.token); ``` For a worked example of chaining two requests where the second depends on data from the first, see [Chaining API requests](/api-client/scripts#chaining-api-requests). #### Clear a variable | Snippet | Code inserted | | :- | :- | | Clear a global variable | `rq.globals.unset("variable_key");` | | Clear an environment variable | `rq.environment.unset("variable_key");` | | Clear a collection variable | `rq.collectionVariables.unset("variable_key");` | *** ### Request / Other These snippets are available in both phases unless noted. | Snippet | Phase | Code inserted | | :- | :- | :- | | Log request details | Both | `console.log("Request:", rq.request.method, rq.request.url);` | | Log response body | Post-response only | Logs `rq.response.status` and `rq.response.body` | Logs appear in the **DevTools** console tab, tagged with `#script`. See [DevTools](/api-client/devtools) for details. *** ## Related pages * [Pre-request and Post-response Scripts](/api-client/scripts) - overview of the scripting system and the `rq` API * [Tests](/api-client/tests) - running and viewing test results after a request * [Import packages into your scripts](/api-client/import-packages-into-your-scripts) - use external libraries like `moment` and `uuid` in scripts # Pre-request & Post-response Scripts Source: https://docs.requestly.com/api-client/scripts Learn how to use JavaScript in Requestly to customize API requests, process responses, and interact with variables, with examples. *** Scripts in Requestly allow you to extend and customize your API requests and responses dynamically using JavaScript. These scripts enable you to manipulate requests before they are sent (Pre-request scripts) or process responses after they are received (Post-response scripts). With access to the full request and response objects, you can achieve advanced automation, validations, and transformations. [https://www.youtube.com/embed/jh3Pu4XnbxQ](https://www.youtube.com/embed/jh3Pu4XnbxQ) ## **Pre-Request Scripts** **Pre-Request Scripts** run before the API request is sent to the server. They allow you to modify request attributes, such as headers, body, query parameters, or even the URL. Pre Scripts are useful for adding authentication tokens, generating timestamps, or altering the request dynamically based on certain conditions. ![](https://mintcdn.com/requestly/xVEl1aB2iRcm03E4/images/script---1.png?fit=max\&auto=format\&n=xVEl1aB2iRcm03E4\&q=85\&s=6d058cc25b9a7aec0ee259a3280977cc) Let’s try to understand the workings of pre-script using easy-to-follow examples. **Auto Increment Page Numbers** Let’s assume you have an endpoint that takes page number as query parameter, we use environment variable `{{page_number}}` to get value of page number. ```json theme={null} https://app.requestly.io/echo?page={{page_number}} ``` We can get current page number from environment variables and set it back with an increment. ```json theme={null} rq.environment.set("page_number", rq.environment.get("page_number")+1); ``` Now every time you click the Send button of this request it would send incremented page number. **Test APIs by Randomising Values** During development hitting an API with new data every time can be a pain, we can use Pre-Script to randomise the values and call the same API without getting duplicate entry error. Let’s setup our request with body as follows: ```json theme={null} POST: ``` ```json theme={null} { "name": "{{name}}", "email": "{{email}}", "phone_number": "{{phone_number}}" } ``` We will use below pre-script to create random values and update them in environment variables. ```jsx theme={null} var name = (+new Date).toString(36).slice(-5); var phone = Math.round((Math.random())*(10**10)); rq.environment.set("name", name); rq.environment.set("email", name+"@example.com"); rq.environment.set("phone_number", phone); ``` You can also use pre-script to generate access tokens, validate the requests, generate some random data for the request. You can also access elements of the request, collection variables and environment variables, checkout Requestly’s JavaScript API. ## **Post-Response Scripts** **Post-Response Scripts** run after the API response is received. They allow you to process response data, validate outputs, or log details for debugging. Post Scripts are useful for transforming the response body, validating response codes, or storing results for further use. ![](https://mintcdn.com/requestly/xVEl1aB2iRcm03E4/images/script---2.png?fit=max\&auto=format\&n=xVEl1aB2iRcm03E4\&q=85\&s=2debfb4b7f521a7f013e502f794c5fbf) Let’s try to understand the working of post script using easy to follow examples. **Validate Response Code** ```jsx theme={null} if (rq.response.code !== 200) { console.error("Unexpected Response Code:", rq.response.code); } ``` We can also fetch and set API Keys or auth tokens, id, and other data from response of an API and use it in other APIs. You can access elements of the request, response, collection variables and environment variables, checkout Requestly's JavaScript API. *** ## Viewing Console Logs from Scripts You can use `console.log()` or `console.error()` in your Pre-Request and Post-Response Scripts to debug your logic and inspect values at runtime. The logs appear in Requestly's built-in **DevTools** panel and are tagged with **#script** so you can filter them quickly. **1. Open DevTools** Click the **DevTools** button in the application footer at the bottom of the window. The panel docks to the bottom of the workspace with a **Console** tab selected by default. To see logs for just one request, send the request and open the **Debug** tab in the response area instead. It shows DevTools scoped to that request's most recent execution. **2. Filter logs from your scripts** In the Console tab's search box, type **#script** to show only logs produced by your Pre-Request and Post-Response Scripts and hide system events and network summaries. For everything DevTools can show you, including the Network tab and per-request inspection, see the [DevTools page](/api-client/devtools). ## Requestly JavaScript API `rq` Requestly provides a robust set of JavaScript properties and methods to interact with API requests, responses, environments, and global variables. The `rq` object is available in all pre-request and post-response scripts, giving you full control over your API workflow. ### Available Objects The Requestly JavaScript API consists of the following main objects: #### `rq.request` Access and manipulate API request details including method, headers, body, URL, and query parameters. Use this in both pre-request and post-response scripts to read or modify request data. **Quick Example:** ```jsx theme={null} console.log("Request Method:", rq.request.method); console.log("Request URL:", rq.request.url); ``` [View complete rq.request documentation →](/api-client/rq-api-reference/rq-request) *** #### `rq.response` Access API response details including body, headers, status code, and response time. Primarily used in post-response scripts to process and validate API responses. **Quick Example:** ```jsx theme={null} console.log("Response Code:", rq.response.code); const data = rq.response.json(); ``` [View complete rq.response documentation →](/api-client/rq-api-reference/rq-response) *** #### `rq.sendRequest` Send an HTTP request from inside a script and read its response. Use it to fetch a token before the main request runs, call a second endpoint, or poll a status URL. Available in both pre-request and post-response scripts. **Quick Example:** ```jsx theme={null} const res = await rq.sendRequest("https://api.example.com/health"); console.log("Status:", res.code); ``` [View complete rq.sendRequest documentation →](/api-client/rq-api-reference/rq-send-request) *** #### `rq.execution` Control how a request runs: read where it sits in your collection, skip it, set which request the collection runner goes to next, and run another saved request. **Quick Example:** ```jsx theme={null} if (!rq.environment.get("authToken")) { rq.execution.skipRequest(); } ``` [View complete rq.execution documentation →](/api-client/rq-api-reference/rq-execution) *** #### `rq.variables` Read a variable from whichever scope defines it, and write temporary values for the current session. This is the object to reach for when you want a value and do not care where it lives. **Quick Example:** ```jsx theme={null} const token = rq.variables.get("authToken"); // looks in every scope rq.variables.set("requestId", rq.$randomUUID()); // writes to the runtime scope ``` [View complete rq.variables documentation →](/api-client/rq-api-reference/rq-variables) *** #### `rq.environment` Manage environment-specific variables dynamically. Environment variables are scoped to a specific environment (dev, staging, production) and can be used across multiple requests. **Quick Example:** ```jsx theme={null} rq.environment.set("authToken", "Bearer "); const token = rq.environment.get("authToken"); ``` [View complete rq.environment documentation →](/api-client/rq-api-reference/rq-environment) *** #### `rq.collectionVariables` Manage collection-scoped variables. Collection variables are only accessible within requests that belong to a specific collection and persist across all environments. **Quick Example:** ```jsx theme={null} rq.collectionVariables.set("basePath", "/v1/users"); const path = rq.collectionVariables.get("basePath"); ``` [View complete rq.collectionVariables documentation →](/api-client/rq-api-reference/rq-collection-variables) *** #### `rq.globals` Manage global variables accessible across all collections and environments. Use for truly universal configuration and state. **Quick Example:** ```jsx theme={null} rq.globals.set("appVersion", "1.0.0"); const version = rq.globals.get("appVersion"); ``` [View complete rq.globals documentation →](/api-client/rq-api-reference/rq-globals) *** #### `rq.test` Write tests to validate API responses and ensure your APIs work as expected. Tests help automate quality assurance in post-response scripts. **Quick Example:** ```jsx theme={null} rq.test("Status code is 200", function() { rq.expect(rq.response.code).to.equal(200); }); ``` [View complete rq.test documentation →](/api-client/rq-api-reference/rq-test) *** #### `rq.expect` Write assertions for API testing using the powerful Chai.js assertion library. Use with `rq.test` to validate response data. **Quick Example:** ```jsx theme={null} rq.test("Response has user data", function() { const data = rq.response.json(); rq.expect(data).to.have.property("id"); rq.expect(data.name).to.be.a("string"); }); ``` [View complete rq.expect documentation →](/api-client/rq-api-reference/rq-expect) #### `rq.info` Access execution metadata including request name, iteration index, and event name. Useful for tracking progress in collection runs and implementing iteration-specific logic. **Quick Example:** ```jsx theme={null} console.log(`Running ${rq.info.requestName}`); console.log(`Iteration ${rq.info.iteration + 1} of ${rq.info.iterationCount}`); ``` [View complete rq.info documentation →](/api-client/rq-api-reference/rq-info) *** #### `rq.iterationData` Access data from CSV or JSON files during collection runs. Each iteration receives different data from the file, enabling data-driven testing. **Quick Example:** ```jsx theme={null} const city = rq.iterationData.get("city"); const temp = rq.iterationData.get("temperature"); console.log(`Weather in ${city}: ${temp}°C`); ``` [View complete rq.iterationData documentation →](/api-client/rq-api-reference/rq-iteration-data) *** #### `rq.visualizer` Render a custom visualization of the response - a chart, a table, or formatted HTML - shown behind a **Visualize** button in the response body. Available in both pre-request and post-response scripts. **Quick Example:** ```jsx theme={null} rq.visualizer.set("

{{title}}

", { title: "Hello from the visualizer" }); ``` [View complete rq.visualizer documentation →](/api-client/rq-api-reference/rq-visualizer) *** ### Using Dynamic Variables in Scripts Requestly provides dynamic variables, which are built in values that automatically generate common data such as timestamps, UUIDs, and random values. You can access them in scripts using the rq.\$variableName() syntax. **Quick Example:** ```jsx theme={null} const uniqueId = rq.$randomUUID(); const timestamp = rq.$timestamp(); const email = rq.$randomEmail(); console.log("Generated User ID:", uniqueId); console.log("Request Timestamp:", timestamp); ``` **Common Dynamic Variables:** * `rq.$randomUUID()` - Generate unique identifiers * `rq.$timestamp()` - Current Unix timestamp * `rq.$isoTimestamp()` - ISO 8601 timestamp * `rq.$randomInt()` - Random integer * `rq.$randomEmail()` - Random email address * `rq.$randomFirstName()` - Random first name * `rq.$randomCompanyName()` - Random company name **With Arguments:** ```jsx theme={null} // Generate random integer between 1-100 const age = rq.$randomInt(1, 100); // Generate alphanumeric string of length 10 const code = rq.$randomAlphaNumeric(10); // Generate password with specific length const password = rq.$randomPassword(20); // Generate email with custom name const email = rq.$randomEmail("John", "Doe"); ``` [View complete Dynamic Variables documentation →](/api-client/environments-and-variables/dynamic-variables) *** ## Chaining API requests When one request depends on the output of another, use a post-response script on the first request to extract the values you need, then reference them from the second request using `{{variable_name}}` placeholders. The same pattern covers auth-token flows, "create then update" sequences, and conditional logic that decides what the next call should send. The flow has three pieces: 1. **Post-response script on the prerequisite request.** Parse the response and write the values into a variable scope. 2. **Reference the variables** from the next request's URL, headers, query params, or body using `{{variable_name}}` syntax. See [Using variables in API requests](/api-client/environments-and-variables/using-variables-in-api-requests). 3. **Run the requests in order**, either manually or by adding them to a collection and using the [Collection Runner](/api-client/collection-runner). ### Example: pass dynamic data from one request to the next A collection with two requests: `Get Users` followed by `Add User`. The post-response script on `Get Users` checks whether the target user already exists. If they don't, it stages fresh data for the second request to consume. **Post-response script on `Get Users`:** ```javascript theme={null} const body = rq.response.json(); const users = Array.isArray(body) ? body : body.users; const targetEmail = rq.environment.get("new_user_email"); const existing = users.find(user => user.email === targetEmail); if (existing) { rq.variables.set("user_exists", "true"); rq.variables.set("existing_user_id", existing.id); } else { rq.variables.set("user_exists", "false"); rq.variables.set("new_user_name", "User_" + Date.now()); } ``` **Request body on `Add User`:** ```json theme={null} { "name": "{{new_user_name}}", "email": "{{new_user_email}}" } ``` When the collection runs, Requestly substitutes `{{new_user_name}}` and `{{new_user_email}}` with whatever the post-response script wrote. Anything the next request needs (an id from a `POST` to feed a follow-up `PATCH`, an auth token from a login call, an order number returned by a checkout step) follows the same shape. ### Picking a variable scope | Scope | Setter | Lives for | | :- | :- | :- | | Runtime | `rq.variables.set` | The current session. Local to your device, and not saved back to your runtime variables list, so a reload restores whatever you typed there yourself. | | Environment | `rq.environment.set` | The active environment. Persists across runs. | | Collection | `rq.collectionVariables.set` | The collection. Persists across runs. | | Global | `rq.globals.set` | Everywhere. Persists across runs. | For values that exist only to bridge one request to the next, prefer **runtime** scope. It stays local to your device and does not pollute your saved environment with one-off state. Reach for environment or collection scope when the value (an auth token, a tenant id) is meaningful beyond the immediate chain. For the full per-scope reference, see [Runtime variables](/api-client/environments-and-variables/runtime-variables), [rq.variables](/api-client/rq-api-reference/rq-variables), [rq.environment](/api-client/rq-api-reference/rq-environment), [rq.collectionVariables](/api-client/rq-api-reference/rq-collection-variables), and [rq.globals](/api-client/rq-api-reference/rq-globals). *** ## Sharing code between scripts The section above passes *data* between scripts through a variable scope. To share *code* — a helper function you want every request in a collection to call — you do not need a variable, and you do not need to repeat the helper in each request. Every script in one run shares a single scope: the collection-level script, each folder-level script, the request's own pre-request script, and its post-response script. ### Example: define a helper once, call it from every request Collection pre-request script: ```javascript theme={null} auth = { nonce() { return require('crypto').randomBytes(16).toString('hex'); }, signature(body, secret) { return require('crypto').createHmac('sha256', secret).update(body).digest('hex'); }, }; ``` Request pre-request script: ```javascript theme={null} const nonce = auth.nonce(); const signature = auth.signature(rq.request.body ?? '', rq.environment.get('api_secret')); rq.request.headers.upsert({ key: 'X-Nonce', value: nonce }); rq.request.headers.upsert({ key: 'X-Signature', value: signature }); ``` The post-response script of that same request can call `auth` too — the shared scope spans the whole request, not just the pre-request phase. ### Why there is no `var` in front of `auth` The missing keyword is doing the work, and the reason is ordinary JavaScript scoping. Each script runs wrapped in its own function. A `var`, `let`, `const`, `function` or `class` declaration is scoped to the function it appears in, so it is discarded as soon as that script finishes — a later script has no way to reach it. An assignment with no keyword does not declare anything. `auth = { ... }` sets a property on the global object, and that global object is the one thing every script in the run shares, so the value outlives the script that created it: ```javascript theme={null} var auth = { ... }; // scoped to this script — the next script sees `auth` as undefined auth = { ... }; // a property on the shared global — every later script can read it ``` Writing `globalThis.auth = { ... }` does exactly the same thing and says so explicitly. Prefer it if a bare assignment reads as a mistake to you or your reviewers. > [!WARNING] > > `var auth = { ... }` raises no error of its own. The collection script runs fine and the request script > simply sees `auth` as `undefined`, so the failure surfaces later as a `TypeError` on the first call. If a > shared helper reads as undefined, check for a `var`, `let`, or `const` in front of it first. ### What the shared scope does and does not keep * **It lasts for one run.** Every request in a Collection Runner run shares it. Sending a single request from the editor is a run of one. * **A script timeout discards it.** If a script is killed for exceeding its time budget, the scope is thrown away and the next run starts clean. * **It holds values, not saved state.** Nothing here is persisted. For data that must outlive the run, write it to a variable scope as described above. > [!NOTE] > > To share code across *collections* — or to keep it in one place and version it — author a Custom Package > instead and `require()` it. See [Import packages into your scripts](/api-client/import-packages-into-your-scripts). *** ## Encoding request payloads Some APIs require the body to be transformed before it goes on the wire, for example Base64-encoding a JSON envelope. Compute the transformed value in a pre-request script and write it back with `rq.request.body.update(value)` (or plain assignment, `rq.request.body = value`) — the value is sent exactly as your script produced it, byte for byte, with no variable resolution applied to it. Headers, query parameters, the URL, and the method are writable the same way. See [rq.request](/api-client/rq-api-reference/rq-request) for the full mutation surface, and [Signing requests](#signing-requests) when the transformation is a signature. ### Base64 encoding with `Buffer` `require('buffer')` is available in scripts. It is the recommended path because it handles non-ASCII characters correctly. **Pre-request script:** ```javascript theme={null} const { Buffer } = require('buffer'); const payload = { username: rq.environment.get("username"), password: rq.environment.get("password"), }; const encoded = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64'); rq.request.body.update(encoded); ``` The request is sent with the encoded string as its body. Set `Content-Type` to whatever the server expects — an explicit header row always wins, typically `text/plain` or `application/octet-stream` for a raw Base64 string, or `application/json` if the encoded value is wrapped inside a JSON envelope. ### Base64 encoding with `btoa` `btoa` and `atob` are available as globals. They are convenient when the payload is plain ASCII: ```javascript theme={null} const jsonString = JSON.stringify({ token: rq.environment.get("token") }); rq.request.body.update(btoa(jsonString)); ``` Prefer `Buffer` over `btoa` when the payload may contain non-ASCII characters. `btoa` throws on anything outside the Latin-1 range. ### Decoding a Base64 response Mirror the encoding pattern in a post-response script: ```javascript theme={null} const { Buffer } = require('buffer'); const decoded = Buffer.from(rq.response.body, 'base64').toString('utf8'); const data = JSON.parse(decoded); rq.test("Decoded response contains an access token", () => { rq.expect(data).to.have.property("access_token"); }); ``` When the response itself is binary (an image, PDF, or archive), Requestly already hands you the body as Base64. Check [`rq.response.bodyEncoding`](/api-client/rq-api-reference/rq-response) to tell binary from text before decoding: ```javascript theme={null} const { Buffer } = require('buffer'); if (rq.response.bodyEncoding === 'base64') { const bytes = Buffer.from(rq.response.body, 'base64'); rq.test("Response is a non-empty binary payload", () => { rq.expect(bytes.length).to.be.above(0); }); } ``` *** ## Signing requests Some APIs require a signature computed over the request body. Compute it in a pre-request script and write the body and the signature header onto the request together. The body is sent exactly as your script produced it, byte for byte, with no variable resolution applied afterwards, so the signature always matches the payload it was computed over. You do not need to stage the signed value in a variable and reference `{{signature}}` from the request. That older pattern can send a signature computed for a previous payload. ### HMAC signatures Node's `crypto` module is available via `require('crypto')`, and HMAC works in both Safe and Developer script modes: ```javascript theme={null} const crypto = require('crypto'); const body = JSON.stringify({ amount: 100, currency: "USD" }); const signature = crypto .createHmac('sha256', rq.environment.get("api_secret")) .update(body) .digest('hex'); rq.request.body.update({ mode: 'raw', raw: body, options: { raw: { language: 'json' } } }); rq.request.headers.upsert({ key: 'X-Signature', value: signature }); ``` The same module covers hashes (`createHash`) and symmetric ciphers. ### RS256 and other asymmetric signatures The asymmetric functions of `require('crypto')` (`createSign`, `createVerify`, `generateKeyPair` and their siblings) are not available in Safe mode, which is the default. Use a signing library written in pure JavaScript instead: it does not rely on platform crypto, so it behaves the same in both modes. Install [`jsrsasign`](https://www.npmjs.com/package/jsrsasign) from npm (available in the desktop app), then sign in a pre-request script: ```javascript theme={null} const { KJUR } = require('jsrsasign'); const payload = JSON.stringify({ amount: 100, currency: "USD" }); const jws = KJUR.jws.JWS.sign( 'RS256', { alg: 'RS256', typ: 'JWT' }, payload, rq.environment.get("private_key"), ); rq.request.body.update(jws); rq.request.headers.upsert({ key: 'Content-Type', value: 'application/jose' }); ``` The private key is a PEM string, in either PKCS#8 (`-----BEGIN PRIVATE KEY-----`) or PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`) form. `PS256` and `HS256` work the same way. > [!WARNING] > > Do not paste a library's source into an environment variable and `eval()` it. `require()` loads > the library directly. A megabyte of source held in a variable is awkward to edit, easy to > truncate, and travels with every export of that environment. ### Keys, and what signing costs Keep private keys and signing secrets in the [Vault](/api-client/vault/vault) or as environment secrets, never in the script itself. Signing with a private key is slower in Safe mode than in Developer mode: roughly 1.4 seconds against 0.45 seconds for one RS256 signature on a 2048-bit key, because the arithmetic runs in JavaScript rather than in native code. Loading the library is not what costs; the signature is. Switch the request to Developer mode if that per-request cost matters more to you than running inside the sandbox, unless your organization has restricted scripts to Safe mode - see [Organization resources](/account/organization-resources). See [Import packages into your scripts](/api-client/import-packages-into-your-scripts) for everything `require()` can load, both built in and from npm. *** ## Code Snippets The script editor includes a built-in snippets library with ready-to-use patterns for tests, variable operations, and logging. Click **Snippets** in the editor toolbar to browse and insert them. [View all available snippets →](/api-client/script-snippets) # Authorization Source: https://docs.requestly.com/api-client/send-api-request/authorization Learn how to set up and use every API Authorization method in Requestly, including API Key, Bearer Token, Basic Auth, Digest, JWT Bearer, NTLM, OAuth 1.0, OAuth 2.0, Hawk, and AWS Signature v4. Requestly allows you to send authorization data along with your API requests. Authorization data confirms that the sender has permission to access the API. [https://www.youtube.com/embed/pnZ8toyzjAM](https://www.youtube.com/embed/pnZ8toyzjAM) > [!NOTE] > > Authorization details can be configured in the Authorization tab at either the **collection level** or the **request level**. When authentication is set at the collection level, it applies to all APIs within that collection unless a specific request defines its own authorization settings or selects **NO-AUTH.** Requestly automatically inserts the appropriate authorization information into the necessary sections of the request based on the chosen authentication type. > [!NOTE] > > **OAuth availability:** OAuth 1.0 and OAuth 2.0 are available in the desktop app and are rolling out gradually. If they do not appear in the auth-type dropdown, update to the latest version. The other auth types listed below are unaffected. ## Steps to Add Authorization **1. Open a Request or Collection** Click on any request or collection to begin setting up authorization. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/bff6af01-a980-412b-8b68-26c775ce6e55.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=6df153e3834e8a5618d2418a25c8afa0) **2. Access the Authorization Tab** 1. Go to the **Authorization** tab. 2. Choose the appropriate authorization type from the dropdown menu. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/d2323c4f-282b-4d5e-b1dc-31649edd9702.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=6b7fe1c9a99fb15fed8924a443c3cc43) **3. Enter Authorization Details** Each authorization type has specific fields that must be filled. Below are the details for each type: #### No Auth Requestly won’t send authorization details with a request unless you specify an auth type. If your request doesn’t require authorization, leave the type unset (the dropdown shows "Authorization type" as a placeholder), or use **Clear** to remove a type you set earlier. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/f222a398-7997-4621-adf5-59b9594c039f.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=6021fa113fa1a60e8e988eaa8b531668) #### Inherit Auth from Parent Requestly uses the auth applied at the parent level. The inherited properties are populated when the request is sent. This works for API requests and sub-collections. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/1ec7caab-8612-4bf0-a794-97c4c7d832c5.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=aac3aa396a80bf85fd024ead0bbf07c8) #### API Key Requestly allows you to send key-value pairs along with the request data. These can be added to either Headers or Query Params. Select "API Key" from the Auth Type list, then enter your key name and value. Choose "Header" or "Query Params" from the "Add to" dropdown list for their inclusion. Variable storage enhances security. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/1d01ebb8-282e-478d-87fd-01a1646cdd40.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=1c24bdf0675b73e8e46b2469f267f7ed) #### Bearer Tokens Bearer tokens enable requests to authenticate using an access key such as a JSON Web Token (JWT). Tokens are included in the request header. Select "Bearer Token" from the Auth Type dropdown and enter the token value. For additional security, store the token in a variable and reference it by name. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/de9fed66-ee47-4d40-927b-d4214c162432.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=c288ad0acdae084a5cbf79f5493710d9) Requestly appends the token value to the text "Bearer" in the required format in the Authorization header. #### Basic Auth Basic authentication involves sending a verified username and password with your request. Select "Basic Auth" from the Auth Type dropdown. Enter your API username and password in the respective fields. For extra security, store these in variables. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/2238bb19-24e6-454e-9271-2f947349705b.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=5576780a7e76b85f4d3285f05f9bae91) In the request headers, the Authorization header passes the API a Base64 encoded string representing the username and password, appended to the text "Basic." #### Digest Auth Answer an HTTP Digest challenge without putting the password on the wire. Pick **Digest auth** from the Authorization Type dropdown and enter a username and password. Requestly reads the server's challenge from the first `401`, computes the response hash, and replays the request. See the [Digest Auth page](/api-client/send-api-request/authorization/digest) for the algorithm and quality-of-protection choices, and the server-populated advanced fields. #### JWT Bearer Sign a fresh JSON Web Token on every send. Pick **JWT Bearer** from the Authorization Type dropdown, choose an algorithm, supply the signing key, and write the claims. Requestly signs at send time and attaches the token as a header or a query parameter. See the [JWT Bearer page](/api-client/send-api-request/authorization/jwt-bearer) for the twelve algorithms, the `{{expiresIn}}` directive, and the attachment options. #### NTLM Authenticate against Windows and Active Directory endpoints. Pick **NTLM** from the Authorization Type dropdown and enter your username, password, and domain. Requestly completes the three-message handshake for you. See the [NTLM page](/api-client/send-api-request/authorization/ntlm) for the field reference and availability. #### OAuth 1.0 Sign requests using OAuth 1.0 with HMAC, RSA, or Plaintext signature methods. Pick **OAuth 1.0** from the Auth Type dropdown and fill in the consumer key, consumer secret, access token, and token secret. Requestly generates the nonce, timestamp, and signature on every send. See the [OAuth 1.0 page](/api-client/send-api-request/authorization/oauth1) for the full field reference and signature method options. #### OAuth 2.0 Use OAuth 2.0 for modern token-based flows. Pick **OAuth 2.0** from the Auth Type dropdown, then choose a grant type (Authorization Code, Authorization Code with PKCE, Client Credentials, Implicit, Password Credentials, or Manual). Requestly runs the flow, caches the access token, and refreshes it before it expires. See the [OAuth 2.0 page](/api-client/send-api-request/authorization/oauth2) for each grant type, callback modes, and token lifecycle details. #### Hawk Sign each request with a message authentication code. Pick **Hawk** from the Authorization Type dropdown and enter your auth ID and auth key. Requestly generates the nonce and timestamp and builds the `Authorization: Hawk` header on every send. See the [Hawk page](/api-client/send-api-request/authorization/hawk) for the optional fields and the payload hash toggle. #### AWS Signature v4 Sign requests to AWS services. Pick **AWS Signature v4** from the Authorization Type dropdown and enter your access key, secret key, region, and service. Choose **Live Request** to sign and send, or **Presigned URL** to generate a time-limited link instead. See the [AWS Signature v4 page](/api-client/send-api-request/authorization/aws-signature-v4) for the credential sources and the presigned expiry. **4. Test the Request** Click "Send" to ensure that the authorization data is sent along with the API request. ## Variable Support and Export Requestly supports the use of variables in Authorization Values, allowing flexibility and reuse across multiple requests or collections. Variables can store sensitive data securely and simplify updates when values change. For instance, you can define API tokens or credentials as variables and reference them in authorization fields. ![](https://mintcdn.com/requestly/qIWXalHJdphCbP8R/images/authorization/e5ffe9af-749f-4b37-9dd9-61ea5caae1e0.png?fit=max\&auto=format\&n=qIWXalHJdphCbP8R\&q=85\&s=211d749f8b5df74004996c7bfbde81ee) While authorization data can be exported alongside requests or collections, note that variable values themselves are not exported. This ensures the security of sensitive data and prevents accidental sharing of confidential information. Users need to define variable values locally when importing shared requests or collections. ## What's Next? > **[Environment Variables](/api-client/environments-and-variables)** > > Store and manage auth tokens securely with variables > **[Request Headers](/api-client/send-api-request/create-requests/request-headers)** > > Learn how authorization headers are added to requests > **[API Collections](/api-client/api-collections)** > > Apply authorization to multiple requests at once # AWS Signature v4 Source: https://docs.requestly.com/api-client/send-api-request/authorization/aws-signature-v4 Sign requests to AWS services with Signature Version 4, or generate a presigned URL. AWS Signature Version 4 is the signing scheme every AWS service expects. It derives a signature from your secret key, the region, the service name, and the request itself, so the signature is valid for that one request and nothing else. Requestly offers the scheme in two modes. **Live Request** signs the request and sends it. **Presigned URL** signs a URL you can hand to someone else, or paste into a browser, without sending anything. ![AWS Signature v4 form in the Authorization tab showing access key ID, secret access key, session token, region, service, profile name, and the attachment mode radio buttons.](https://mintcdn.com/requestly/eVaYS_FXw1j-9uVi/images/authorization/aws-sigv4-form.light.png?fit=max\&auto=format\&n=eVaYS_FXw1j-9uVi\&q=85\&s=b02d098dd54b4540ee062e7632ca7374) ## Set up AWS Signature v4 **1. Open the Authorization tab** Open any request or collection, then go to the **Authorization** tab. **2. Select AWS Signature v4** Pick **AWS Signature v4** from the **Authorization Type** dropdown. The AWS fields appear below the dropdown. **3. Enter your credentials** Fill in **Access Key ID** and **Secret Access Key**. Add **Session Token** as well if you are using temporary STS credentials. You can also leave all three blank and let Requestly find credentials elsewhere, as described below. **4. Set the region and service** **Region** defaults to `us-east-1`. **Service** is the AWS service short name, such as `s3`, `execute-api`, or `lambda`. Both values go into the signature, so a mismatch produces a signature the service will not accept. **5. Choose the attachment mode** Leave **Attachment** on **Live Request** to sign and send. Switch to **Presigned URL** to generate a shareable link instead. **6. Send the request** Click **Send**. In live mode Requestly signs the request and returns the service's response. In presigned mode it returns the signed URL. ## Field reference | Field | Purpose | | - | - | | **Access Key ID** | The public half of your key pair, usually starting `AKIA`. | | **Secret Access Key** | The private half. Requestly derives the signing key from it; the secret is never sent. | | **Session Token** | Optional. Required when your credentials come from STS, `assume-role`, or an IAM role session. | | **Region** | The AWS region the request targets, such as `eu-west-1`. Defaults to `us-east-1`. | | **Service** | The service short name the signature is scoped to, such as `s3` or `execute-api`. | | **Profile Name** | Optional. A profile in your `~/.aws/credentials` file. | | **Attachment** | **Live Request** or **Presigned URL**. | | **Expiry (seconds)** | Presigned mode only. How long the generated URL stays valid. | Every credential field accepts Requestly [variables](../../environments-and-variables) and [vault](../../vault/vault) references. > [!WARNING] > > An AWS secret access key in a shared collection is a shared AWS account. Store it as a [vault](../../vault/vault) secret and reference it as `{{vault:aws_secret_key}}`, or leave the field blank and use a credential profile. ## Where credentials come from Requestly looks in three places, in order, and uses the first one that produces a complete pair: **1. The form fields** **Access Key ID** and **Secret Access Key** as typed above. Both must be non-empty; one alone is treated as not set. **2. Environment variables** `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, plus `AWS_SESSION_TOKEN` when present. Both the ID and the secret must be set, otherwise Requestly moves on. **3. A credentials profile** The profile you name in **Profile Name**, read from `~/.aws/credentials`. The file is read fresh on every send, so rotating a credential there takes effect on the next request with no restart. > [!NOTE] > > Reading AWS credentials from this machine requires the desktop app. [Download Requestly](https://requestly.com/downloads). If none of the three produces credentials, the send fails and tells you so rather than sending the request unsigned. > [!TIP] > > The credential profile is the tidiest option for a collection you share. Nothing sensitive is stored in the request, and each teammate points the same **Profile Name** at their own account. ## Live Request mode The default. Requestly computes the signature at send time and attaches it as an `Authorization` header, along with the `X-Amz-Date` header and, for temporary credentials, `X-Amz-Security-Token`. The response panel shows the service's real response. ## Presigned URL mode Select **Presigned URL** and an **Expiry (seconds)** field appears, defaulting to `3600` (one hour). AWS caps a presigned URL at `604800` seconds, which is seven days. Press **Send** and Requestly does not send anything. It signs the request into a URL and shows it in the response panel, with a **Copy** button and a note stating how long it is valid. Anyone holding that URL can perform that one request until it expires. Presigned mode applies to HTTP requests. It is not available for GraphQL, WebSocket, or Socket.IO requests, which have no single URL to sign. AWS Signature v4 as a whole is not offered for gRPC requests. > [!WARNING] > > A presigned URL carries its own authorization. Treat it as a credential: anyone who has the link can use it until it expires, with no further sign-in. ## Inherit AWS Signature v4 from a collection One AWS account usually fronts many endpoints, so collection-level auth fits well. Set AWS Signature v4 once on the collection and leave every request inside it on **Inherit from parent**. Requestly walks up from the request to the nearest ancestor that sets a concrete auth type. Remember that **Service** is part of the signature. A collection that mixes `s3` and `execute-api` endpoints needs the service set per request, or split into one collection per service. A request that picks its own auth type stops inheriting, and a collection or folder whose auth type is cleared or left unset stops the walk for everything below it. ## Troubleshooting > **SignatureDoesNotMatch** > > Check **Region** and **Service** before you check the keys. Both are inputs to the signature, so a request to a `eu-west-1` bucket signed for `us-east-1` fails with exactly this error even though the credentials are correct. > **The token included in the request is expired** > > Your STS session has ended. Refresh the temporary credentials and update **Session Token**, or switch to a credential profile so Requestly reads the current values on every send. > **Requestly says no credentials were found** > > All three sources came up empty. Fill in the form fields, or name a profile that exists in `~/.aws/credentials`. > **Profile Name will not accept input** > > You are in the web app, which cannot read files on your machine. Open the same project in the [desktop app](https://requestly.com/downloads), or type the keys into the form fields instead. ## What's Next? > **[Hawk](/api-client/send-api-request/authorization/hawk)** > > The other per-request signing scheme in the dropdown. > **[Vault](/api-client/vault/vault)** > > Keep AWS secrets out of the collection. > **[Authorization](/api-client/send-api-request/authorization)** > > Back to every auth type Requestly supports. # Digest Auth Source: https://docs.requestly.com/api-client/send-api-request/authorization/digest Authenticate requests with HTTP Digest access authentication (RFC 7616). Digest auth proves you know a password without ever putting the password on the wire. The server answers your first request with a `401` and a `WWW-Authenticate` challenge. Requestly hashes your credentials together with values from that challenge and replays the request with an `Authorization: Digest` header. You never fill in the challenge values yourself. Enter a username and a password, pick the algorithm and quality of protection your API expects, and send. Digest applies to HTTP requests. It is not offered for gRPC, and a WebSocket, Socket.IO, or GraphQL request cannot perform the challenge exchange. ![Digest auth form in the Authorization tab showing username, password, algorithm, QOP, and the Disable Retry toggle.](https://mintcdn.com/requestly/eVaYS_FXw1j-9uVi/images/authorization/digest-form.light.png?fit=max\&auto=format\&n=eVaYS_FXw1j-9uVi\&q=85\&s=ece854163656c01e8d4a0b75f794b776) ## Set up Digest auth **1. Open the Authorization tab** Open any request or collection, then go to the **Authorization** tab. **2. Select Digest auth** Pick **Digest auth** from the **Authorization Type** dropdown. The Digest fields appear below the dropdown. **3. Enter your credentials** Fill in **Username** and **Password**. Both accept Requestly [variables](../../environments-and-variables) and [vault](../../vault/vault) references, so you can write `{{vault:staging_password}}` instead of pasting a password into the request. **4. Match the algorithm and QOP to your API** Leave **Algorithm** on `MD5` and **QOP** on `auth` unless your API documentation names something else. See the field reference below. **5. Send the request** Click **Send**. Requestly performs the challenge exchange and replays the request for you. ## Field reference | Field | Purpose | | - | - | | **Username** | The account name the server expects. | | **Password** | The password for that account. Requestly hashes it; the plain value is never sent. | | **Algorithm** | The hash function used to build the response. Six choices, listed below. | | **QOP** | Quality of protection. `auth` signs the method and the URI. `auth-int` also signs the request body. | | **Disable Retry** | When on, Requestly shows you the first `401` instead of replaying the request. | ### Algorithm Pick the algorithm your API advertises in its challenge: | Algorithm | Notes | | - | - | | **MD5** | The RFC 2617 default, and still the most widely deployed. | | **MD5-sess** | Session variant. Derives a per-session secret so the password hash is not reused across nonces. | | **SHA-256** | RFC 7616 modern default. Prefer it when your API supports it. | | **SHA-256-sess** | Session variant of SHA-256. | | **SHA-512-256** | SHA-512 truncated to 256 bits, per RFC 7616. | | **SHA-512-256-sess** | Session variant of SHA-512/256. | > [!NOTE] > > If the server's challenge names a different algorithm than the one you picked, the server's choice wins. The same applies to QOP. ### QOP * **auth** (default): the signature covers the HTTP method and the request URI. Correct for almost every API. * **auth-int**: the signature also covers the request body, so a proxy cannot alter the body in transit. Pick it only when your API documentation requires it, and only for requests whose body is text. ### Disable Retry Turn this on while debugging. Requestly sends the request once, stops at the `401`, and hands you the response so you can read the server's `WWW-Authenticate` header and see exactly which realm, nonce, algorithm, and QOP it is asking for. Turn it back off to authenticate normally. ## Advanced fields Expand **Advanced (auto-populated from server challenge)** to see the five values that come from the server: | Field | Where it comes from | | - | - | | **Realm** | The protection space named in the server's challenge. | | **Nonce** | The one-time value the server issued for this exchange. | | **Nonce Count** | How many times Requestly has used this nonce, as an eight-digit hex counter such as `00000001`. | | **Client Nonce** | A random value Requestly generates to prove the response is fresh. | | **Opaque** | An opaque string the server asked you to echo back unchanged. | These start empty and fill in after the first send. You can edit them, but the next send overwrites them with whatever the server returns, so treat the panel as a read-out rather than as configuration. > [!TIP] > > Leave every advanced field blank on a new request. Requestly fills them in from the challenge. ## Inherit Digest auth from a collection Set Digest auth once on a collection and leave every request inside it on **Inherit from parent**. Requestly walks up from the request to the nearest ancestor that sets a concrete auth type and uses that configuration. Two things to know: * A request that picks its own auth type stops inheriting. * A collection or folder whose auth type is cleared or left unset stops the walk, so requests below it send no credentials even if a higher collection sets Digest. ## Troubleshooting > **Every send comes back 401** > > Read the server's `WWW-Authenticate` header first: turn on **Disable Retry**, send once, and compare the realm, algorithm, and `qop` it lists against what you configured. A username or password with a stray trailing space is the next most common cause. > **The request fails with auth-int but works with auth** > > `auth-int` hashes the request body, so it needs a body it can read as text. Switch **QOP** back to `auth` unless your API documentation explicitly requires `auth-int`. > **The server keeps issuing a new challenge** > > Requestly sends the request at most three times in total. If the third attempt still comes back with a challenge, the send fails with an error rather than returning the last response. A server that rejects every nonce it just issued is usually rotating nonces faster than the exchange can complete, or is behind a load balancer sending each attempt to a different backend. ## What's Next? > **[NTLM](/api-client/send-api-request/authorization/ntlm)** > > The other challenge-response scheme in the dropdown. > **[Vault](/api-client/vault/vault)** > > Keep the password out of the collection. > **[Authorization](/api-client/send-api-request/authorization)** > > Back to every auth type Requestly supports. # Hawk Source: https://docs.requestly.com/api-client/send-api-request/authorization/hawk Sign requests with a Hawk message authentication code. Hawk signs each request with a message authentication code computed from a shared key. The key itself never leaves your machine, and the signature covers the method, the URI, the host, the port, and optionally the request body, so a replayed or tampered request fails verification. Requestly builds the `Authorization: Hawk` header on every send. You supply the ID and the key; the nonce and the timestamp can be left to Requestly. Hawk is offered for HTTP, GraphQL, WebSocket and Socket.IO requests. It is not offered for gRPC. ![Hawk form in the Authorization tab showing auth ID, auth key, algorithm, user, nonce, timestamp, ext, app, dlg, and the include payload hash toggle.](https://mintcdn.com/requestly/eVaYS_FXw1j-9uVi/images/authorization/hawk-form.light.png?fit=max\&auto=format\&n=eVaYS_FXw1j-9uVi\&q=85\&s=2cf184ab38901759203343f66a48cb9e) ## Set up Hawk **1. Open the Authorization tab** Open any request or collection, then go to the **Authorization** tab. **2. Select Hawk** Pick **Hawk** from the **Authorization Type** dropdown. The Hawk fields appear below the dropdown. **3. Enter the ID and key your API issued** Fill in **Hawk Auth ID** and **Hawk Auth Key**. These are the credential pair the API gave you; everything else is optional. **4. Match the algorithm** Leave **Algorithm** on `SHA-256` unless the API specifies `SHA-1`. The two sides must agree or verification fails. **5. Send the request** Click **Send**. Requestly computes the MAC and attaches the `Authorization: Hawk` header. ## Field reference ### Required | Field | Purpose | | - | - | | **Hawk Auth ID** | The public identifier for your credential pair. Travels on the wire as `id`. | | **Hawk Auth Key** | The shared secret used to compute the MAC. Never sent; only the resulting MAC is. | | **Algorithm** | `SHA-256` (default) or `SHA-1`. Must match what the server expects. | Both credential fields accept Requestly [variables](../../environments-and-variables) and [vault](../../vault/vault) references. Store the key as a vault secret and reference it as `{{vault:hawk_key}}`. ### Optional | Field | Purpose | | - | - | | **User** | A local label for your own reference. Requestly does not send it, and it is not part of the MAC. | | **Nonce** | A unique value per request. Leave blank and Requestly generates a random one on every send. | | **Timestamp** | Unix time in seconds. Leave blank and Requestly uses the current time on every send. | | **ext** | Free-form application data. It is bound into the MAC and echoed in the header as `ext`. | | **app** | Application ID, from the Oz extension to Hawk. | | **dlg** | Delegated-by application ID, also from Oz. It is only sent when **app** is also set. | > [!TIP] > > Leave **Nonce** and **Timestamp** blank. A fresh nonce and a current timestamp are what stop a captured request from being replayed, and Requestly produces both for you. ### Include payload hash When this is on, Requestly hashes the request body and binds the result into the MAC, so the signature covers the body as well as the request line. Turn it on when the API validates payload integrity, and leave it off otherwise. A server that does not expect a payload hash will reject the request when one is present. ## Inherit Hawk from a collection Set Hawk once on the collection and leave every request inside it on **Inherit from parent**. Requestly walks up from the request to the nearest ancestor that sets a concrete auth type and signs with that credential pair. The nonce and timestamp are still generated per request, so inheriting one configuration does not reuse one signature. A request that picks its own auth type stops inheriting, and a collection or folder whose auth type is cleared or left unset stops the walk for everything below it. ## Troubleshooting > **The server rejects the MAC** > > Check the algorithm first: a `SHA-256` signature against a `SHA-1` verifier always fails. Then check that the key was pasted without a trailing newline, and that your machine clock is accurate, since most Hawk servers reject timestamps more than a minute or two out. > **Requests work without a body and fail with one** > > Turn **Include payload hash** off, or turn it on, depending on which side you changed. Both ends must agree on whether the body is part of the signature. > **The dlg value never reaches the server** > > `dlg` only travels when `app` is also set. Fill in **app** as well. ## What's Next? > **[AWS Signature v4](/api-client/send-api-request/authorization/aws-signature-v4)** > > The other per-request signing scheme in the dropdown. > **[Vault](/api-client/vault/vault)** > > Keep the Hawk key out of the collection. > **[Authorization](/api-client/send-api-request/authorization)** > > Back to every auth type Requestly supports. # JWT Bearer Source: https://docs.requestly.com/api-client/send-api-request/authorization/jwt-bearer Sign a fresh JSON Web Token on every send and attach it to the request. JWT Bearer builds and signs a JSON Web Token at the moment you press Send, then attaches it to the request. Use it when an API wants a signed assertion you generate yourself, rather than a token you fetched from an authorization server. If you already hold a token, use [Bearer token](/api-client/send-api-request/authorization#bearer-tokens) instead. If a provider issues tokens through a grant flow, use [OAuth 2.0](/api-client/send-api-request/authorization/oauth2). ![JWT Bearer form in the Authorization tab showing the algorithm dropdown, signing key, claim payload editor, JWT headers editor, and attachment fields.](https://mintcdn.com/requestly/eVaYS_FXw1j-9uVi/images/authorization/jwt-bearer-form.light.png?fit=max\&auto=format\&n=eVaYS_FXw1j-9uVi\&q=85\&s=ce534e5dc37f3e511d54cb4f4f8d228a) ## Set up JWT Bearer **1. Open the Authorization tab** Open any request or collection, then go to the **Authorization** tab. **2. Select JWT Bearer** Pick **JWT Bearer** from the **Authorization Type** dropdown. The JWT fields appear below the dropdown. **3. Pick an algorithm** Choose from the **Algorithm** dropdown. The choice decides what the signing key field expects: a shared secret for `HS*`, a private key for everything else. **4. Supply the signing key** For `HS*`, paste the shared secret. For `RS*`, `ES*`, and `PS*`, paste the whole PKCS#8 private key, including its `BEGIN PRIVATE KEY` and `END PRIVATE KEY` armor lines. **5. Write the claim payload** Edit **Payload (JSON)** to hold the claims the API expects, such as `sub`, `aud`, and `iss`. See the payload section below for the two things Requestly fills in for you. **6. Choose where the token goes** Leave **Add JWT to** on `Header` for the usual `Authorization: Bearer ` shape, or switch to `Query param` when the API reads the token from the URL. **7. Send the request** Click **Send**. Requestly signs a new token and attaches it. ## Algorithms Twelve algorithms are available, in four families: | Family | Algorithms | Signing key | | - | - | - | | **HMAC** | `HS256`, `HS384`, `HS512` | A shared secret string. | | **RSA PKCS#1 v1.5** | `RS256`, `RS384`, `RS512` | A PKCS#8 RSA private key. | | **ECDSA** | `ES256`, `ES384`, `ES512` | A PKCS#8 elliptic-curve private key. | | **RSA-PSS** | `PS256`, `PS384`, `PS512` | A PKCS#8 RSA private key. | `HS256` is the default on a new configuration. The unsigned `none` algorithm is refused and cannot be selected. The field shape follows the family. `HS*` shows a single-line secret box; every other family shows a multi-line editor, because a PEM key has to keep its line breaks. ### Secret is base64-encoded This checkbox appears for `HS*` only. Turn it on when the API gave you the shared secret as base64 rather than as plain text, so Requestly decodes it before signing instead of hashing the base64 characters themselves. ## Payload **Payload (JSON)** holds the token's claims. It must be a JSON object. Requestly applies two conveniences to the top level of that object before signing. ### iat is filled in for you Leave `iat` out, or set it to `null` or `""`, and Requestly writes the current time in seconds. Set it to a number and Requestly keeps your number exactly as written, which is what you want when reproducing a bug against a fixed timestamp. ### The expiresIn directive Write `{{expiresIn:}}` as a claim value and Requestly replaces it with the current time plus that duration. Units are `s`, `m`, `h`, and `d`. ```json theme={null} { "sub": "user-123", "aud": "https://api.example.com", "exp": "{{expiresIn:15m}}" } ``` Each send produces a token that expires fifteen minutes from that send, so a saved request never goes stale. Both conveniences apply to top-level claims only. Requestly passes an `iat` or an `{{expiresIn:…}}` value nested inside a sub-object through unchanged. > [!WARNING] > > The directive takes a whole number and one unit, with no spaces. `{{expiresIn:15m}}` works; `{{ expiresIn:15m }}`, `{{expiresIn:1.5h}}`, and `{{expiresIn:1h30m}}` do not. Requestly flags a malformed directive under the payload editor as you type, and refuses to sign with it. ## JWT headers **JWT headers (JSON)** sets the token's JOSE header. Leave it as `{}` for the common case: Requestly already sets `alg` from the dropdown. Use it when the API needs an extra header such as a `kid` key identifier: ```json theme={null} { "kid": "2026-prod-signing-key" } ``` ## Attachment **Add JWT to** decides where the signed token lands. **Header** Two further fields appear: * **Header name**, default `Authorization`. * **Prefix**, default `Bearer`. Clear it to send the bare token with no prefix. The result is a header such as `Authorization: Bearer eyJhbGciOi…`. **Query param** One further field appears: * **Param name**, default `token`. Requestly appends the token to the URL as `?token=eyJhbGciOi…`. > [!WARNING] > > A token in the URL is recorded by proxies, server access logs, and browser history. Prefer the header placement unless the API gives you no choice. ## Inherit JWT Bearer from a collection Set JWT Bearer once on the collection and leave every request inside it on **Inherit from parent**. Requestly walks up from the request to the nearest ancestor that sets a concrete auth type, and signs a fresh token per request from that configuration. A request that picks its own auth type stops inheriting, and a collection or folder whose auth type is cleared or left unset stops the walk for everything below it. ## Troubleshooting > **The API rejects the token signature** > > Confirm both sides agree on the algorithm, then confirm the key form. An `HS256` secret that the provider issued as base64 needs **Secret is base64-encoded** turned on; without it Requestly signs with the literal base64 characters and the signature will not verify. > **The key fails to parse** > > `RS*`, `ES*`, and `PS*` expect a PKCS#8 key, the block whose armor line reads `BEGIN PRIVATE KEY`. Convert an older PKCS#1 key, whose armor line reads `BEGIN RSA PRIVATE KEY`, first. Encrypted keys with a passphrase are not supported; decrypt a copy for use here. > **The token is always expired** > > A literal number in `exp` is a fixed point in time and goes stale the moment it passes. Replace it with `{{expiresIn:15m}}` so every send gets a fresh window. > **A warning sits under the payload editor** > > The payload is not valid JSON, or an `{{expiresIn}}` directive is malformed. The warning names which. Fix it before sending; Requestly will not sign an unparseable payload. ## What's Next? > **[OAuth 2.0](/api-client/send-api-request/authorization/oauth2)** > > Use a grant flow when the provider issues the token. > **[Vault](/api-client/vault/vault)** > > Keep the signing key out of the collection. > **[Authorization](/api-client/send-api-request/authorization)** > > Back to every auth type Requestly supports. # NTLM Source: https://docs.requestly.com/api-client/send-api-request/authorization/ntlm Authenticate against Windows and Active Directory endpoints with NTLM. NTLM is the challenge-response scheme Windows services use. It is what you reach for against IIS endpoints, on-premise SharePoint and Exchange, and internal APIs joined to an Active Directory domain. Like Digest, NTLM is a conversation rather than a single header. Requestly sends the request, reads the server's challenge, answers it with a response derived from your password, and replays. All three exchanges travel over the same connection. NTLM applies to HTTP requests. It is not offered for gRPC, and a WebSocket, Socket.IO, or GraphQL request cannot perform the handshake. > [!NOTE] > > NTLM authentication requires the desktop app. [Download Requestly](https://requestly.com/downloads). In the web app NTLM cannot be selected. ![NTLM form in the Authorization tab of the desktop app, showing username, password, domain, and workstation fields.](https://mintcdn.com/requestly/eVaYS_FXw1j-9uVi/images/authorization/ntlm-form-desktop.light.png?fit=max\&auto=format\&n=eVaYS_FXw1j-9uVi\&q=85\&s=798bae4dfecdca878ef85f99b72ebdc2) ## Set up NTLM **1. Open the Authorization tab** Open any request or collection in the desktop app, then go to the **Authorization** tab. **2. Select NTLM** Pick **NTLM** from the **Authorization Type** dropdown. The four NTLM fields appear below the dropdown. **3. Enter your domain credentials** Fill in **Username** and **Password**, then **Domain** if your account belongs to one. See the field reference below. **4. Send the request** Click **Send**. Requestly completes the three-message handshake and returns the authenticated response. ## Field reference | Field | Purpose | | - | - | | **Username** | Your account name. You can write it bare (`jdoe`) and set **Domain** separately, or use the combined `DOMAIN\jdoe` form and leave **Domain** blank. | | **Password** | The password for that account. | | **Domain** | The Active Directory or Windows domain the account belongs to, such as `CORP`. Leave blank for a local machine account. | | **Workstation** | Optional. The client machine name to report to the server. Most servers ignore it; leave it blank unless your administrator asks for a specific value. | All four fields accept Requestly [variables](../../environments-and-variables) and [vault](../../vault/vault) references. > [!WARNING] > > A domain password unlocks far more than one API. Store it as a [vault](../../vault/vault) secret and reference it as `{{vault:corp_password}}` so it never travels inside an exported collection. ## Inherit NTLM from a collection A domain usually fronts many endpoints, so NTLM is a good fit for collection-level auth. Set it once on the collection and leave every request inside on **Inherit from parent**. Requestly walks up from the request to the nearest ancestor that sets a concrete auth type. A request that picks its own auth type stops inheriting, and a collection or folder whose auth type is cleared or left unset stops the walk for everything below it. ## Troubleshooting > **NTLM is missing or unselectable in the dropdown** > > The web app cannot use NTLM. Open the same project in the [desktop app](https://requestly.com/downloads). In the desktop app, NTLM is also unavailable while the execution target is the Cloud Agent, so switch the target back to your own machine. > **The server returns 401 with correct credentials** > > Check how you split the account name. `DOMAIN\jdoe` in **Username** with `DOMAIN` also in **Domain** sends the domain twice and fails. Use one or the other. > **The endpoint expects Kerberos or Negotiate** > > Requestly signs with NTLMv2. A server configured for Kerberos or SPNEGO only will refuse the handshake. Ask your administrator whether the endpoint accepts NTLM fallback. ## What's Next? > **[Digest Auth](/api-client/send-api-request/authorization/digest)** > > The other challenge-response scheme in the dropdown. > **[Vault](/api-client/vault/vault)** > > Keep domain credentials off the collection. > **[Authorization](/api-client/send-api-request/authorization)** > > Back to every auth type Requestly supports. # OAuth 1.0 Source: https://docs.requestly.com/api-client/send-api-request/authorization/oauth1 Sign API requests with OAuth 1.0 using HMAC, RSA, or Plaintext signature methods. OAuth 1.0 is a signature-based authorization scheme. Each request is signed with credentials you hold (a consumer key and access token, plus secrets) using a signature method you pick. The signature, signing parameters, and your credentials are sent in the `Authorization` header or in the request body. Use OAuth 1.0 when an API explicitly requires it (Twitter API v1.1, older Atlassian and Yahoo APIs, parts of Magento, and various RFC 5849 implementations). Most modern APIs use OAuth 2.0 instead. > [!NOTE] > > **Availability:** OAuth authorization is available in the Requestly desktop app and is rolling out gradually. If **OAuth 1.0** does not appear in the auth-type dropdown, update to the latest version. ![OAuth 1.0 form in the Authorization tab with template values for consumer key, consumer secret, access token, token secret, signature method, and realm.](https://mintcdn.com/requestly/3K9ZnIMCMIAQfXVu/images/authorization/oauth1-form.light.png?fit=max\&auto=format\&n=3K9ZnIMCMIAQfXVu\&q=85\&s=42b73fa70e04e483c7da67dc45db5600) ## Choose OAuth 1.0 as the auth type **1. Open the Authorization tab** Open any request or collection, then go to the **Authorization** tab. **2. Select OAuth 1.0** Pick **OAuth 1.0** from the **Authorization type** dropdown. The OAuth 1.0 fields appear below the dropdown. **3. Fill in the required fields** See the field reference below. **4. Send the request** Click **Send**. Requestly computes the signature and attaches it to the request automatically. ## Field reference ### Credentials | Field | Purpose | | - | - | | **Consumer Key** | Public identifier the provider issued for your application. | | **Consumer Secret** | Shared secret paired with the consumer key. Used to sign the request. | | **Access Token** | Token that represents the resource owner's grant to your application. | | **Token Secret** | Shared secret paired with the access token. Used together with the consumer secret to sign the request. | All four fields accept Requestly [variables](../../environments-and-variables) and [vault](../../vault/vault) references. Reference secrets by name (for example `{{vault:twitter_consumer_secret}}`) rather than pasting them inline. ### Signature Method Pick the algorithm used to sign the request. Requestly supports seven methods: | Method | What it uses | | - | - | | **HMAC-SHA1** | HMAC keyed by your consumer and token secrets. Most widely supported. | | **HMAC-SHA256** | HMAC variant using SHA-256. Stronger than SHA-1; supported by newer providers. | | **HMAC-SHA512** | HMAC variant using SHA-512. | | **PLAINTEXT** | Sends the secrets directly, with no signing. Only safe over HTTPS. | | **RSA-SHA1** | RSA signature using your private key and SHA-1 digest. | | **RSA-SHA256** | RSA signature with SHA-256 digest. | | **RSA-SHA512** | RSA signature with SHA-512 digest. | > [!NOTE] > > When you pick an `RSA-*` method, an **RSA Private Key** field appears. Paste the PEM-encoded private key (the block that starts with `-----BEGIN RSA PRIVATE KEY-----` or `-----BEGIN PRIVATE KEY-----`). The consumer secret and token secret fields are still used to populate the standard OAuth parameters, but the signature itself is computed from the RSA key. ### Realm Optional. If the provider expects a `realm` parameter inside the `Authorization` header (RFC 5849 §3.5.1), set it here. Leave blank when the provider does not require it. ### Add params to Where to put the OAuth parameters. Two choices: * **Header** (default): Requestly sends them in the `Authorization` header as `OAuth oauth_consumer_key="…", oauth_token="…", …`. * **Body**: Requestly sends them as `application/x-www-form-urlencoded` fields in the request body. Only valid when the request has a form body and uses a method that carries one (`POST`, `PUT`, `PATCH`). Header is correct for the vast majority of providers. Use **Body** only if the API documentation specifies it. ### Include body hash When on, Requestly adds the `oauth_body_hash` extension parameter (OAuth Request Body Hash spec) to the signature for requests whose body is not `application/x-www-form-urlencoded`. Some providers (notably parts of the Yahoo and Google legacy APIs) require this; most do not. ### Add empty parameters When on, query parameters and form fields that have a name but an empty value are included in the signature base string. Some providers require empty parameters to be signed; the default is off because most do not. ### Encode OAuth params in header When on, the `oauth_*` values inside the `Authorization` header are percent-encoded a second time. This matches a stricter reading of RFC 5849 §3.5.1 that some providers enforce. If signature verification keeps failing for no obvious reason, try toggling this. ## What Requestly does for you automatically You do **not** need to fill in these OAuth parameters manually: * `oauth_nonce` (a fresh random nonce per request) * `oauth_timestamp` (current Unix time) * `oauth_signature_method` (driven by the Signature Method dropdown) * `oauth_version` (always `1.0`) * `oauth_signature` (computed from the signature base string and your secrets / private key) Requestly generates all five on every send, so the same configuration produces a fresh, valid signature each time. ## Troubleshooting > **The provider returns 401 Unauthorized** > > Recompute the signature manually using the provider's debugger (most large providers have one) and compare against Requestly's signature base string. The most common causes: > > * A required parameter is missing from the request (the API expects it, the signature base string excludes it). > * The clock on your machine is skewed by more than a few minutes - some providers reject stale timestamps. > * **Encode OAuth params in header** does not match the provider's expectation. Try toggling it. > **Signature\_invalid even though credentials look right** > > Check that **Consumer Secret** and **Token Secret** have not been accidentally URL-encoded before you pasted them in. Requestly performs the OAuth encoding itself; double-encoding produces an invalid signature. > **RSA signing fails with a key parse error** > > Confirm the key is PEM-encoded (begins with `-----BEGIN`). Encrypted PEM keys with a passphrase are not supported - decrypt the key first, or generate an unencrypted copy for use here. ## What's Next? > **[OAuth 2.0](/api-client/send-api-request/authorization/oauth2)** > > Set up grant-type-driven OAuth 2.0 flows. > **[Vault](/api-client/vault/vault)** > > Store OAuth secrets securely outside your collection. > **[Variables](/api-client/environments-and-variables)** > > Reference OAuth credentials by name across requests. # OAuth 2.0 Source: https://docs.requestly.com/api-client/send-api-request/authorization/oauth2 Acquire and attach OAuth 2.0 tokens across all six standard grant types, with built-in token caching and refresh. OAuth 2.0 is the dominant authorization framework for modern APIs. Requestly handles the entire flow: it opens the provider's consent screen when needed, exchanges the response for an access token, caches the token, refreshes it before it expires, and attaches it to every request. You pick a **grant type** that matches how the API issues tokens; Requestly shows the right fields for the grant you choose. > [!NOTE] > > **Availability:** OAuth authorization is available in the Requestly desktop app and is rolling out gradually. If **OAuth 2.0** does not appear in the auth-type dropdown, update to the latest version. ![OAuth 2.0 form in the Authorization tab showing the Authorization code grant with template values for auth URL, token URL, callback URL, client ID, client secret, and scope.](https://mintcdn.com/requestly/3K9ZnIMCMIAQfXVu/images/authorization/oauth2-form.light.png?fit=max\&auto=format\&n=3K9ZnIMCMIAQfXVu\&q=85\&s=544d28c15746429166d59d5b4dac41f6) ## Choose OAuth 2.0 as the auth type **1. Open the Authorization tab** Open any request or collection, then go to the **Authorization** tab. **2. Select OAuth 2.0** Pick **OAuth 2.0** from the **Authorization type** dropdown. **3. Pick a grant type** Use the **Grant type** dropdown at the top of the OAuth 2.0 form. Requestly swaps the field set to match. See [Grant types](#grant-types) below for which to pick. **4. Fill the fields and click Get token** The **Get token** button at the bottom of the form is enabled once all required fields are filled. Requestly runs the flow (opening the browser for grants that need user consent), stores the resulting token, and shows its status. **5. Send the request** Click **Send**. Requestly attaches the cached token as `Authorization: Bearer ` (the prefix is configurable - see [Token settings](#token-settings) below). ## Grant types Pick the grant that matches how the API issues tokens. If you are unsure, the provider's documentation will tell you. | Grant type | When to use | | - | - | | **Authorization code** | Server-to-server apps where the API has a confidential client secret. Most common for first-party integrations. | | **Authorization code (PKCE)** | Public clients (mobile, SPA, CLI) where you cannot keep a client secret. Adds a code challenge for binding the auth request to the token exchange. | | **Client credentials** | Service-to-service calls with no user involved. Authenticates the application itself. | | **Implicit** | Legacy browser-only flow. New integrations should use PKCE instead. Still required by a handful of older providers. | | **Password credentials** | Resource owner password grant. Only use with first-party apps where you control both ends and only when no other grant fits. | | **Manual token** | Paste an access token you obtained elsewhere. Useful for one-off testing or when the provider does not implement any standard grant. | ### Authorization code The standard three-legged flow. Requestly opens the provider's authorization page, the user signs in and consents, the provider redirects back with a code, and Requestly exchanges the code for a token at the token endpoint. | Field | Required | Purpose | | - | - | - | | **Auth URL** | Yes | Provider's authorization endpoint, e.g. `https://provider.example.com/oauth/authorize`. | | **Token URL** | Yes | Provider's token endpoint, e.g. `https://provider.example.com/oauth/token`. | | **Callback URL** | Yes | Redirect URI registered with the provider. See [Callback mode](#callback-mode-hosted-vs-embedded) below. | | **Client ID** | Yes | OAuth client identifier issued by the provider. | | **Client Secret** | Yes | OAuth client secret. Store in the [vault](../../vault/vault) rather than pasting it inline. | | **Scope** | Optional | Space-separated scopes you are requesting, for example `read:user write:user`. | | **State** | Optional | CSRF nonce. Requestly verifies it on the callback when set. | ### Authorization code (PKCE) Same as Authorization code, plus a code-challenge / code-verifier pair. Requestly generates and tracks both for you. Additional field: | Field | Required | Purpose | | - | - | - | | **Challenge method** | Yes | `SHA-256` (recommended) or `Plain`. SHA-256 is what RFC 7636 mandates for confidentiality; `Plain` exists only for legacy providers. | The **Client Secret** field is optional for PKCE - public clients omit it. ### Client credentials Two-legged flow. No user, no browser. | Field | Required | Purpose | | - | - | - | | **Token URL** | Yes | Provider's token endpoint. | | **Client ID** | Yes | OAuth client identifier. | | **Client Secret** | Yes | OAuth client secret. | | **Scope** | Optional | Space-separated scopes. | ### Implicit The provider returns the token directly in the redirect URL fragment. Avoid in new integrations. | Field | Required | Purpose | | - | - | - | | **Auth URL** | Yes | Provider's authorization endpoint. | | **Callback URL** | Yes | Redirect URI registered with the provider. | | **Client ID** | Yes | OAuth client identifier. | | **Scope** | Optional | Space-separated scopes. | | **State** | Optional | CSRF nonce. | ### Password credentials The user's username and password are exchanged directly at the token endpoint. Use only when you trust the client with the user's password. | Field | Required | Purpose | | - | - | - | | **Token URL** | Yes | Provider's token endpoint. | | **Client ID** | Yes | OAuth client identifier. | | **Client Secret** | Optional | OAuth client secret, when the provider expects one. | | **Username** | Yes | Resource owner's username. | | **Password** | Yes | Resource owner's password. Store in the [vault](../../vault/vault). | | **Scope** | Optional | Space-separated scopes. | ### Manual token For when you already have an access token from somewhere else and just want Requestly to attach it. No flow, no refresh. | Field | Required | Purpose | | - | - | - | | **Token** | Yes | The token to attach. Click **Save token** to store it. | ## Callback mode (hosted vs. embedded) Grants that involve a browser redirect (Authorization code, Authorization code with PKCE, Implicit) expose a **Use embedded browser** toggle. * **Hosted callback** (default): the OAuth handshake happens in your system browser, with Requestly's hosted callback URL (`https://oauth.requestly.com/callback`) catching the redirect and handing the code back to the app. The **Callback URL** field is auto-populated and read-only. Use this when you can register `https://oauth.requestly.com/callback` (or the staging equivalent) with the provider. * **Embedded browser**: the OAuth handshake happens inside an in-app browser window. The **Callback URL** field becomes editable - set it to any redirect URI you have already registered with the provider. The URL is never fetched; Requestly intercepts the navigation as soon as the provider redirects to it. Use this when the provider restricts redirect URIs to URLs you control. > [!WARNING] > > Some enterprise identity providers detect embedded webviews and refuse to load the consent page (commonly seen with strict conditional-access, advanced-protection, or anti-phishing policies). When that happens, switch back to **Hosted callback** and register Requestly's callback URL with the provider. > [!NOTE] > > Whichever mode you pick, the redirect URI shown in the **Callback URL** field must be listed in your OAuth app's allowed redirect URIs on the provider side. Most "invalid redirect URI" errors during the consent flow come from forgetting this step. Register the URL once in the provider's developer console before clicking **Get token**. ## Token settings These cross-grant fields appear below the grant-specific fields (everywhere except **Manual token**). ### Header prefix The scheme Requestly puts in front of the token in the `Authorization` header. Defaults to `Bearer`, which is what almost every provider expects. Override only if the provider documents a different prefix (for example `Token` or an empty string). ### Token selection For providers that return both an access token and an OpenID Connect ID token in the same response. Pick which one to attach to outgoing requests: * **Access token** (default): the standard OAuth 2.0 access token. * **ID token**: the OIDC ID token. Pick this when you are calling an endpoint that authenticates the user identity rather than authorizing API access. ### Custom auth, token, and refresh parameters Three collapsible tables for additional parameters most providers do not need: * **Custom auth parameters**: extra query parameters appended to the authorization URL. Use for vendor-specific extensions like `audience`, `prompt`, or `login_hint`. * **Custom token parameters**: extra form fields appended to the token-exchange request body. * **Custom refresh parameters**: extra form fields appended to refresh-token requests. Each row has a name, a value, and an enable toggle. Disabled rows are kept in the configuration but skipped at send time. ## Token lifecycle Once you click **Get token**, the panel at the bottom of the form shows the token's status. The panel updates without you having to refresh the form. | Status | What it means | | - | - | | **No token acquired yet** | The flow has not been run yet. Click **Get token**. | | **Acquiring token…** | The flow is running. Cancel it, or click **Restart** to start over. | | **Bearer** badge with countdown | A valid token is cached. The countdown shows time until expiry. Click **Clear token** to invalidate it. | | **Token expired** | The cached token's lifetime is up and there is no refresh token. Click **Get token** to start a new flow. | | **Refreshing token…** | The cached token expired but a refresh token is available; Requestly is exchanging it for a fresh access token. | | **Failed** with detail | The flow failed - the panel shows the headline and detail from the provider. Click **Retry** to run it again. | Tokens are cached per authorization configuration. If you change a field that affects the token (Client ID, Auth URL, Scope, etc.), clear the existing token first to avoid stale cache hits. ### How refreshes happen Requestly refreshes tokens **lazily, at send time**. There is no background timer that pre-refreshes before expiry. Instead: * When you click **Send** and the cached token is still valid, Requestly attaches it as-is. * When the cached token has expired and the provider returned a refresh token, Requestly exchanges the refresh token for a new access token before sending the request. Concurrent sends share a single refresh, so you do not end up with parallel refresh calls hitting the provider. * When the cached token has expired and there is no refresh token, the request fails with a refresh error and the panel switches back to **Token expired**. Click **Get token** to run the grant flow again. To force a fresh token before expiry (for example, after rotating client credentials on the provider side), click **Clear token** and then **Get token**. The **Custom refresh parameters** table under [Token settings](#custom-auth-token-and-refresh-parameters) appends extra fields to the refresh request body when your provider needs them (some providers expect a repeated `scope` or `audience` parameter on refresh). ## Variables and the vault All OAuth 2.0 fields accept Requestly [variables](../../environments-and-variables) and [vault](../../vault/vault) references. For long-lived credentials (client secrets, RSA keys, user passwords), store the value once in the vault and reference it by name in the form. The reference is what gets exported when you share a collection; the underlying secret stays on your machine. ## What's Next? > **[OAuth 1.0](/api-client/send-api-request/authorization/oauth1)** > > Sign requests with the older signature-based OAuth scheme. > **[Vault](/api-client/vault/vault)** > > Store OAuth client secrets and passwords securely. > **[Variables](/api-client/environments-and-variables)** > > Reference OAuth credentials by name across requests. # Cookies Source: https://docs.requestly.com/api-client/send-api-request/cookies Manage cookies for your API requests in Requestly. Cookies captured from responses are stored in a shared cookie jar and automatically attached to matching outgoing requests. Requestly keeps a built-in cookie jar that captures cookies from API responses and replays them on later requests. This mirrors how a browser handles cookies, so you can reproduce session-based flows (login, then call protected endpoints) without copying values around by hand. > [!NOTE] > > The cookie jar is shared across all your projects on this device. It is stored locally and never synced to the cloud, so session tokens stay on the machine that captured them. Switching projects or environments does not switch the jar. > [!NOTE] > > **Availability:** The cookie jar is a desktop-app feature and is rolling out gradually. If you don't see the **Cookies** entry in the app footer, update to the latest version. ## Open the Cookie manager **1. Click Cookies in the footer** The **Cookies** button is in the application footer at the bottom of the window. Clicking it opens the **Cookie manager** modal. **2. Browse cookies by domain** The **Cookies** tab lists every cookie in the jar, grouped by host. Click a host row to expand it and see the cookies stored for that domain. ## How cookies are captured When a response includes one or more `Set-Cookie` headers, Requestly parses each cookie and stores it in the jar. Once the cookie jar is available for your build, this capture happens automatically. The next time you send a request whose URL matches the cookie's domain and path, Requestly attaches the cookie to that request as a `Cookie` header. Matching follows standard browser rules (RFC 6265): * Cookies are matched on the request URL's hostname and path. * A cookie with `Domain=.example.com` is sent to `api.example.com`, `www.example.com`, and any other subdomain. * A cookie with no `Domain` attribute is scoped to the exact host that set it. * Path scoping is enforced. A cookie with `Path=/api` is not sent to `/`. > [!NOTE] > > If you set a `Cookie` header manually on a request, your value wins. The jar will not overwrite a header you wrote yourself. ## Add a cookie manually You can plant cookies in the jar without sending a request first. This is useful when you want to seed a session token from another tool, or when you are testing how an endpoint behaves under a specific cookie. **1. Open the add cookie modal** In the **Cookies** tab, click the **+** button next to the search field. The tooltip reads **Add cookie (any domain)**. To add a cookie scoped to a specific host that already appears in the list, click the **+** button on that host's row instead. The modal title shows the host so you know which domain the cookie will land on. **2. Paste a Set-Cookie value** The modal accepts a single `Set-Cookie` header value, the same string a server would send. For example: ``` sessionId=abc123; Path=/; Secure; HttpOnly; SameSite=Lax ``` Supported attributes: `Domain`, `Path`, `Expires`, `Max-Age`, `Secure`, `HttpOnly`, `SameSite`, `Partitioned`. Hover the help icon next to the modal title for a quick reference. When `Domain=` is omitted, the cookie is scoped to the host shown in the modal title. **3. Save** Click **Save**. The cookie appears under its host in the **Cookies** tab and will be attached to matching requests from now on. ## Edit, delete, or clear cookies Hover any cookie row to reveal its action buttons: * **Edit cookie** opens the same modal pre-filled with the existing `Set-Cookie` string. Change anything, then save. * **Delete cookie** removes a single cookie immediately. To clear cookies in bulk: * **Clear cookies for this domain** is the trash icon on a host row. It removes every cookie under that host after a confirmation prompt. * **Clear all cookies** is the sweep icon next to the search field. It empties the entire jar after a confirmation prompt. > [!WARNING] > > Clearing cookies is local and immediate. There is no undo. If you cleared cookies you needed, the only way to recover them is to send the request that originally set them. ## Find a cookie quickly The search input at the top of the **Cookies** tab filters the list as you type. Search matches across host, name, and path, so you can locate a single cookie even when the jar holds hundreds of entries across many domains. ## Cookie row indicators Each cookie row shows badges and icons that summarize its attributes: * An **Expires** date or **Session** label. Expired cookies show a red **Expired** badge but stay in the jar until you remove them. * A **lock** icon means `Secure` is set: the cookie is only sent over HTTPS. * A **shield** icon means `HttpOnly` is set: the cookie is hidden from scripts. * A **SameSite** badge (`Lax`, `Strict`, or `None`) reflects the cookie's `SameSite` attribute. ## Allow scripts to read cookies Pre and post-request scripts can read and write cookies, but only for domains you have explicitly allowed. This keeps a third-party request you import from accidentally exfiltrating cookies for an unrelated host. **1. Open the Domains allowlist tab** In the **Cookie manager**, switch to the **Domains allowlist** tab. **2. Add a host** Type a host (for example `api.example.com`) into the input and click **Add**. The host appears in the list below. **3. Revoke when no longer needed** Hover a host in the list and click **Revoke** to remove it from the allowlist. Scripts can no longer access cookies for that host until you add it back. > [!NOTE] > > The allowlist only governs script access to the jar. Cookies are still captured from responses and attached to requests automatically regardless of whether their host is allowlisted. ## What's Next? > **[Authorization](/api-client/send-api-request/authorization)** > > Configure auth alongside cookies for full session reproduction > **[Request Headers](/api-client/send-api-request/create-requests/request-headers)** > > Override jar-attached cookies with a manual `Cookie` header > **[Scripts](/api-client/scripts)** > > Read and write cookies from pre and post-request scripts # Configure Request Source: https://docs.requestly.com/api-client/send-api-request/create-requests/configure-request Learn how to configure HTTP methods, URLs, and send API requests in Requestly. This guide covers how to set up HTTP methods, URLs, and send requests effectively. ## HTTP Methods Requestly supports all standard HTTP methods for API requests: **GET** **GET** retrieves data from a server. It's the most common method for fetching resources. **Use cases:** * Fetch user data * Get list of items * Retrieve resource details **POST** **POST** sends data to create a new resource on the server. **Use cases:** * Create new user * Submit form data * Upload content **PUT** **PUT** updates an existing resource by replacing it entirely. **Use cases:** * Update user profile * Replace document * Modify configuration **PATCH** **PATCH** partially updates an existing resource. **Use cases:** * Update specific fields * Modify user settings * Change status **DELETE** **DELETE** removes a resource from the server. **Use cases:** * Delete user account * Remove item * Clear cache **HEAD** **HEAD** retrieves only the headers of a resource without the body. It's identical to GET but without the response body. **Use cases:** * Check if resource exists * Get content length before downloading * Verify last modified date **OPTIONS** **OPTIONS** retrieves the communication options available for a resource or server. **Use cases:** * Check supported HTTP methods * Verify CORS configuration * Discover API capabilities ## Setting Up Your Request URL The request URL specifies where your API request should be sent. It consists of several components: ![URL Structure](https://mintcdn.com/requestly/Gag9_SKIhyHPyhE2/images/url-structure.png?fit=max\&auto=format\&n=Gag9_SKIhyHPyhE2\&q=85\&s=a092829fef7facb03140dd61be097cb0) ## Naming Your Request Give your request a clear, descriptive name to easily identify it later: **Good naming examples:** * `Get User Profile` * `Create New Order` * `Update Product Inventory` * `Delete Customer Account` **Avoid:** * `Test` * `Request 1` * `API Call` > [!TIP] > > Use action verbs and specific resource names to make your requests self-documenting. This helps when sharing with team members or revisiting later. ## Sending Your Request Once you've configured your request: **1. Save Your Configuration** Click the **Save** button to preserve your request settings. This allows you to reuse it later without reconfiguring. **2. Click Send** Press the **Send** button to execute the request. It will display the response in the panel below. **3. Review Response** Check the response `status code`, `body`, and `headers` to verify the request was successful. **Common status codes:** * `200 OK` - Success * `201 Created` - Resource created * `400 Bad Request` - Invalid request * `401 Unauthorized` - Authentication required * `404 Not Found` - Resource doesn't exist * `500 Server Error` - Server-side issue ## What's Next? > **[Add Parameters](/api-client/send-api-request/parameters-and-body)** > > Learn how to add query params, path variables, and request body > **[Configure Headers](/api-client/send-api-request/request-headers)** > > Set up authentication and custom headers # Generate Client Code Source: https://docs.requestly.com/api-client/send-api-request/create-requests/generate-client-code Export any API request as ready-to-run code in cURL, Python, JavaScript, Go, Java, C#, Swift, PHP, and 20+ other language/library combinations. Requestly can convert any configured API request into a ready-to-paste code snippet. Use this to move from manual testing to implementation without rewriting the request from scratch. ## How to Generate Client Code **1. Open API Request** Navigate to the API request for which you want to generate code. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/generate-client-code/25955bc2-a37e-4300-a12d-c980ca562db8.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=1f2c53ef4e937ca9854a5f553f16c5cb) **2. Open the code snippet** Click the **Get client code** button in the request editor header (next to the request actions). ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/generate-client-code/4f431083-0dc2-42af-94f2-aef5824a8533.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=10c4defef12648cea08c4b01eee9dcce) **3. Choose a Programming Language** A modal opens with the generated code. Use the dropdown at the top left to switch languages. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/generate-client-code/ae31c8af-dac9-478d-8ec2-422b1f5cf462.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=e3cf161ac79d308cd588dd8ebd9bc980) **4. Copy the Code** Click **Copy** in the top right corner to copy the snippet to your clipboard. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/generate-client-code/252eed1c-d8bc-4d01-886e-385eee8b89c9.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=9e2658dc244ae86587ee135f7af55257) ## Example Output For a `POST https://api.example.com/users` request with a JSON body and a Bearer token, here is what the generated code looks like per language: **Shell - cURL** ```bash theme={null} curl --request POST \ --url https://api.example.com/users \ --header 'Authorization: Bearer YOUR_TOKEN' \ --header 'Content-Type: application/json' \ --data '{"name":"Jane Doe","email":"jane@example.com"}' ``` **JavaScript - Fetch** ```javascript theme={null} const response = await fetch("https://api.example.com/users", { method: "POST", headers: { "Authorization": "Bearer YOUR_TOKEN", "Content-Type": "application/json" }, body: JSON.stringify({ name: "Jane Doe", email: "jane@example.com" }) }); const data = await response.json(); console.log(data); ``` **Python - Requests** ```python theme={null} import requests url = "https://api.example.com/users" headers = { "Authorization": "Bearer YOUR_TOKEN", "Content-Type": "application/json" } payload = {"name": "Jane Doe", "email": "jane@example.com"} response = requests.post(url, json=payload, headers=headers) print(response.status_code, response.json()) ``` **Go - Native** ```go theme={null} package main import ( "bytes" "fmt" "io" "net/http" ) func main() { body := bytes.NewBufferString(`{"name":"Jane Doe","email":"jane@example.com"}`) req, _ := http.NewRequest("POST", "https://api.example.com/users", body) req.Header.Set("Authorization", "Bearer YOUR_TOKEN") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) fmt.Println(string(data)) } ``` **Java - OkHttp** ```java theme={null} OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, "{\"name\":\"Jane Doe\",\"email\":\"jane@example.com\"}"); Request request = new Request.Builder() .url("https://api.example.com/users") .post(body) .addHeader("Authorization", "Bearer YOUR_TOKEN") .addHeader("Content-Type", "application/json") .build(); Response response = client.newCall(request).execute(); System.out.println(response.body().string()); ``` **C# - HttpClient** ```csharp theme={null} using var client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_TOKEN"); var content = new StringContent( "{\"name\":\"Jane Doe\",\"email\":\"jane@example.com\"}", System.Text.Encoding.UTF8, "application/json"); var response = await client.PostAsync("https://api.example.com/users", content); Console.WriteLine(await response.Content.ReadAsStringAsync()); ``` **Swift - URLSession** ```swift theme={null} var request = URLRequest(url: URL(string: "https://api.example.com/users")!) request.httpMethod = "POST" request.setValue("Bearer YOUR_TOKEN", forHTTPHeaderField: "Authorization") request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = #"{"name":"Jane Doe","email":"jane@example.com"}"#.data(using: .utf8) let (data, response) = try await URLSession.shared.data(for: request) print(String(data: data, encoding: .utf8)!) ``` **PHP - cURL** ```php theme={null} **[Configure Request](/api-client/send-api-request/create-requests/configure-request)** > > Set up HTTP methods, URLs, and send your first request > **[Parameters and Body](/api-client/send-api-request/create-requests/parameters-and-body)** > > Add query parameters, path variables, and request body data > **[Request Headers](/api-client/send-api-request/create-requests/request-headers)** > > Configure headers for authentication and content types # Parameters and Body Data Source: https://docs.requestly.com/api-client/send-api-request/create-requests/parameters-and-body Learn how to add query parameters, path variables, and request body data to your API requests in Requestly. Parameters and request bodies allow you to send data with your API requests. This guide covers query parameters, path variables, and different request body formats. ## Path Variables Path variables allow you to define dynamic segments in your API URL using the **:variableName** syntax. This is useful for RESTful APIs where resource identifiers are part of the URL path. For example, if your API endpoint is: ``` https://api.example.com/users/:userId/posts/:postId ``` Requestly automatically detects the path variables (`:userId` and `:postId`) from the URL and displays them in the **Params** tab under **Path Variables**. You can then set values for each variable: | Key | Value | Description | | - | - | - | | userId | 123 | The user's unique identifier | | postId | 456 | The post's unique identifier | When you send the request, Requestly compiles the URL with your provided values: ``` https://api.example.com/users/123/posts/456 ``` > [!TIP] > > Path variables are automatically extracted from your URL. Simply type a URL with `:variableName` segments, and they'll appear in the Path Variables table for you to fill in. ## Query Parameters In the **Query Params** section, you can add query parameters as **key-value pairs** to send extra information with the URL. To add more parameters, click on the `+ Add More` button. Each query parameter consists of: * **Key**: The parameter name * **Value**: The parameter value * **Type**: An enum to enforce the value type * **Description** (optional): Internal documentation explaining the purpose of the parameter For example: * Adding `uid=123` to `https://app.requestly.io/echo` results in: `https://app.requestly.io/echo?uid=123` > [!TIP] > > The checkboxes next to each parameter let you include or exclude them without deleting them. For instance, if you uncheck a parameter, the final URL will not include it. ### Bulk Edit Query Parameters ![](https://mintcdn.com/requestly/hqaBs_u8toaieppT/images/QueryParam-1.png?fit=max\&auto=format\&n=hqaBs_u8toaieppT\&q=85\&s=181c19a0ccdf064958641adf0b4fbe7c) You can also manage query parameters using **Bulk Edit**. This allows you to add or update multiple parameters at once in a key:value format. * Add one parameter per line * Separate keys and values using a colon `:` * Prefix any line with `//` to disable that parameter Bulk Edit is useful when working with a large number of query parameters or when making quick mass updates. **Example:** ``` page:1 limit:50 sort:desc // filter:active ``` ## Request Body For POST, PUT, or PATCH requests, use the **Body** tab to send data to the server. Requestly supports multiple body formats to accommodate different API requirements. ### Supported Body Types **RAW (JSON/Text)** Send raw data as plain **text** or structured **JSON**. **When to use:** * Sending JSON data to REST APIs * Posting XML or plain text * Sending custom formatted data You can select the language format: * **JSON** – for structured data like API payloads * **Text** – for plain string or unstructured data * **XML** – for XML-based APIs * **HTML** – for HTML content * **JavaScript**: for JavaScript payloads ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/send-api-request/76a50480-84ca-4ffd-87c0-cf27e0e5208b.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=450022384d7075f9dbaf4e4ff731111f) **Example JSON:** ```json theme={null} { "name": "John Doe", "email": "john@example.com", "age": 30, "active": true } ``` **x-www-form-urlencoded** Sends data as URL-encoded key-value pairs. This format is commonly used for HTML form submissions. **When to use:** * Traditional web form submissions * Simple key-value data * APIs that expect form data Each field consists of: * **Key**: Field name * **Value**: Field value * **Description**: Optional documentation ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/send-api-request/79119883-fd9d-4b33-b617-4f7a7bf36f0e.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=7769dbe319598a3a103a6b84c196f6ea) **Example:** ``` username=johndoe password=secret123 remember=true ``` **multipart/form-data** Used when uploading files along with form fields. Each field is sent as a separate part of the request body. **When to use:** * Uploading images, documents, or files * Sending files with metadata * Form submissions with file attachments Each field can be either: * **Text field**: Regular key-value pair * **File field**: File upload with browse button ![](https://mintcdn.com/requestly/C-8RNowaOOgmOMj9/images/send-api-request/fa74f6c1-8ebb-4652-8667-7993cc3d57f7.png?fit=max\&auto=format\&n=C-8RNowaOOgmOMj9\&q=85\&s=dc6acaa14725584cd91c4f70e0eae999) **Example use case:** Uploading a user profile picture with name and bio ### Per-field Content-Type Each row has a **Content-Type** column. It sets the `Content-Type` header of that one part. Text rows and file rows both support it. Use it when an API needs a typed part. The common case is one JSON metadata part plus one file part in the same request: | Key | Type | Value | Content-Type | | - | - | - | - | | `metadata` | Text | `{"title":"Q3 contract"}` | `application/json` | | `file` | File | `contract.pdf` | `application/pdf` | That request goes on the wire as: ``` --BOUNDARY Content-Disposition: form-data; name="metadata" Content-Type: application/json {"title":"Q3 contract"} --BOUNDARY Content-Disposition: form-data; name="file"; filename="contract.pdf" Content-Type: application/pdf --BOUNDARY-- ``` `BOUNDARY` is the delimiter Requestly generates. It also appears in the request-level `Content-Type` header, as `multipart/form-data; boundary=BOUNDARY`. > [!NOTE] > > Leave the field empty to use the default. The placeholder shows `Auto`. An empty > value on a **text** row sends no `Content-Type` header for that part. An empty > value on a **file** row sends `application/octet-stream`. Requestly does not validate the value. You can enter any string, including an invalid MIME type, because a wrong content type is sometimes the case under test. Postman imports and exports carry this field on text rows, so the value survives a round-trip. File rows are a separate matter: Requestly cannot export the local file itself, so re-attach files after an import. Generated code snippets carry the value in curl: each typed part gains `;type=` in its `--form` argument. Other snippet languages follow their generator's capability. `python/requests` keeps the type on file parts and drops it on text parts. Most other languages do the same. A few drop it on both parts, and a few keep it on both. Check the generated snippet before you rely on it for a typed part. **GraphQL** For GraphQL APIs, use the dedicated GraphQL request type which provides: * Query/Mutation editor with syntax highlighting * Variables panel * Schema introspection, or a schema you attach yourself from a file or a URL Learn more in our [GraphQL Request guide](../graphql-request). ## Autogenerated Headers Requestly will automatically add certain headers to your requests based on your request body selections. When you add a request body, Requestly automatically sets the appropriate `Content-Type` header: | Body Type | Content-Type Header | | - | - | | RAW (JSON) | `application/json` | | RAW (Text) | `text/plain` | | RAW (XML) | `application/xml` | | RAW (HTML) | `text/html` | | RAW (JavaScript) | `application/javascript` | | x-www-form-urlencoded | `application/x-www-form-urlencoded` | | multipart/form-data | `multipart/form-data` | > [!TIP] > > You can view and override the autogenerated headers in the Headers tab. These headers are automatically managed by Requestly to ensure your requests are properly formatted. ## What's Next? > **[Configure Headers](/api-client/send-api-request/request-headers)** > > Add authentication and custom headers to your requests > **[Add Authorization](/api-client/authorization)** > > Set up API authentication methods > **[Use Variables](/api-client/environments-and-variables)** > > Make your requests dynamic with variables # Request Headers Source: https://docs.requestly.com/api-client/send-api-request/create-requests/request-headers Learn how to configure HTTP headers for authentication, content types, and custom metadata in your API requests. HTTP headers are key-value pairs that provide additional information about your request. They're essential for authentication, specifying content types, and sending custom metadata to the API. ## Understanding Headers Headers serve multiple purposes in HTTP requests: > **Authentication** > > Pass tokens, API keys, or credentials to authenticate with the API > **Content Type** > > Tell the server what format your data is in (JSON, XML, etc.) > **Accept Type** > > Specify what response format you expect from the server > **Custom Metadata** > > Send additional information like user agent, tracking IDs, or custom flags *** ## Adding Headers The **Headers** tab allows you to add Request Headers in your API request. Each header consists of: * **Key**: The header name (e.g., `Authorization`, `Content-Type`) * **Value**: The header value * **Description** (optional): Internal documentation to explain the purpose of this header ![Headers - Send API Request](https://mintcdn.com/requestly/hxDG-lNXUZAdWoty/images/Headers-Create-Requests.png?fit=max\&auto=format\&n=hxDG-lNXUZAdWoty\&q=85\&s=6110acb3c0cefae6cc1cf3fac2130b31) > [!TIP] > > The checkboxes next to each header let you include or exclude them without deleting them. This is useful for testing with and without certain headers. ### Bulk Edit Headers You can also manage headers using **Bulk Edit**. This allows you to add or update multiple headers at once in a `key:value` format. **How to use:** 1. Click the **Bulk Edit** button in the Headers tab 2. Add one header per line 3. Separate keys and values using a colon `:` 4. Prefix any line with `//` to disable that header **Example:** ``` Content-Type:application/json Authorization:Bearer {{token}} X-API-Version:v2 // X-Debug:true ``` > [!TIP] > > Bulk Edit is especially useful when copying headers from documentation or sharing with team members. ## Using Variables in Headers You can use variables in header values to make them dynamic: ``` Key: Authorization Value: Bearer {{authToken}} ``` > [!NOTE] > > Learn more about using variables in [Variables and Environments](/api-client/environments-and-variables). ## Header Inheritance Headers can be inherited from collections, making it easy to apply common headers across multiple requests: **Collection-Level Headers** → **Request-Level Headers** → **Authorization Tab** * **Collection-Level Headers**: Set headers at the collection level to apply them to all requests in that collection. * **Request-Level Headers**: Override collection-level headers with the same key. Request-level headers have the highest priority. * **Authorization Tab**: Headers set in the Authorization tab are applied in addition to manual headers and do not override them. > [!NOTE] > > Headers are resolved from most-specific to least-specific. Request-level headers always win over collection-level headers when both define the same key. ## What's Next? > **[Add Authorization](/api-client/send-api-request/authorization)** > > Use the Authorization tab for easier authentication setup > **[Use Scripts](/api-client/send-api-request/save-and-manage-data)** > > Dynamically generate headers with pre-request scripts > **[Environment Variables](/api-client/environments-and-variables)** > > Learn how to use variables in headers # Filter a JSON Response Source: https://docs.requestly.com/api-client/send-api-request/filter-json-response Narrow a JSON response in Requestly to just the values you care about using a JSONPath expression in the Preview view. When an endpoint returns a large JSON response, scrolling to the few fields you actually care about is slow. The **Preview** view of the response body lets you type a JSONPath expression and narrow the displayed JSON to only the matching values, the same way Postman does. ## Open the filter bar The filter is available in the **Preview** view when the response is JSON. **1. Send a request that returns JSON** Send any request whose response is JSON. The body opens in the **Preview** view, formatted and syntax-highlighted. **2. Click the funnel icon** In the response body toolbar, click the funnel icon on the right. A full-width filter bar appears below the toolbar. ![The JSON response Preview view with the funnel icon highlighted and the filter bar revealed below the toolbar](https://mintcdn.com/requestly/EuyRJ2u2abyeba23/images/response-json-filter-bar.light.png?fit=max\&auto=format\&n=EuyRJ2u2abyeba23\&q=85\&s=76d0e0fe8c86a139bfb37d4b2b567c0b) **3. Type a JSONPath expression** Enter an expression such as `$.store.book[*].author`. The displayed JSON narrows to the matched values as you type. ![A JSON response narrowed to the matched values after typing a JSONPath expression in the filter bar](https://mintcdn.com/requestly/EuyRJ2u2abyeba23/images/response-json-filter-applied.light.png?fit=max\&auto=format\&n=EuyRJ2u2abyeba23\&q=85\&s=336c3d536e09507ec91d4448f185da9d) ## Write the expression The filter uses standard JSONPath. A few common patterns: | Expression | Selects | | - | - | | `$.store.book[*].author` | The `author` of every book under `store.book` | | `$.items[?(@.price < 10)]` | Every item in `items` whose `price` is below 10 | | `$.headers` | The whole `headers` object | | `$.results[0]` | The first element of the `results` array | # GraphQL Request Source: https://docs.requestly.com/api-client/send-api-request/graphql-request Requestly supports GraphQL requests, allowing you to send queries, mutations, and define variables GraphQL requests work over HTTP just like REST, but instead of defining multiple endpoints, you typically interact with a **single endpoint** (e.g., `/graphql`) and specify the exact data you want. This gives you flexibility, reduces over-fetching, and makes debugging APIs much simpler. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/b393cc24-502b-4229-80e0-fd5b75a374cf.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=e8628fa6787dbc4a6e776aca492f0acd) ## Create your first GraphQL request **1. Open API Client and Create a New Request** Open **Requestly Desktop App**, then click the `+ New` button to create a new request and select **GraphQL request** from the menu. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/9e445125-233d-4086-bbb1-913887d4edfd.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=2224cfb28115309c133ce3812030bd83) **2. Name Your API Request** Give a descriptive title for your request to make it easy to identify later ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/08acf961-0623-4ec8-a7a9-c9eebd57ca82.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=d5d93cefd173c4a966c1c959d80fb9d3) **3. Enter the GraphQL server URL** Add your GraphQL endpoint. > [!NOTE] > > It will automatically perform **schema introspection** so you can explore available queries, mutations, and types. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/8c9a443f-86dc-489c-94e5-84e5f33a7c9c.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=8e0250fd4795ceb846fca178af56951b) **4. Explore the schema** Under the **Query** tab, you’ll see three panels: * **Query/Mutation editor**: where you write or generate queries. * **Variables editor**: where you define variables in JSON format. * **Schema explorer**: where you browse your API’s schema (Queries, Mutations, Subscriptions). If the panel is closed, the **Schema** button at the right-hand end of the tab strip reopens it, and that button disappears while the panel is open. > [!NOTE] > > The **Schema** button described here only opens this explorer panel. The separate **Schema** tab in the same tab strip is where you attach a schema document, covered in [Attach a schema from a file or URL](#attach-a-schema-from-a-file-or-url). ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/c674ba8c-8ead-4c18-95a2-8197e8dc460c.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=87f2a6a40779e5f982e8f300a177a48b) **5. Build your query** In the schema explorer, select a field and expand its arguments. A query will automatically appear in the **Query editor**.\ Alternatively, you can write your query manually ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/468ee277-2628-4400-bfd1-06dcaaaa7583.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=b35c1ca15fc5f8da06ed53c5f5272f63) **6. Add variables (optional)** In the **Variables editor**, provide values in JSON format. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/e547f084-420b-409b-8d51-dd0b925a5b39.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=4dd2d365ee0c914c826adf314b9d8556) **7. Send the request** Click **Send** to execute your query and view the response. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/6bbd5f6f-29c3-48d7-8e10-9384b2d86ff3.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=0c7f587a0ca519bae8b6c0656524d8ae) ### Create a GraphQL request with multiple queries **1. Create a new request** Open **Requestly Desktop App**, then click the `+ New` button to create a new request and select **GraphQL request** from the menu. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/9e445125-233d-4086-bbb1-913887d4edfd.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=2224cfb28115309c133ce3812030bd83) **2. Select multiple fields** From the schema explorer, select more than one field. Both queries will appear in the **Query editor**. Alternatively, you can manually add a new query / mutation. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/c674ba8c-8ead-4c18-95a2-8197e8dc460c.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=87f2a6a40779e5f982e8f300a177a48b) **3. Choose a query to run** Only one query runs at a time. First, click the **Send** button, then select the query you want to run from the dropdown. To execute another query, click the Send button again and select the other query from the dropdown. ![](https://mintcdn.com/requestly/Z9psaKI2OUaqbNe1/images/graphql-request/6f82178d-a478-40a6-9f99-03f066ee2cb4.png?fit=max\&auto=format\&n=Z9psaKI2OUaqbNe1\&q=85\&s=e55f21cab6f31d489d8091c549b3b29a) ## Attach a schema from a file or URL By default a GraphQL request builds its schema by introspecting whatever endpoint is in the URL bar, and that keeps working exactly as before. Attach a schema document yourself when introspection is turned off on the server, when the schema you develop against is not the one that endpoint serves yet, or when you keep the schema in your repository. > [!NOTE] > > Attaching a schema is rolling out gradually. If your GraphQL requests show no **Schema** tab, it is not enabled for your account yet. ![The Schema tab of a GraphQL request with nothing attached, showing the schema picker, the Import a GraphQL schema link and the Use GraphQL introspection link](https://mintcdn.com/requestly/R1c-VDYdoBMf7TWZ/images/graphql-schema-tab-unattached.light.png?fit=max\&auto=format\&n=R1c-VDYdoBMf7TWZ\&q=85\&s=0e8e75336ed02586ab3d4a8804e0a086) The tab gives you three ways to get a schema, and they are mutually exclusive. Attaching a document turns introspection off for that request, and choosing **Use GraphQL introspection** drops the attached document. One request never has two live schema sources. Nothing is ever copied. Every attachment is a reference that Requestly re-reads when the request loads, so the schema document itself is never stored inside your request. ### Attach a file from your machine **1. Open the Schema tab** Open the GraphQL request, then select the **Schema** tab. **2. Choose the file** Click **Import a GraphQL schema**, then click **Choose a file** and pick your schema document. `.graphql`, `.gql`, `.graphqls`, `.sdl`, and `.json` files are all accepted. **3. Check that it loaded** The picker now names the file and the tab reads "Schema document attached from a local file". Switch back to the **Query** tab: autocomplete and the schema explorer behave exactly as they do on an introspected schema. A file attachment stays a live reference, not a snapshot. Edit the file in your editor, click the refresh button beside the picker, and the change is picked up without attaching the file again. Requestly never watches the file, so picking up an edit is always an explicit refresh. > [!NOTE] > > On the web app, keeping an attached file in sync needs a Chromium-based browser (Chrome, Edge, Brave, Arc) or the desktop app. On other browsers the file still attaches, but it is read once: edit it and attach it again to pick up the change. ### Attach a schema by URL **1. Open the Schema tab** Open the GraphQL request, then select the **Schema** tab. **2. Enter the URL** Paste the URL straight into the picker and select the **Attach** row that appears, or click **Import a GraphQL schema** and press Enter in the **Enter a URL** field. **3. Check that it loaded** The picker now shows a short name taken from the URL, which is its last path segment rather than the whole link. If the URL served a schema document, the tab reads "Schema document attached from a URL". Switch back to the **Query** tab: autocomplete and the schema explorer behave exactly as they do on an introspected schema. The URL you paste is meant to point at a schema **document**: GraphQL SDL, or the JSON result of an introspection query. Requestly fetches it and reads the response as a document first. If what comes back is not a schema document, Requestly then **introspects that same URL** before it reports any error. So pasting a plain GraphQL endpoint works too, and you do not need to know in advance which of the two a URL is. One thing to expect when the fallback is what succeeded: no document was ever parsed, so the request is now introspecting that URL rather than holding a document, and the tab says so. It reads "No schema document attached. This request uses GraphQL introspection" even though the schema loaded and is driving the editor. The URL is still added to the picker, so you can reuse it on another request. > [!TIP] > > Coming from Postman? A plain endpoint URL is accepted here because of the introspection fallback above, and an **introspection-result JSON** file or URL is a first-class import format rather than something you must convert to SDL first. > [!NOTE] > > On the web app, fetching a schema URL runs through Cloud Agent, which cannot reach `localhost` or private network addresses. Attach those from the desktop app. ### Reuse a location you have attached before Once a file or URL has loaded successfully, it is remembered on that device and offered in the picker on every other GraphQL request, with no network call. A document that failed to load is not remembered, so a broken location never comes back to haunt you. Each remembered row is labelled with a short name derived from its location, so the list stays one line per entry. Hover a row to see the full location. Hover any remembered row except the one this request is using and click the cross to forget it. Forgetting a location removes it from the list and nothing else: every request already attached to it stays attached and keeps working. ![The Schema tab with a schema attached, showing the attached location in the picker and the refresh button beside it](https://mintcdn.com/requestly/R1c-VDYdoBMf7TWZ/images/graphql-schema-tab-attached.light.png?fit=max\&auto=format\&n=R1c-VDYdoBMf7TWZ\&q=85\&s=deea640f257253c0edcafc6317a657b0) ### Go back to introspection While a document is attached, the tab offers **Use GraphQL introspection**. Choosing it detaches the document and the request goes back to introspecting the URL in the URL bar. The control needs a request URL to work against, and says so when the URL bar is empty. While introspection is already the live source there is nothing to switch to, so the tab shows "Using GraphQL introspection" with its own re-run control instead. ### What a teammate on another machine sees What travels with a shared request depends on the kind of attachment, and not on whether you work in a team project or a local project. The behaviour is the same in both. | You attached | What a teammate opening that request gets | | - | - | | A **URL** | The same attachment. The URL is part of the request, so the schema loads for them too. | | A **file** | Nothing device-specific. The request falls back to introspection, and the tab offers them a route to attach their own copy. They never see a file path from your machine. | If you want a schema to be shared, attach it by URL. ### On a GraphQL example A GraphQL [example](../examples) has a **Schema** tab too, and it shows where its parent request's schema comes from rather than the schema itself: the source (**Introspection**, **Schema document**, or **Local file**), the location when that source is a URL, and that it was resolved from the parent request. Everything there is read-only, with no attach, reuse or refresh controls, because an example never carries a schema of its own. A **Local file** source shows no location at all, so an example never displays a path from another machine. ### Why there is no "Import as specification" Postman lets you import a GraphQL schema as an API specification. Requestly has no equivalent, and that is deliberate rather than an oversight: [Requestly specifications](/api-client/api-design/overview) are OpenAPI documents, and there is no GraphQL format for a schema to become. To share a schema with your team, host it where your teammates can reach it and attach it **by URL**. A URL attachment travels with the request. A file you attach stays on your own machine by design, and there is no way to promote it into something shared. ### What survives when you attach SDL An attached SDL document is used as SDL. Requestly never converts it to introspection JSON on the way in, so things introspection cannot express survive attaching: custom directive applications, and type extensions that add nothing but a directive. ### When something goes wrong Errors on this tab are short and always name what to do next. The common ones: | What you see | What it means | | - | - | | "Could not load GraphQL schema. The document is not valid GraphQL SDL. Check the file and attach it again." | The document was read but is not a schema Requestly can build. | | "Could not load GraphQL schema. That URL did not return a schema document, and introspecting it failed. Check the URL and attach it again." | Both attempts were made against your URL and both failed. | | "Could not refresh the GraphQL schema. The location was not found. The previously loaded schema is still in use. Re-import it to continue." | A refresh could not reach the file or URL. Your request keeps working on the schema it already loaded. | If an attached file has moved, been deleted, or the browser has dropped its permission, the tab says so and offers **Re-attach** so you can point at it again in one click. ![The Schema tab showing a schema load error above the attach controls, which stay available](https://mintcdn.com/requestly/R1c-VDYdoBMf7TWZ/images/graphql-schema-tab-error.light.png?fit=max\&auto=format\&n=R1c-VDYdoBMf7TWZ\&q=85\&s=533341829c6a28b9098dcc8ac20c1f5b) The attach controls stay available in every error state, so you can fix the problem from where you are told about it. ## What's Next? > **[Add Authorization](/api-client/send-api-request/authorization)** > > Secure your GraphQL requests with API keys, tokens, or OAuth flows > **[Use Variables](/api-client/environments-and-variables)** > > Make your GraphQL queries dynamic with environment variables > **[Organize in Collections](/api-client/api-collections)** > > Group related GraphQL requests together # gRPC Request Source: https://docs.requestly.com/api-client/send-api-request/grpc-request Learn how to create and invoke gRPC requests in Requestly using server reflection or a proto file, with support for unary and streaming methods. gRPC is a high-performance RPC framework that uses Protocol Buffers to define services and messages. Instead of hitting REST-style URLs, you connect to a gRPC server, pick a service method, and invoke it with a structured message. Requestly discovers your services automatically through server reflection or from a `.proto` file, and supports unary as well as all three streaming method types. ![gRPC request editor in Requestly with a connected server, the GetProduct method selected, and an example message in the Message tab](https://mintcdn.com/requestly/zRhiVCdVoXHisCd0/images/grpc-request.png?fit=max\&auto=format\&n=zRhiVCdVoXHisCd0\&q=85\&s=070843ff0ab9f29506c815e49bac7b42) > [!NOTE] > > **Availability:** gRPC is a desktop-app feature and is rolling out gradually. If you don't see **gRPC request** in the `+ New` menu, update to the latest version. ## Create your first gRPC request **1. Create a new gRPC request** Open the **Requestly Desktop App**, click the `+ New` button, and select **gRPC request** from the menu. **2. Name your request** Give your request a clear, descriptive name so it's easy to identify later. **3. Enter the server address** In the address bar, enter your gRPC server address in `host:port` format, for example `localhost:50051`. An address without a scheme connects without TLS. For a server that requires TLS, prefix it with `grpcs://`, for example `grpcs://grpc.example.com:443`. > [!NOTE] > > As soon as you enter a reachable address, Requestly performs **server reflection** to discover the services and methods the server exposes. No extra setup is required if your server has reflection enabled. **4. Select a method** Open the **Select method** dropdown and choose the service method you want to call. Each method shows an icon indicating its type: * **Unary**: a single request, a single response. * **Server streaming**: a single request, a stream of responses. * **Client streaming**: a stream of requests, a single response. * **Bidirectional**: streams of requests and responses at the same time. **5. Build your message** Go to the **Message** tab and enter your request message as JSON. To start from a ready-made template, click **Generate example message** (see below). **6. Invoke the method** Click **Invoke** to call the method. The response panel opens with the received messages, response metadata, and trailers. ## Generate an example message Writing a request message by hand means knowing every field, its type, and its nesting. The **Generate example message** button, at the bottom of the **Message** tab, does this for you. It reads the selected method's input message definition and writes a complete, correctly shaped JSON skeleton into the editor, so you only have to replace the placeholder values. The generated message includes every field in the request type, with a placeholder value chosen to match each field's type: * **Strings** get a sample word, **numbers** get a small sample number, and **booleans** get `true` or `false`. * **Nested messages** are expanded into nested objects, and **repeated fields** become single-element arrays so you can see the shape. * **Enums** use one of the defined values, and well-known types are filled with valid examples (for instance, a `google.protobuf.Timestamp` becomes an ISO date such as `2024-01-01T00:00:00Z`). > [!NOTE] > > Generating an example replaces the current contents of the Message editor. Generate first, then edit the values. ## Discover services with a proto file If your server does not support reflection, or you want to work against a local contract, you can load services from a `.proto` file instead. ![Service definition popover in Requestly with Proto file selected, showing the Choose .proto file button and the Import paths section](https://mintcdn.com/requestly/zRhiVCdVoXHisCd0/images/grpc-proto-file.png?fit=max\&auto=format\&n=zRhiVCdVoXHisCd0\&q=85\&s=8f4d245e99a398c5a45c655696edc8e4) **1. Open the service definition source** Open the schema source control next to the address bar and switch from **Server reflection** to **Proto file**. **2. Choose your .proto file** Click **Choose .proto file** and select the file on disk. Requestly parses it and lists the discovered services and methods in the **Select method** dropdown. **3. Add import paths (optional)** If your `.proto` file imports other definitions, use **Add import path** to point Requestly at the directories that contain them. Well-known types such as `google.protobuf` are resolved automatically. ## Add metadata gRPC metadata works like request headers. Open the **Metadata** tab and add key/value pairs. You can enable or disable individual entries with the checkbox, and use `{{variables}}` for dynamic values. ## Handle streaming methods For server-streaming, client-streaming, and bidirectional methods, the call stays open after you invoke it instead of returning a single response. While a stream is active you have three controls: * **Invoke** starts the call. Once connected, the address bar's button changes to **Cancel**, which closes the connection immediately in both directions. * **Send** pushes the message currently in the editor onto the stream without closing it. Available on client-streaming and bidirectional methods, where the client can send more than one message. * **End streaming** closes the request (client) side of the stream while leaving it open for the server to finish responding. Available on client-streaming and bidirectional methods. The response panel lists every message in order. Each row shows a direction indicator (an up arrow for messages you sent, a down arrow for messages the server sent back), a sequence number, the timestamp, and a preview you can expand to the full JSON body. Filter by **Sent** or **Received**, or search across all messages. ### Bidirectional streaming A bidirectional method keeps both sides open at once: you can keep sending messages while the server keeps responding. Invoke the method to open the stream, use **Send** to push each new message, watch responses arrive in the panel, and click **End streaming** when you are done sending. ![Bidirectional gRPC stream in Requestly showing a STREAMING status, a sent message and a received message in the response panel, and the Send and End streaming controls](https://mintcdn.com/requestly/zRhiVCdVoXHisCd0/images/grpc-bidi-streaming.png?fit=max\&auto=format\&n=zRhiVCdVoXHisCd0\&q=85\&s=7d7bd007818e102bf8f1ddc82d5ff89f) ## Read the response The response panel shows: * **Responses**: each message sent and received, with timestamps and an expandable JSON body. Filter by direction or search across messages. * **Metadata**: the response headers returned by the server. * **Trailers**: the trailing metadata, including the final gRPC status code and message (for example, `0 OK` or `12 UNIMPLEMENTED`). The panel header shows the status code, the response time, and the number of messages exchanged. ## Get client code Click **Get client code** to generate a ready-to-use code snippet for the current request in several languages. ## What's Next? > **[Add Authorization](/api-client/send-api-request/authorization)** > > Secure your gRPC requests with API keys, tokens, or OAuth flows > **[Use Variables](/api-client/environments-and-variables)** > > Make your gRPC messages and metadata dynamic with variables > **[Organize in Collections](/api-client/api-collections)** > > Group related gRPC requests together # MQTT Request Source: https://docs.requestly.com/api-client/send-api-request/mqtt-request Connect to an MQTT broker in Requestly, publish messages, subscribe to topic filters, and read the live message timeline. MQTT is a lightweight publish/subscribe protocol used by IoT fleets, telemetry pipelines, and anything else that keeps one long-lived connection open instead of sending a request at a time. In Requestly you connect to a broker once, then publish messages to topics and subscribe to topic filters while that session stays open. Everything that leaves or arrives lands in a live message timeline beside the editor. ![MQTT request editor in Requestly with the broker URL bar, the Message tab open, and the empty message timeline on the right](https://mintcdn.com/requestly/FQI_Y7CdnpUE3zd-/images/mqtt-request-editor.light.png?fit=max\&auto=format\&n=FQI_Y7CdnpUE3zd-\&q=85\&s=e5c84862e1bf4bdfa576785f058c2ebd) > [!NOTE] > > **Availability:** MQTT connections open from the **Requestly Desktop App**. In the web app you can create, edit, and save an MQTT request, but **Connect** is disabled with the note "This protocol requires the desktop app." ## Create an MQTT request **1. Create the request** Click `+ New` and select **MQTT request**. You can also click the **+** on a collection in the sidebar and choose **MQTT Request** to create it directly inside that collection. **2. Enter the broker URL** Type your broker address into the URL bar. Requestly connects over four transports: | Scheme | Transport | | - | - | | `mqtt://` | MQTT over plain TCP | | `mqtts://` | MQTT over TLS | | `ws://` | MQTT over WebSocket | | `wss://` | MQTT over WebSocket with TLS | A public test broker is handy while you are getting your bearings: ```text theme={null} mqtt://test.mosquitto.org:1883 ``` If you type a host with no scheme, Requestly adds `mqtt://` when you leave the field and nudges you to switch to `mqtts://` if you want TLS. An unsupported scheme or a port outside 1 to 65535 shows an inline error and keeps **Connect** disabled. **3. Pick the protocol version** Use the version selector to the left of the URL bar. **V5** is MQTT 5.0 and is the default for a new request; **V3** is MQTT 3.1.1. **4. Connect** Click **Connect**. A status dot appears at the right edge of the URL bar (amber while connecting, green once connected, red on failure), the button turns into **Disconnect**, and the timeline records a **Connected** entry. **5. Save the request** Click **Save**. The request is stored in your project and appears in the collection tree with a signal icon rather than an HTTP method badge, so you can spot MQTT requests at a glance. > [!TIP] > > Press `Cmd`/`Ctrl` + `Enter` to connect when you are disconnected, and to publish the current message once you are connected. Disconnecting is always a deliberate click on the URL bar button. ## Use variables in the broker URL The URL bar accepts `{{variables}}` from your environment and collection scopes, including a bare placeholder that holds the whole address: ```text theme={null} {{brokerUrl}} ``` Requestly leaves a placeholder like that unvalidated and resolves it when you connect, so a single variable can point every request at a staging or production broker. Variables also resolve in publish topics, message payloads and topic filters when you publish, and in the Authorization fields when you connect. One shape is not supported: a `{{variable}}` placed directly inside JSON braces, as in `{"value":{{count}}}`, fails to render and the publish is refused. Quote it as `{"value":"{{count}}"}` instead. ## What locks while you are connected The broker URL, the protocol version, and the **Authorization**, **Properties**, and **Last Will** tabs are all fixed at the moment of the handshake. While a session is live those fields go read-only and each of the three tabs shows a banner naming the broker you are connected to. Click **Disconnect**, change what you need, and connect again. The **Message** and **Topics** tabs stay editable throughout, because publishing and subscribing are exactly what a live session is for. ## The editor tabs An MQTT request opens on **Message**. Alongside it are **Topics**, **Authorization**, **Properties** (on MQTT 5.0 only), and **Last Will**, plus an **Overview** tab where you can write a description of the request for your team. ### Message The Message tab is where you compose and send a single publish. **1. Set the publish topic** Enter the topic in **Publish to topic**, for example `device/abc/cmd`. Publish topics must be exact: the `+` and `#` wildcards belong in subscribe filters, and Requestly flags them here with an inline error. **2. Write the payload** Type the message body into the **Payload** editor and pick how you are entering it: **Text**, **JSON**, **Base64**, or **Hex**. Requestly validates Base64 and Hex as you type and converts them to bytes when it sends. **3. Choose QoS and retain** Set the delivery guarantee with **QoS** (`0` at most once, `1` at least once, `2` exactly once) and tick **Retain** if you want the broker to hold the message as the topic's last known value for future subscribers. **4. Publish** Click **Publish**. The button is enabled only while you are connected and the topic and payload are valid. The message appears in the timeline with an up arrow. At QoS 1 or 2 it also carries a status dot that fills in when the broker acknowledges it; at QoS 0, the default, there is no acknowledgement on the wire and so no dot. On MQTT 5.0 the tune icon at the bottom left of the tab opens **Publish options**, which carries the 5.0 message properties: * **Topic alias** replaces a repeated topic string with a small integer to shrink packets. * **Response topic** and **Correlation data** together let you do request/response over pub/sub. * **Message expiry interval** tells the broker how long to keep trying to deliver. * **Content type** labels the payload, for example `application/json`. * **Payload format indicator** flags the payload as UTF-8 text rather than opaque bytes. * **User properties** attach arbitrary key/value metadata to the message. ![Publish options dialog for an MQTT 5.0 request showing user properties and the topic alias, response topic, correlation data, message expiry, content type, and payload format fields](https://mintcdn.com/requestly/FQI_Y7CdnpUE3zd-/images/mqtt-publish-options.light.png?fit=max\&auto=format\&n=FQI_Y7CdnpUE3zd-\&q=85\&s=22b358bb467e38248032339c5bb49751) ### Topics The Topics tab holds the subscriptions that belong to this request. Each row is one topic filter with its own QoS, an optional description, and a **Subscribe** toggle. **1. Add a topic filter** Click **Add topic** and enter a filter. Wildcards are allowed here: `+` matches one level (`sensor/+/temperature`) and `#` matches everything below a level (`sensor/#`). **2. Set the QoS** Pick the QoS you want the broker to grant for this filter. Once the subscription is live, the status dot's tooltip tells you the QoS the broker actually granted, which can be lower than the one you asked for. **3. Turn the subscription on** Flip **Subscribe**. If you are already connected, Requestly sends the subscription right away. If you are not, the row waits and shows a "queued" dot, then subscribes as soon as you connect. ![Topics tab of an MQTT request with two topic filter rows, their QoS selectors, Subscribe toggles, status dots, and descriptions](https://mintcdn.com/requestly/FQI_Y7CdnpUE3zd-/images/mqtt-topics-tab.light.png?fit=max\&auto=format\&n=FQI_Y7CdnpUE3zd-\&q=85\&s=32999537af224bbc9f86223996c84d77) The dot beside each toggle is the row's live state: grey for not subscribed, amber while the subscribe or unsubscribe is in flight or queued, green once the broker has granted it, and red if the broker rejected it. A red dot is clickable, so a rejected subscription can be retried in place. Your subscriptions are saved with the request, so they survive a reload, a tab switch, and a reconnect. On every reconnect Requestly reconciles: rows you left switched on are subscribed again, and rows that are already live are skipped, so reconnecting does not stack up duplicate subscriptions on the broker. Editing a row's filter, QoS, or description is blocked while that row is live on the broker, since the broker holds the values that are actually in effect. Toggle the row off to edit it. If two rows end up with the same filter, Requestly marks the earlier one with a warning icon, switches it off, and keeps the newest row as the live subscription. On MQTT 5.0, the `...` button at the right of a topic row opens **Subscription options** for that single filter: a **Subscription identifier** the broker echoes back on matching messages, per-filter **User properties**, **Filter local messages** (so the broker does not send you back your own publishes), **Retain as published**, and **Retain handling** (whether retained messages arrive when you subscribe). ### Authorization MQTT requests authenticate with a username and password on connect. Choose **Basic auth** and fill in the two fields. Both accept `{{variables}}`, so credentials can come from an environment rather than being typed into the request. > [!WARNING] > > Set **Basic auth** on the request itself. A new MQTT request starts on **Inherit**, and an MQTT connect does not pick up authorization from the parent collection, so a request left on Inherit connects with no credentials and the broker refuses it. ### Properties The **Properties** tab carries **User properties** for the connection itself: key/value metadata sent with the connect packet, which brokers commonly use for tenant tags, client metadata, or routing hints. This tab exists only on MQTT 5.0. User properties are a 5.0 feature, so switching a request to **V3** removes the tab entirely, and if Properties was the tab you were on, the editor drops you back to **Message**. > [!WARNING] > > Switching from V5 to V3 hides the Properties tab and every 5.0-only option, and those values are not sent to a 3.1.1 broker. They are kept on the request, so switching back to V5 brings them into view again. ### Last Will A Last Will is the message you want the broker to publish on your behalf if your connection drops without a clean disconnect, which is how a fleet learns that a device went offline. The tab starts empty. Click **Configure Last Will**, then set the **Will topic**, the **Will message** (with the same Text, JSON, Base64, and Hex modes as a publish payload), **Will QoS**, and **Will retain**. **Remove Will** clears it again. On MQTT 5.0 the tune icon opens **Will options**, which adds a **Will delay interval**: the number of seconds the broker waits after your client disconnects before publishing the Will, so a brief reconnect can suppress it entirely. The same 5.0 message properties available on a publish apply here too, except **Topic alias**, which a Will does not carry. In its place the Will offers a **Will delay interval**. A Last Will with an empty topic counts as not configured and is left out of the connect entirely. ## Read the message timeline The panel to the right of the editor is the live record of the session, newest entry first. It carries three kinds of row: * **Messages you published**, marked with an up arrow. At QoS 1 or 2 a status dot fills in when the broker acknowledges the publish. QoS 0 has no acknowledgement, so those rows show the arrow alone. * **Messages you received**, marked with a down arrow, on any topic you are subscribed to. * **Connection and subscription events**: connected, server disconnect, and each subscribe or unsubscribe acknowledgement, including the broker's reason when it rejects one. ![MQTT message timeline showing a Connected event, a subscribe acknowledgement, a published message, and a received message expanded to show its payload](https://mintcdn.com/requestly/UGVQErFGsLJ-OY7V/images/mqtt-message-timeline.light.png?fit=max\&auto=format\&n=UGVQErFGsLJ-OY7V\&q=85\&s=9e1e52f079117dd9806632029bf06ffc) Every row shows the topic, a one-line payload preview, the QoS, and a millisecond timestamp. A lock icon marks a message that carried the retain flag. The panel header shows the connection status and, while connected, how long the session has been up. You can move the panel to the bottom of the editor or collapse it out of the way. ### Filter and search The filter bar above the list narrows what you see. Type into the **Filter messages** box to match on topic, payload, or the text of an event, and use the dropdown to show **All messages**, only **Received**, only **Sent**, or only **Others** (the connection and subscription events). The two combine, and a counter at the foot of the list tells you how many of the total entries are showing. The clear button empties the timeline. Requestly keeps the most recent 10,000 entries, or 100 MB of message data, whichever it reaches first. Large payloads therefore start evicting well before 10,000 rows. When a session passes either cap the oldest entries are dropped and the counter reports how many were evicted. ### Expand a message Click a published or received message to open it. The expanded row shows: * **The payload**, in a read-only editor with its own **Text**, **JSON**, **Base64**, and **Hex** switcher. Requestly inspects the actual bytes to pick the opening format, so a JSON payload opens as JSON, plain text as text, and anything that is not valid UTF-8 opens as Base64. The collapsed row shows the byte size for those. On MQTT 5.0 a `Content-Type` of `text/...` overrides the guess and opens the payload as Text. Switching formats re-decodes the same bytes, so you can read a binary payload as Hex without touching the message. * **A Retain marker** in the editor header when the message carried the retain flag. * **MQTT 5.0 properties** the message arrived with or was sent with: Content-Type, Response Topic, Correlation Data, Message Expiry, Topic Alias, Payload Format, the Subscription Id the broker matched, and any User Properties. MQTT 3.1.1 messages never carry properties, so nothing is shown for them. * **A failure banner** if the broker rejected your publish, with the reason in plain language. Because MQTT shows a message timeline rather than a single response body, the action that turns a response value into a variable is not available on MQTT requests. ## Save and reuse MQTT examples An example is a saved snapshot of an MQTT request's configuration: the broker URL, the protocol version, the subscriptions, the publish message, the authorization, the properties, and the Last Will. Use them to keep a set of named scenarios (a staging broker, a malformed payload, a QoS 2 publish) beside the request they belong to. Examples work on both cloud projects and local projects. **1. Save the current setup as an example** With the MQTT request saved, open the dropdown next to **Save** and choose **Save as example**. You can also right-click the request in the sidebar and choose **Add Example**. The example opens in its own tab and appears in the sidebar underneath its parent request. **2. Edit and save the example** An example opens on the same tabs as the request, bound to the snapshot instead of the live request. Change whatever you need and click **Save**. **3. Run it with Try It** An example holds no broker session of its own, so its primary button is **Try It** rather than **Connect**. Clicking it opens a new draft MQTT request pre-filled from the example, and you connect, publish, and subscribe there. Because an MQTT session is a stream of messages rather than one response, an MQTT example stores the request side only. There is no captured response attached to it. For the general behaviour of examples, see [Request Examples](/api-client/examples). ## Import and export MQTT requests MQTT requests round-trip through Requestly's own export format. Export a collection to a `.json` file and its MQTT requests, their subscriptions, publish messages, Last Wills, MQTT 5.0 properties, and their examples all travel with it. Import that file into another project or onto another machine and they come back intact. The steps are the same as for any collection: see [Import / Export Collections](/api-client/import-export/import-export-api-collections). Other formats have no vocabulary for MQTT. Exporting a collection to Postman's format drops MQTT requests and their examples, and the export dialog does not name what it dropped, so use Requestly's own format whenever MQTT requests need to come along. ## MQTT requests in the Collection Runner The [Collection Runner](/api-client/collection-runner) runs a collection's requests in sequence. You can select an MQTT request in the run order and it appears with an **MQTT** badge, but it does not connect: the runner executes one request at a time and waits for it to finish, which a long-lived broker session never does. Each MQTT request in a run is recorded as **skipped**, with the reason on the result row reading "not supported in runner". Skipped requests are counted in the run summary and listed under the **Skipped** tab, so a run stays green and you can see exactly what was left out. Connect to brokers from the request editor instead. [Scheduled Runs](/api-client/scheduled-runs) go further: an MQTT request cannot be added to a schedule at all. Its row is locked in the request picker with a note that the protocol cannot run on a schedule. ## What's next? > **[Use Variables](/api-client/environments-and-variables)** > > Point one request at different brokers with environment and collection variables > **[Organize in Collections](/api-client/api-collections)** > > Group MQTT requests with the rest of the APIs they belong to > **[Request Examples](/api-client/examples)** > > Keep named MQTT scenarios beside the request they belong to # API Call History Source: https://docs.requestly.com/api-client/send-api-request/replay-request-from-history Track and manage API requests with a clear, editable history view in the API Client. The API Call History feature allows users to track and manage all requests triggered from the API Client. The most recent request is displayed at the top of the history panel, providing a clear chronological view of interactions. > [!WARNING] > > History is stored locally and is not synced to the cloud. ### Viewing API Call History All API calls made from the client are listed in the left sidebar. Each entry can be clicked to load the request details back into the API Client. This enables users to quickly replay a request after editing some fields. ![](https://mintcdn.com/requestly/qjoPMMH7xQ-WaHDj/images/replay-request-from-history/f708edc8-da2e-4fdb-970c-31643c7c76d0.png?fit=max\&auto=format\&n=qjoPMMH7xQ-WaHDj\&q=85\&s=f2c17d67db11384ab666a2e3b4d59ce5) > [!WARNING] > > By default, cached responses are session-only: if you refresh the page, response data is cleared and requests must be re-sent to see their responses again. To keep responses across refreshes, enable **Save responses** from the history menu. Additionally, the response for any request made during the current session is cached and can be revisited without making a new call, provided the page has not been refreshed. ![](https://mintcdn.com/requestly/qjoPMMH7xQ-WaHDj/images/replay-request-from-history/aa41d107-1019-4432-833b-7988e889b32b.png?fit=max\&auto=format\&n=qjoPMMH7xQ-WaHDj\&q=85\&s=e0ab8f6fdc9476a2f25ccc1d3be6aa7d) ### Clearing History Open the history menu and select **Clear all history**. This will permanently remove all recorded requests. ![](https://mintcdn.com/requestly/qjoPMMH7xQ-WaHDj/images/replay-request-from-history/288129ca-1d03-4b29-94d0-114d18d01aa0.png?fit=max\&auto=format\&n=qjoPMMH7xQ-WaHDj\&q=85\&s=32bfce10f76d7b75cee6720470f13440) ## What's Next? > **[Save to Collections](/api-client/api-collections)** > > Permanently save frequently used requests in collections > **[Use Variables](/api-client/environments-and-variables)** > > Make requests reusable across different environments > **[Add Authorization](/api-client/send-api-request/authorization)** > > Configure authentication for your API requests # SOAP Requests Source: https://docs.requestly.com/api-client/send-api-request/send-soap Learn how to create and send SOAP requests in Requestly using XML bodies, endpoints, and variables. SOAP (Simple Object Access Protocol) is a protocol for exchanging structured information using XML. Unlike REST, SOAP requests require a strict envelope structure and often rely on predefined contracts (WSDL). [YouTube video player](https://www.youtube.com/embed/EaSmpUrqcS4) > [!NOTE] > > You can also import SOAP requests directly using the WSDL. See the [import guide](/api-client/import-export/import-from-wsdl) to get started. ## Create your first SOAP request **1. Create a New Request** Open **Requestly Desktop App**, then click the `+ New` button to create a new request. Select a standard **HTTP request** since SOAP works over HTTP. ![Openrequestlyand Createa New Request 2](https://mintcdn.com/requestly/R6m8uVxanKtHow4E/images/OpenrequestlyandCreateaNewRequest-2.png?fit=max\&auto=format\&n=R6m8uVxanKtHow4E\&q=85\&s=fa41f984bdfc150d105468975f2840ea) **2. Name Your Request** Give your request a clear and descriptive name so it’s easy to identify later. ![Naming Soaprequest](https://mintcdn.com/requestly/R6m8uVxanKtHow4E/images/NamingSoaprequest.png?fit=max\&auto=format\&n=R6m8uVxanKtHow4E\&q=85\&s=32bc8334678406aeb9659b208a7f8b15) **3. Enter the SOAP Endpoint** Add your SOAP service endpoint URL and set the method to **POST**: ```http theme={null} http://www.dneonline.com/calculator.asmx ``` ![Enterthe SOAP Endpoint](https://mintcdn.com/requestly/R6m8uVxanKtHow4E/images/EntertheSOAPEndpoint.png?fit=max\&auto=format\&n=R6m8uVxanKtHow4E\&q=85\&s=fc75f222d2f1378d61d1e98ec2239057) **4. Add XML Body** Go to the **Body** tab, select **raw**, and choose **XML** format. Paste your SOAP request body: ```xml theme={null} {{intA}} {{intB}} ``` > [!NOTE] > > Your request must include the required SOAP structure such as **Envelope** and **Body**, along with proper namespaces. ![Add XML Body](https://mintcdn.com/requestly/R6m8uVxanKtHow4E/images/AddXMLBody.png?fit=max\&auto=format\&n=R6m8uVxanKtHow4E\&q=85\&s=8b72636a24769743c41ba32b5a0b5381) **5. Send the Request** Click **Send** to execute the request and view the response. ![Sendthe SOAP Request](https://mintcdn.com/requestly/R6m8uVxanKtHow4E/images/SendtheSOAPRequest.png?fit=max\&auto=format\&n=R6m8uVxanKtHow4E\&q=85\&s=13f60f1f7ed52598053cae8a854b56a3) ## What's Next? > **[Add Authorization](/api-client/send-api-request/authorization)** > > Secure your SOAP requests with API keys, tokens, or OAuth flows > **[Use Variables](/api-client/environments-and-variables)** > > Make your SOAP requests dynamic with variables > **[Organize in Collections](/api-client/api-collections)** > > Group related SOAP requests together # Socket.IO Request Source: https://docs.requestly.com/api-client/send-api-request/socketio-request Connect to a Socket.IO server from Requestly, emit named events with typed arguments, subscribe to inbound events, and read everything on a live timeline. Socket.IO is a messaging layer on top of WebSocket. Rather than sending raw frames, you emit a **named event** carrying zero or more arguments, and the server emits named events back. It adds its own handshake, its own protocol versions, acknowledgements, automatic reconnection, and a polling fallback when a WebSocket upgrade is not possible. A Socket.IO request in Requestly stores the connection (URL, handshake path, protocol version, transport order, headers, query params, authorization, and the `auth` payload), the events you want to emit, and the events you want to listen for. Save it in a collection and the whole session is reproducible. ![Socket.IO request editor in Requestly with a connected socket, the Message tab showing an event composer, and emitted and received events in the session panel on the right](https://mintcdn.com/requestly/FQI_Y7CdnpUE3zd-/images/socketio-request-editor.light.png?fit=max\&auto=format\&n=FQI_Y7CdnpUE3zd-\&q=85\&s=e286066800060206d5f844435a61f0ff) > [!NOTE] > > **Availability:** Socket.IO connections open from the **Requestly Desktop App**. In the web app you can create, edit, and save a Socket.IO request, but **Connect** is disabled with the note "This protocol requires the desktop app." ## Create a Socket.IO request **1. Add a new Socket.IO request** Click the `+ New` button in the API Client sidebar and choose **Socket.IO request**. To create it inside a collection instead, hover the collection in the sidebar, click its `+` icon, and choose **Socket.IO Request**. The request then inherits the collection's variables. On a cloud project it also inherits the collection's authorization; on a local project set the authorization on the request itself. **2. Name the request** Click the name in the breadcrumb at the top of the editor, type a descriptive name, and press **Enter**. **3. Enter the server URL** A new request is pre-filled with `wss://socketio-echo.requestly.com`, Requestly's public Socket.IO demo server, so you have a working target before you have your own. It echoes any event you emit back to you with `:echo` appended to the event name, and resolves acknowledgements with an `ok` flag and a timestamp. The URL must start with `ws://` or `wss://`. Anything else is rejected inline with "Socket.IO URL must start with ws\:// or wss\://", and a URL with the right scheme but no usable host is rejected with "Enter a valid Socket.IO URL." **4. Subscribe to the events you want to see** Open the **Events** tab and either add a listener per event name, or turn **Catch-all** on to capture everything the server emits. Requestly shows an inbound event on the timeline only if one of those is true, so a brand-new request with no listeners and Catch-all off shows nothing coming back. **5. Connect and emit** Click **Connect**, wait for the status badge to read **Connected**, then open the **Message** tab, give the event a name, add its arguments, and click **Send**. > [!TIP] > > Press `Ctrl`/`Cmd` + `Enter` to connect when you are disconnected, and to emit the current event once you are connected. ## The URL bar * **Connect** opens the connection. It is shown while you are idle, disconnected, or sitting on a failed attempt. * **Cancel** replaces Connect while the handshake is in flight, so you are not stuck waiting on an unreachable host. * **Disconnect** replaces Connect once the connection is open. * **Save** stores your edits. On a saved request the arrow next to it offers **Save as new**, which writes a copy instead of overwriting. While a connection is active, the URL, the **Events** tab, and the **Settings** tab are read-only. The **Message**, **Headers**, **Params**, and **Authorization** tabs stay editable. ### When a connection fails A failed attempt names the cause rather than resetting to a blank state. The status badge holds the reason until you connect again, and the session panel records a matching error row. The badge names the specific cause: | Badge | What it means | | - | - | | Connection refused | Nothing was listening at that host and port. | | DNS failure | The hostname could not be resolved. | | TLS handshake failed | The `wss://` certificate could not be negotiated or trusted. | | Handshake timeout | The upgrade did not complete within the handshake timeout. | | Handshake rejected | The server answered but refused the upgrade, for example with a 401 or 403. | | Auth rejected | The server refused the credentials sent on the handshake. | | Server closed connection | The server closed it deliberately. | | Connection lost | The connection dropped without a clean close. | | Protocol error | The server sent something this client could not follow. | | Unknown error | The failure could not be classified. | A clean close by the server is not a failure: the badge returns to disconnected and the panel records a close-code row instead. When you run through the Cloud Agent rather than locally, the badge can also report reasons about the session itself rather than the endpoint, such as the agent restarting or the session reaching its time limit. A protocol-version mismatch is a common first-time failure, and it does not get a badge of its own: it usually surfaces as **Handshake rejected**. If a server you trust refuses the handshake, check the **Version** setting against what it runs. ## Editor tabs ### Overview A free-text Markdown description of the request. Useful for recording which namespace the endpoint serves, or which event the server expects first. ### Message The outbound side. The left pane lists saved events that persist with the request; the right pane composes the one you selected. Each saved event carries: * **An event name.** Set it from the row's `...` menu using **Rename**, which updates both the row label and the emitted event name. Send is blocked until the name is non-empty, with the message "Event name is required". * **Arguments.** Click **Add argument** for each one. Socket.IO events can carry zero or more, and every argument has its own format: **Text**, **JSON**, or **Binary** (with a **Base64** or **Hex** encoding dropdown). JSON arguments get a beautify button. * **Ack.** Turn the **Ack** switch on to ask the server to acknowledge the event, and set a timeout in milliseconds next to it. The default timeout is 5000. * **Auto-send on connect.** The toggle on each saved row emits that event immediately after the connection opens. Use it for a join or authenticate event that has to go first. The `...` menu also adds a description or deletes the event. **Send** sits at the bottom right and is enabled only while you are connected. ### Events The inbound side, and the tab that decides what reaches your timeline. ![Events tab of a Socket.IO request in Requestly showing a table of named listeners with colored chips, per-row enable switches, and the Catch-all toggle in the header](https://mintcdn.com/requestly/FQI_Y7CdnpUE3zd-/images/socketio-events-tab.light.png?fit=max\&auto=format\&n=FQI_Y7CdnpUE3zd-\&q=85\&s=67d73ed25a59ad7f9fe6af2c96dc23e9) **Listeners** is a table of event names you want to capture. Click **Add listener** in the table footer to add a row (it starts as `message`), then type the event name you want. Each row has an **Enabled** switch, so you can mute a noisy event without losing it, and a delete button. Every row also carries a colored chip derived from the event name, and the same chip appears next to that event on the timeline, so you can pick one event out of a fast-moving list at a glance. **Catch-all**, the switch in the tab header, changes the policy: when it is on, every inbound event is captured whether or not it has a listener. Events captured only because Catch-all is on are labelled `(catch-all)` on their timeline chip, so you can still tell a named-listener hit from a catch-all sweep. > [!WARNING] > > With Catch-all off, an inbound event whose name has no enabled listener is dropped rather than shown. If a server you know is emitting looks silent, that is the first thing to check. Both listeners and the Catch-all switch are locked while a connection is active. Disconnect to change your subscriptions. ### Headers Headers sent on the Socket.IO handshake, the HTTP request that opens the connection. Add key and value pairs, use the checkbox to disable a row without deleting it, and use bulk edit to paste several at once. Values accept `{{variable}}` references, which resolve when you connect. ### Params Query params attached to the handshake URL. This tab and the URL bar are two views of the same data: typing `?room=lobby` into the URL bar adds a `room` row here, and editing a row rewrites the URL bar's query string. Disabled rows stay in the list but are left out of the URL. ### Authorization Two sections. The top is the same authorization editor the HTTP and GraphQL editors use, applied to the handshake. Basic, Bearer, API key, OAuth and AWS signing all work here. Digest and NTLM appear in the list but a Socket.IO connect cannot perform their challenge exchange, so do not pick them. Below it is **Auth Payload**, a key and value table sent as Socket.IO's own `auth` object on the connection packet. This is the channel most Socket.IO servers read a token from, and it is available on Socket.IO v3 and later. If your request is on v3 or later but has no authorization set and an empty payload, Requestly shows an inline note here so you do not miss it. ### Settings | Setting | Default | What it does | | - | - | - | | Version | `v4 (current)` | Socket.IO protocol version. The other options are `v3` and `v2 (legacy)`. Locked while connected: disconnect to change it. | | Handshake path | `/socket.io/` | The Engine.IO endpoint path your server serves. Change it if your server mounts Socket.IO elsewhere. | | Transport order | `Polling, then WebSocket` | Which transport to try first. The alternatives are `WebSocket, then polling` and `WebSocket only`. Polling first is the most compatible; WebSocket only skips the HTTP upgrade entirely. | | Handshake timeout (ms) | 30000 | How long to wait for the handshake before giving up. | | Reconnection attempts | 3 | How many times to retry after the connection drops. `0` disables reconnection. | | Reconnection delay (ms) | 1000 | Base wait before a retry. | | Reconnection max delay (ms) | 5000 | Ceiling on the wait as retries back off. | | Randomization factor (jitter) | 0.5 | Random multiplier between 0 and 1 applied to the retry delay, so many clients reconnecting at once do not arrive together. | ![Settings tab of a Socket.IO request in Requestly showing the version selector, handshake path, transport order, handshake timeout, and the reconnection and jitter controls](https://mintcdn.com/requestly/FQI_Y7CdnpUE3zd-/images/socketio-settings-tab.light.png?fit=max\&auto=format\&n=FQI_Y7CdnpUE3zd-\&q=85\&s=641e7ad59e7fef8deafc2ae54d6f3095) Below those settings is a **Device-local** section with a **Handshake headers** table. Headers added there are sent on the handshake from this machine only and are never synced to your team, which makes it the right place for a personal credential. Values accept both `{{variable}}` and `{{vault:KEY}}` references, so you can point at a [Vault](/api-client/vault/vault) secret instead of pasting the secret itself. ## The session panel The panel on the right, labelled **Events**, records the session: every event you emit, every inbound event that passes your subscriptions, and every connection event, newest first. Each row shows a direction arrow (up for emitted, down for received), the event's colored name chip, a payload preview, its size, and a local timestamp down to the millisecond. Click a row to expand it into a read-only editor holding the full `{ eventName, args }` payload, with a language picker so you can read it as JSON. Alongside events, the timeline records: * **Handshake** rows carrying the handshake response status and headers. * **Lifecycle** rows for connecting, connected, reconnecting, and disconnected. After a reconnect it also records whether Socket.IO's connection-state recovery worked: either "Connection state recovered", or "Recovery failed" with a note that the server may not have `connectionStateRecovery` enabled and that a fresh socket ID was assigned. * **Error** rows carrying the failure reason. Three controls narrow the list: * **Search messages** matches on payload content. * The **All / Sent / Received** dropdown filters by direction. * The **Filter by event** multi-select lists every event name seen in this session. Pick one or several to show only those. It reads "No events yet" until the first event arrives. A counter on the right shows how many rows match out of the total, and the clear button empties the timeline without touching your filters. The timeline keeps the most recent 5000 rows; past that the oldest are dropped and a row is inserted saying how many were discarded. Use the controls in the panel's header bar to dock the panel at the bottom of the editor instead of the right side, or to collapse it. ## Save and reuse examples An **example** is a saved snapshot of a request's configuration. For Socket.IO it captures the URL, handshake headers, query params, authorization and `auth` payload, connection settings, saved events, and listeners. It carries no response, because a Socket.IO session has no single response to capture. **1. Create the example** Right-click the Socket.IO request in the sidebar and choose **Add Example**. The example opens in a new tab and appears nested under the request in the sidebar. **2. Edit and save it** The example tab shows the same tabs as the request editor. Change the URL, headers, params, authorization, settings, or saved events, then click **Save**. **3. Run it with Try It** The example tab's primary button reads **Try It** rather than Connect. Clicking it opens a **new draft request** pre-filled with the example's configuration, parented to the example's own collection so collection variables still resolve. Connect from that draft. An example tab never holds a live connection itself. The example stays a stable reference, and the session runs in the draft Try It spawns. See [Create Request & Response Examples](/api-client/examples) for renaming, duplicating, and deleting examples. ## Import and export Socket.IO requests are carried in full by Requestly's own collection format. Exporting a collection as a Requestly `.json` file includes every Socket.IO request with its URL, headers, params, authorization, `auth` payload, settings, saved events, and listeners, and importing that file restores them exactly. Examples ride along with their parent request. Other formats cannot represent them: * **Postman.** Exporting as a Postman v2.1 collection leaves Socket.IO requests out, because the format has no shape for them. The export dialog reports how many were excluded before you download. * **OpenAPI.** Socket.IO requests are skipped, since OpenAPI describes HTTP operations. See [Import & Export](/api-client/import-export) for the full matrix. ## Socket.IO requests in the Collection Runner The [Collection Runner](/api-client/collection-runner) runs a collection's requests in sequence. You can select a Socket.IO request in the run order and it appears with an **SIO** badge, but it does not connect: the runner executes one request at a time and waits for it to finish, which a long-lived connection never does. Each Socket.IO request in a run is recorded as **skipped**, with the reason shown on the result row reading "not supported in runner". Skipped requests are counted in the run summary and listed under the **Skipped** tab, so a run stays green and you can see exactly what was left out. Connect to Socket.IO endpoints from the request editor instead. Scheduled Runs behave the same way. See [Scheduled Runs](/api-client/scheduled-runs). ## What's next? > **[WebSocket Requests](/api-client/send-api-request/websocket-request)** > > Work with raw WebSocket frames when you do not need Socket.IO's event layer > **[Use Variables](/api-client/environments-and-variables)** > > Make URLs, headers, and event payloads dynamic across environments > **[Organize in Collections](/api-client/api-collections)** > > Group related Socket.IO requests with the rest of your API # SSL Certificates Source: https://docs.requestly.com/api-client/send-api-request/ssl-certificates Add custom CA certificates and per-host client certificates to authenticate against internal or mTLS-protected APIs in the Requestly desktop app. Many internal APIs use a private certificate authority (CA) instead of a public one, or require a client certificate to prove the caller's identity (mutual TLS / mTLS). Requestly lets you add both kinds of certificate from App Settings so every request to the right host automatically picks them up, with no changes needed to individual requests or collections. > [!NOTE] > > Certificates stay on this device. They are not synced to the Requestly cloud, so each device must add its own copy. These settings apply across every request type the API client sends: REST/HTTP, GraphQL queries and mutations, and GraphQL subscriptions over WebSocket (`wss://`). The same CA trust set and client-certificate matching rules apply uniformly. ## Prerequisites * Requestly desktop app version 2605.12.2 or later. * For CA certificates: a PEM-encoded CA certificate file (`.pem` or `.crt`). * For client certificates: either a PEM pair (certificate file `.crt` / `.pem` + private key file `.key`) or a PFX bundle (`.pfx` / `.p12`). Optional passphrase if the key or bundle is encrypted. > [!NOTE] > > **Availability:** SSL certificates are a desktop-app feature and are rolling out gradually. If you don't see the **Certificates** section in App settings, update to the latest version. ## Open the Certificates settings **1. Open App Settings** Click the **Settings** icon in the application footer, or navigate to **App Settings** from the menu. **2. Find the Certificates section** Scroll to the **Certificates** section. It contains two panels: **CA Certificate** and **Client Certificates**. ![App Settings Certificates section with the CA Certificate and Client Certificates panels](https://mintcdn.com/requestly/7InefyUlJA4bpEUA/images/ssl-certificates-settings.light.png?fit=max\&auto=format\&n=7InefyUlJA4bpEUA\&q=85\&s=adb0dfcc8bcec9481065c973c4d435e3) ## CA certificates A CA certificate tells Requestly to trust servers whose certificate chain is signed by that CA. Use it when your internal API returns a certificate signed by your company's own CA and requests fail with an SSL error. > [!NOTE] > > Requestly merges your uploaded CA with the system and Node built-in trust roots, so public HTTPS sites continue to work normally. You do not need to replace the default trust set. ### Add a CA certificate **1. Open the file picker** In the **CA Certificate** section, click **Add CA Certificate**. An OS file picker opens. **2. Select your certificate** Choose your PEM-encoded CA certificate file (`.pem` or `.crt`). The certificate appears in the list and is enabled by default. > [!WARNING] > > Only one CA certificate is supported at a time. The **Add CA Certificate** button stays disabled while a certificate is already listed, so delete the existing one before switching to a different CA. ### Enable or disable a CA certificate Each CA certificate row has an **Enabled** toggle. Turn it off to stop trusting that CA without deleting the certificate. > [!TIP] > > Toggle the CA off to quickly check whether it is the cause of a trust error, without losing your reference to the certificate file. ### Delete a CA certificate Click the delete icon on the row. A confirmation dialog explains that the cert file on disk is not deleted, only the reference inside Requestly is removed. ## Client certificates A client certificate lets Requestly prove the caller's identity during a TLS handshake. The certificate is attached only to requests whose host and port match the rule you configure. ### Add a client certificate **1. Open the Add Client Certificate dialog** In the **Client Certificates** section, click **Add Client Certificate**. **2. Set the host** Enter a specific hostname (`api.internal.example.com`) or a single-label wildcard (`*.example.com`) in the **Host** field. > [!NOTE] > > The wildcard matches one subdomain level only: `*.example.com` matches `api.example.com` but not `a.api.example.com` and not `example.com` itself. **3. Set the port** The default is 443. Change it if your API runs on a non-standard port. **4. Choose a format and select files** Pick the format that matches your certificate bundle: * **Certificate (PEM)**: select your certificate file and your private key file separately. * **PFX**: select a single `.pfx` or `.p12` bundle that contains both. If the key or bundle is protected by a passphrase, enter it in the **Passphrase** field. The passphrase is stored encrypted at rest on this device. ![Add Client Certificate dialog with the PEM tab selected, showing fields for host, port, certificate file, key file, and passphrase](https://mintcdn.com/requestly/7InefyUlJA4bpEUA/images/ssl-certificates-add-client-pem.light.png?fit=max\&auto=format\&n=7InefyUlJA4bpEUA\&q=85\&s=9d6cec0327ede4342a11b40684d22c25) Switch to the **PFX** tab if you have a single bundle file instead: ![Add Client Certificate dialog with the PFX tab selected, showing fields for host, port, PFX bundle file, and passphrase](https://mintcdn.com/requestly/7InefyUlJA4bpEUA/images/ssl-certificates-add-client-pfx.light.png?fit=max\&auto=format\&n=7InefyUlJA4bpEUA\&q=85\&s=b55a6abda2f5e283628c0757eec2718a) **5. Save the rule** Click **Add**. The new rule appears in the Client Certificates list. > [!WARNING] > > Only one client certificate rule is allowed per host-and-port pair. If a rule already exists for the same host and port, Requestly asks you to confirm before replacing it. ### Delete a client certificate Click the delete icon on the row. The confirmation dialog shows the host and port the rule covered. As with CA certificates, the cert files on disk are not deleted. > [!NOTE] > > Client certificate rows do not have an individual enable toggle. To stop attaching a certificate to a host, delete the row. ## How certificate matching works When you send a request, Requestly checks the request URL against your client certificate rules in this order: 1. Exact host match (case-insensitive) takes priority over wildcard matches. 2. Ports must match exactly. If the URL has no explicit port and uses `https`, port 443 is assumed. 3. The first matching rule is used. At most one client certificate is attached per request. If no rule matches, no client certificate is sent. > [!NOTE] > > CA certificates that are enabled are always merged in for every HTTPS request. Disabled CA certificates are ignored. ## TLS errors in the response panel When a request fails because of a TLS or certificate problem, the response panel shows an **SSL Error** message describing what went wrong (for example, `SSL Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE`). A **Manage certificates** button appears next to the error to jump directly to the Certificates settings. ![Response panel showing an SSL Error message with a Manage certificates button](https://mintcdn.com/requestly/7InefyUlJA4bpEUA/images/ssl-certificates-tls-error.light.png?fit=max\&auto=format\&n=7InefyUlJA4bpEUA\&q=85\&s=33340d6564a2c2d7b311a5f624e62a50) Common errors and what they usually mean: | Error code | Likely cause | | - | - | | `UNABLE_TO_VERIFY_LEAF_SIGNATURE` | The server's certificate chain is incomplete or signed by a CA Requestly does not trust. Add the CA certificate. | | `ERR_TLS_CERT_ALTNAME_INVALID` | The hostname in the request does not match any name on the server's certificate. Check that the URL is correct. | | `CERT_HAS_EXPIRED` | The server's certificate has passed its expiry date. This is a server-side issue. | | `ERR_SSL_WRONG_VERSION_NUMBER` | TLS version mismatch between Requestly and the server. | > [!WARNING] > > If a cert file referenced in your settings cannot be read from disk (for example, the file was moved), the error reads `SSL Error: Certificate file not found` and includes the path. Re-add the certificate from its new location to fix it. ## Inspect TLS details after a successful request For HTTPS requests that succeed, you can see the full handshake details in DevTools. **1. Open DevTools** Click **DevTools** in the application footer. **2. Select the request** Go to the **Network** tab and click the request whose TLS details you want to inspect. **3. Open the Info tab** Select the **Info** tab in the detail panel. It shows the TLS version, cipher suite, server certificate (subject, issuer, and expiry date), and, when a client certificate was sent, the matched rule (host pattern and port), the certificate subject, and the SHA-256 fingerprint. ![DevTools Network Info tab showing TLS version, cipher suite, server certificate details, and the matched client certificate rule with SHA-256 fingerprint](https://mintcdn.com/requestly/7InefyUlJA4bpEUA/images/ssl-certificates-devtools-info.light.png?fit=max\&auto=format\&n=7InefyUlJA4bpEUA\&q=85\&s=acaccbb96db9ffa1f3676fefdb2c57e9) ## What's Next > **[Authorization](/api-client/send-api-request/authorization)** > > Set API keys, Bearer tokens, and other auth schemes on requests or collections > **[DevTools](/api-client/devtools)** > > Inspect TLS handshake details, headers, and script logs in one panel # WebSocket Request Source: https://docs.requestly.com/api-client/send-api-request/websocket-request Open a WebSocket connection from Requestly, send and receive messages on a live timeline, and save reusable WebSocket requests in your collections. A WebSocket connection stays open. Instead of sending one request and reading one response, you connect once and then exchange messages in both directions for as long as the connection lives. A WebSocket request in Requestly stores everything needed to open that connection (the URL, handshake headers, query params, authorization, and connection settings) plus the payloads you want to send, so you can reopen the same session tomorrow without retyping anything. ![WebSocket request editor in Requestly with a connected socket, the Messages tab open, and a sent and received message in the session panel on the right](https://mintcdn.com/requestly/MFO7lKZDpSld4Afx/images/websocket-request-editor.light.png?fit=max\&auto=format\&n=MFO7lKZDpSld4Afx\&q=85\&s=c9e22370a8e17210c8192eb7f15d9a5c) > [!NOTE] > > **Availability:** WebSocket connections open from the **Requestly Desktop App**. In the web app you can create, edit, and save a WebSocket request, but **Connect** is disabled with the note "This protocol requires the desktop app." ## Create a WebSocket request **1. Add a new WebSocket request** Click the `+ New` button in the API Client sidebar and choose **WebSocket request**. To put the request straight into a collection instead, hover the collection in the sidebar, click its `+` icon, and choose **WebSocket Request**. The request is created inside that collection and inherits the collection's variables. On a cloud project it also inherits the collection's authorization; on a local project set the authorization on the request itself. **2. Name the request** Click the name in the breadcrumb at the top of the editor and type a descriptive name, then press **Enter**. The request appears in the sidebar under its collection alongside your HTTP and GraphQL requests. **3. Enter the WebSocket URL** A new request is pre-filled with `wss://echo.websocket.org`, a public echo server, so you have something that answers immediately. Replace it with your own endpoint when you are ready. The URL must start with `ws://` or `wss://`. Anything else is rejected inline with "WebSocket URL must start with ws\:// or wss\://", and a URL with the right scheme but no usable host is rejected with "Enter a valid WebSocket URL." **4. Connect** Click **Connect**. A status badge appears at the top of the session panel on the right and moves from **Connecting…** to **Connected**. **5. Send a message** Open the **Messages** editor tab, select a saved message on the left, type a payload into the editor, and click **Send**. The message and anything the server sends back appear in the session panel on the right, which is also labelled **Messages**. > [!TIP] > > Press `Ctrl`/`Cmd` + `Enter` to connect when you are disconnected, and to send the current message once you are connected. ## The URL bar The URL bar holds the address and every connection-level action. * **Connect** opens the connection. It is shown while you are idle, disconnected, or sitting on a failed attempt. * **Cancel** replaces Connect while the handshake is in flight, so you are not stuck waiting on an unreachable host. * **Disconnect** replaces Connect once the socket is open, and closes it. * **Save** stores your edits. On a saved request the arrow next to it offers **Save as new**, which writes a copy instead of overwriting. While a connection is active, the URL and the **Settings** tab become read-only. The **Messages**, **Headers**, **Params**, and **Authorization** tabs stay editable, so you can adjust what you send next without dropping the socket. ### When a connection fails A failed attempt names the cause rather than resetting to a blank state. The status badge holds the reason until you connect again, and the session panel records a matching error row. The badge names the specific cause: | Badge | What it means | | - | - | | Connection refused | Nothing was listening at that host and port. | | DNS failure | The hostname could not be resolved. | | TLS handshake failed | The `wss://` certificate could not be negotiated or trusted. | | Handshake timeout | The upgrade did not complete within the handshake timeout. | | Handshake rejected | The server answered but refused the upgrade, for example with a 401 or 403. | | Auth rejected | The server refused the credentials sent on the handshake. | | Server closed connection | The server closed it deliberately. | | Connection lost | The connection dropped without a clean close. | | Protocol error | The server sent something this client could not follow. | | Unknown error | The failure could not be classified. | A clean close by the server is not a failure: the badge returns to disconnected and the panel records a close-code row instead. When you run through the Cloud Agent rather than locally, the badge can also report reasons about the session itself rather than the endpoint, such as the agent restarting or the session reaching its time limit. ## Editor tabs ### Overview A free-text description of the request, written in Markdown. Useful for recording which environment the endpoint belongs to or what the server expects first. ### Messages The Messages tab is a saved-payload library plus a composer. The left pane lists **Saved messages** that persist with the request, so a payload you use often is one click away on every future session. The right pane is the editor for the message you selected. * The format dropdown above the editor switches between **Text**, **JSON**, **XML**, **HTML**, and **Binary**. JSON, XML, and HTML get syntax highlighting and a format button. Choosing Binary adds a second dropdown for **Base64** or **Hex** encoding. * The toggle on each saved row auto-sends that message immediately after the connection opens. Use it for a subscribe or authenticate frame that always has to go first. * The `...` menu on each row renames the message, adds a description, or deletes it. * **Send** sits at the bottom right of the editor and is enabled only while you are connected. A new request already contains one saved message called `Message 1`. If you connect with an empty list, Requestly adds a starter message so you always have somewhere to type. ### Headers Headers here are sent on the WebSocket handshake, the HTTP request that upgrades the connection. Add key and value pairs, use the checkbox to turn individual rows off without deleting them, and switch to bulk edit to paste several at once. Values accept `{{variable}}` references, which resolve from your environment and collection variables when you connect. Requesting a subprotocol is not supported. Adding a `Sec-WebSocket-Protocol` header by hand does not negotiate one, and if the server echoes it back the handshake is aborted, so leave it off. ### Params Query params attached to the handshake URL. This tab and the URL bar are two views of the same data: typing `?token=abc` into the URL bar adds a `token` row here, and editing a row rewrites the URL bar's query string. Disabled rows stay in the list but are left out of the URL. ### Authorization The same authorization editor the HTTP and GraphQL editors use, applied to the handshake. Basic, Bearer, API key, OAuth and AWS signing all work here. Digest and NTLM appear in the list but a WebSocket connect cannot perform their challenge exchange, so do not pick them. ### Settings Per-request connection tuning: | Setting | Default | What it does | | - | - | - | | Verify server certificate | On | Validates the TLS certificate. Disabled automatically on a `ws://` URL, where there is no TLS to verify. | | Handshake timeout (ms) | 30000 | How long to wait for the upgrade to complete before giving up. | | Max message size (MB) | 0 | Largest message to accept. `0` means uncapped. | | Reconnection attempts | 3 | How many times to retry after the connection drops unexpectedly. A clean close by the server is not retried. `0` disables reconnection. | | Reconnection interval (ms) | 1000 | Wait between retries. | | Keep-alive interval (ms) | 0 | How often to send a keep-alive frame. `0` disables it. | ![Settings tab of a WebSocket request in Requestly showing certificate verification, handshake timeout, message size, reconnection, keep-alive, and the Device-local handshake headers table](https://mintcdn.com/requestly/MFO7lKZDpSld4Afx/images/websocket-settings-tab.light.png?fit=max\&auto=format\&n=MFO7lKZDpSld4Afx\&q=85\&s=2cc52887283163d7c5e638c12b448023) Below those settings is a **Device-local** section with a **Handshake headers** table. Headers added there are sent on the handshake from this machine only and are never synced to your team. That makes it the right place for a personal credential: values accept both `{{variable}}` and `{{vault:KEY}}` references, so you can point at a [Vault](/api-client/vault/vault) secret instead of pasting the secret itself. ## The session panel The panel on the right, labelled **Messages**, is the record of the session. Every message you send, every message the server sends, and every connection event lands there, newest first. Each row shows a direction arrow (up for sent, down for received), the payload preview, its size, and a local timestamp down to the millisecond. Click a row to expand it into a read-only editor with the full payload and a language picker, so you can read a JSON frame as JSON even if it arrived as text. Beyond messages, the timeline records: * **Handshake** rows carrying the upgrade response status and headers. * **Lifecycle** rows for connecting, connected, reconnecting, and disconnected, including the close code and its standard name (for example `1000 NORMAL_CLOSURE` or `1006 ABNORMAL_CLOSURE`). * **Error** rows carrying the failure reason. To narrow the list, use the **Search messages** box to match on payload content, and the dropdown to show **All**, **Sent**, or **Received**. A counter on the right reads how many rows match out of the total. The clear button empties the timeline without touching your filters. > [!NOTE] > > The timeline keeps the most recent 5000 rows. Past that the oldest rows are dropped and a row is inserted saying how many were discarded. Use the controls in the panel's header bar to move it to the bottom of the editor instead of the right side, or to collapse it out of the way. ## Save and reuse examples An **example** is a saved snapshot of a request's configuration. For WebSocket requests it captures the URL, handshake headers, query params, authorization, connection settings, and saved messages. It carries no response, because a WebSocket session has no single response to capture. **1. Create the example** Right-click the WebSocket request in the sidebar and choose **Add Example**. The example opens in a new tab and appears nested under the request in the sidebar. **2. Edit and save it** The example tab shows the same tabs as the request editor. Change the URL, headers, params, authorization, settings, or saved messages, then click **Save**. **3. Run it with Try It** The example tab's primary button reads **Try It** rather than Connect. Clicking it opens a **new draft request** pre-filled with the example's configuration, parented to the example's own collection so collection variables still resolve. Connect from that draft. ![A saved WebSocket example open in Requestly, showing the Try It button in the URL bar in place of Connect](https://mintcdn.com/requestly/MFO7lKZDpSld4Afx/images/websocket-example-try-it.light.png?fit=max\&auto=format\&n=MFO7lKZDpSld4Afx\&q=85\&s=26ec0dc10944f3c8251a2e61e6fccf34) An example tab never holds a live connection itself. That is deliberate: the example stays a stable reference, and the session runs in the draft that Try It spawns. See [Create Request & Response Examples](/api-client/examples) for renaming, duplicating, and deleting examples. ## Import and export WebSocket requests are carried in full by Requestly's own collection format. Exporting a collection as a Requestly `.json` file includes every WebSocket request with its URL, headers, params, authorization, settings, and saved messages, and importing that file back restores them exactly. Examples ride along with their parent request. Other formats cannot represent them: * **Postman.** Exporting a collection as a Postman v2.1 collection leaves WebSocket requests out, because the format has no shape for them. The export dialog tells you how many were excluded before you download. * **OpenAPI.** WebSocket requests are skipped, since OpenAPI describes HTTP operations. * **HAR.** Importing a `.har` capture skips `ws://` and `wss://` entries, with one exception: a WebSocket entry that is a GraphQL subscription and has captured frames is imported as a GraphQL request. See [Import & Export](/api-client/import-export) for the full matrix. ## WebSocket requests in the Collection Runner The [Collection Runner](/api-client/collection-runner) runs a collection's requests in sequence. You can select a WebSocket request in the run order and it appears with a **WS** badge, but it does not connect: the runner executes one request at a time and waits for it to finish, which a long-lived connection never does. Each WebSocket request in a run is recorded as **skipped**, with the reason shown on the result row reading "not supported in runner". Skipped requests are counted in the run summary and listed under the **Skipped** tab, so a run stays green and you can see exactly what was left out. Connect to WebSocket endpoints from the request editor instead. Scheduled Runs behave the same way. See [Scheduled Runs](/api-client/scheduled-runs). ## What's next? > **[Socket.IO Requests](/api-client/send-api-request/socketio-request)** > > Work with Socket.IO's named events, acknowledgements, and protocol versions > **[Use Variables](/api-client/environments-and-variables)** > > Make URLs, headers, and payloads dynamic across environments > **[Organize in Collections](/api-client/api-collections)** > > Group related WebSocket requests with the rest of your API # Writing Tests Source: https://docs.requestly.com/api-client/tests Learn to write and execute API tests in Requestly using JavaScript, including validations like status code checks and JSON body tests. Automated API testing ensures endpoints function as expected. Requestly allows you to write tests using JavaScript with the [`rq`](/api-client/scripts#requestly-javascript-api-rq) object enabling validations, schema checks, and automated workflows. Common testing approaches include: * **Contract Testing**: Validate responses against JSON schemas. * **Unit Testing**: Test individual endpoints in isolation. * **Error Handling**: Verify API behavior for invalid inputs. You can execute tests using either [Pre-request scripts](/api-client/scripts#pre-request-scripts) (run before a request is sent) or [Post-response scripts](/api-client/scripts#post-response-scripts) (run after a response is received). ![](https://mintcdn.com/requestly/LX9nR6xxyL7F8mCE/images/tests/a22d4521-145d-4cf7-9311-d44d802bd4b7.png?fit=max\&auto=format\&n=LX9nR6xxyL7F8mCE\&q=85\&s=d39e630eb3d6ae9cee622ccc53d48a01) The Pre-request and Post-response tabs provide a scripting environment that allows dynamic behavior for API requests. * The **Scripts → Pre-request tab** enables processing before sending a request, such as setting variable values or modifying headers. * The **Scripts → Post-response tab** runs after receiving the response and allows for test assertions, logging, and response validation. This tab includes the [Chai.js library](https://www.chaijs.com/api/bdd/), supporting behavior-driven development (BDD) syntax for test assertions. ## Scripting Environment Requestly provides a JavaScript runtime with built-in utilities. Here’s a quick reference table for key methods: | **Method/Interface** | **Description** | | - | - | | [`rq.test`](/api-client/rq-api-reference/rq-test) | Define a test with a name and callback for assertions. | | [`rq.expect`](/api-client/rq-api-reference/rq-expect) | Use [Chai.js BDD ](https://www.chaijs.com/api/bdd/)style assertions to compare values. | | [`rq.environment`](/api-client/rq-api-reference/rq-environment) | Access and manage environment variables. | | [`rq.globals`](/api-client/rq-api-reference/rq-globals) | Access and manage global variables. | | [`rq.response`](/api-client/rq-api-reference/rq-response) | Access response details (status, body, headers, etc.). | | [`rq.request`](/api-client/rq-api-reference/rq-request) | Access request details (method, headers, body, URL, etc.). | ## Writing Tests To create a test, use the following syntax: > [!TIP] > > Requestly tests use [**Chai.js for assertions**](https://www.chaijs.com/api/bdd/). For more details and examples, visit the official [***Chai.js documentation***](https://www.chaijs.com/). ```javascript theme={null} rq.test("Test name", () => { rq.expect(actualValue).to.equal(expectedValue); }); ``` ## Example Tests ### Status Code Check ```javascript theme={null} rq.test("Status is 200", () => { rq.response.to.have.status(200); }); ``` ### JSON Body Validation ```javascript theme={null} rq.test("User exists", () => { rq.response.to.have.jsonBody("user.name", "John"); }); ``` ### Header Check ```javascript theme={null} rq.test("Has auth header", () => { rq.response.to.have.header("Authorization"); }); ``` ### Schema Validation ```javascript theme={null} rq.test("Valid schema", () => { rq.response.to.have.jsonSchema({ type: "object", required: ["id"], properties: { id: { type: "number" } } }); }); ``` ### Skipping Tests ```javascript theme={null} rq.test.skip("Temporarily disabled test", () => { // This test won't run }); ``` ## Response specific assertions The `.to` API is supported only for response data in Post-response scripts. **Status code assertions** ```javascript theme={null} // Success responses rq.response.to.be.ok // 2XX rq.response.to.be.success // 200 rq.response.to.be.accepted // 202 // Client error responses rq.response.to.be.badRequest // 400 rq.response.to.be.unauthorized // 401 rq.response.to.be.forbidden // 403 rq.response.to.be.notFound // 404 rq.response.to.be.rateLimited // 429 rq.response.to.be.clientError // 4XX // Server error responses rq.response.to.be.serverError // 5XX // Other status categories rq.response.to.be.error // 4XX or 5XX rq.response.to.be.info // 1XX rq.response.to.be.redirection // 3XX ``` `.to.have` **assertions** ```javascript theme={null} // Checks if response body exactly matches expected value. rq.response.to.have.body(expectedValue: string) // Checks response status code or text. rq.response.to.have.status(expectedValue: number | string) rq.response.to.have.status(200); rq.response.to.have.status("OK"); // Checks if response has the specified header. The header name is matched // case-insensitively. rq.response.to.have.header(headerName: string) rq.response.to.have.header("Content-Type"); // With a second argument, also checks the header's value. The value must match // exactly: the comparison is case-sensitive and whitespace is not trimmed. rq.response.to.have.header(headerName: string, expectedValue: string) rq.response.to.have.header("Content-Type", "application/json"); // Validates that response body is valid JSON. rq.response.to.have.jsonBody(); // Checks if a path exists in the response. rq.response.to.have.jsonBody(path: string) rq.response.to.have.jsonBody("user.name"); // Checks if a JSON path has a specific value. rq.response.to.have.jsonBody(path: string, value: any) rq.response.to.have.jsonBody("user.name", "John"); // Validates the response body against a JSON schema. Accepts optional Ajv configuration. rq.response.to.have.jsonSchema(schema: object, ajvOptions?: AjvOptions) rq.response.to.have.jsonSchema({ type: "object", required: ["id", "name"], properties: { id: { type: "number" }, name: { type: "string" }, email: { type: "string", format: "email" } } }, { allErrors: true }); ``` **Negation with** `.to.not` All the above assertions can be negated by inserting `.not` after `.to`: ```javascript theme={null} rq.response.to.not.be.error; rq.response.to.not.have.header("X-Custom"); rq.response.to.not.have.jsonBody("error"); ``` > [!NOTE] > > `.not.have.header()` checks only that the header is **absent**. If you pass a > value as the second argument it is ignored, so > `rq.response.to.not.have.header("Content-Type", "text/html")` fails whenever > the header is present, whatever its value. To assert that a header exists but > holds a different value, compare it directly: > `rq.expect(rq.response.headers.get("Content-Type")).to.not.equal("text/html")`. # AWS Secrets Manager Source: https://docs.requestly.com/api-client/vault/aws-secrets-manager Connect your AWS account to fetch centrally managed secrets into the Requestly vault and reference them in API requests with the {{vault:key}} syntax. Connect your AWS account to pull centrally managed secrets into the [Vault](/api-client/vault). AWS secrets share the same `{{vault:key}}` namespace as local secrets, so your requests don't need to know where a secret comes from. > [!NOTE] > > **Availability:** External secret providers, including AWS Secrets Manager, require the desktop app, a signed-in Cloud project, and an eligible plan, and are rolling out gradually. If you don't see the option to add a provider, update to the latest version or contact support. Local vault remains fully functional without signing in. *** ## Setting up an AWS provider **1. Open the Vault page** Click **Vault** in the app footer. **2. Connect a provider** Click **Connect provider** below the Local Secrets section. **3. Enter AWS credentials** Fill in the configuration form: | Field | Required | Description | | - | - | - | | **Instance name** | Yes | A label for this configuration (e.g., "Production", "Staging") | | **Access key** | Yes | Your AWS IAM access key | | **Secret key** | Yes | Your AWS IAM secret key | | **Region** | Yes | AWS region (e.g., `us-east-1`) | | **Session token (optional)** | No | Required only for STS temporary credentials | **4. Test the connection** Click **Test connection** to validate your credentials against AWS. You can still save even if the test fails and fix credentials later. **5. Save** Click **Add provider**. The AWS Secrets Manager section appears on the Vault page. *** ## Required AWS IAM permissions Your IAM user or role needs the following permissions: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:*" } ] } ``` > [!TIP] > > Scope the `Resource` to specific secret ARNs for least-privilege access instead of using `*`. *** ## Adding and fetching secrets **1. Add a secret mapping** In the AWS Secrets Manager section, click **Add secret**. Enter: * **Alias**: the key you'll use in `{{vault:alias}}` * **Secret Name or ARN**: the AWS secret identifier * **Mode**: `Plaintext` or `JSON` **2. Fetch the secret** Click **Fetch secrets** to pull the values. Requestly calls the AWS `GetSecretValue` API and stores the result encrypted locally. **3. Use it in a request** Reference the secret using `{{vault:alias}}` in any request field. It resolves on send just like a local secret. *** ## JSON secrets When an AWS secret contains a JSON object, Requestly auto-expands it into dot-separated keys: ``` AWS Secret "dbCredentials": { "username": "admin", "password": "s3cret", "host": "db.example.com" } ``` This creates three vault entries: * `{{vault:dbCredentials.username}}` resolves to `admin` * `{{vault:dbCredentials.password}}` resolves to `s3cret` * `{{vault:dbCredentials.host}}` resolves to `db.example.com` Nested JSON objects expand recursively with dot notation. *** ## Refreshing secrets after rotation Fetched values are cached locally and survive app restarts. Requestly also re-fetches every secret of the active configuration automatically when the app starts, so a secret rotated in AWS overnight is usually current before you send your first request. While that startup fetch runs, the Secret Provider section shows a "Loading secrets from provider at startup" banner. If the startup fetch fails, a warning banner names the affected configuration and offers a **Fetch secrets** button to retry. You can click **Fetch secrets** at any time to pull the current values for every row in the section. The **Last fetched** label next to the configuration selector helps you judge staleness. > [!WARNING] > > There is no scheduled refresh. Fetching always refreshes the whole section, not a single row. *** ## Multiple AWS configurations You can store multiple AWS configurations (e.g., Production, Staging, EU region) and switch between them: 1. Click the **config selector** in the AWS section header 2. Select a different configuration. The secrets table swaps to that config's secrets. 3. `{{vault:key}}` references resolve from the **active** configuration only Each configuration maintains its own independent set of secrets and cached values. Switching configs preserves all caches, so no re-fetching is needed. To add a new configuration, select **+ Add new configuration** from the config selector dropdown. *** ## Credential errors When AWS credentials expire or become invalid: * The affected secret row shows an error message * The provider config section shows an error indicator * The failed secret's cached value is **cleared** from disk and memory, so `{{vault:alias}}` stops resolving until a fetch succeeds. Only the rows that failed are affected. To fix: edit your credentials in the same provider config form (no separate reauthentication flow), save, and retry the fetch. *** ## Move to local You can convert any AWS secret to a local vault secret: 1. Select **Move to local** on an AWS secret 2. The secret moves to the Local Secrets section with the last fetched value preserved 3. It becomes fully editable and is no longer linked to AWS *** ## FAQ > **Can I use multiple AWS accounts at the same time?** > > You can store multiple AWS configurations, but only one is active at a time. The active config's secrets are the ones that resolve via `{{vault:key}}`. Switch between configs using the config selector in the AWS section header. > **Do vault secrets auto-refresh when rotated in AWS?** > > No. Fetched values are cached locally and persist until you refresh them. Click **Fetch secrets** to pull the latest values from AWS. > **Can scripts modify AWS secrets?** > > No. `rq.vault` is read-only from scripts. Only `rq.vault.get()`, `rq.vault.has()`, and `rq.vault.toObject()` are available. Manage AWS secrets from the Vault page or in AWS directly. *** ## Related Documentation * [Vault Overview](/api-client/vault) * [`rq.vault` Scripting API](/api-client/rq-api-reference/rq-vault) # Azure Key Vault Source: https://docs.requestly.com/api-client/vault/azure-key-vault Connect an Azure service principal to pull secrets from one or more Azure key vaults into the Requestly vault and reference them in API requests with the {{vault:key}} syntax. Connect an Azure service principal to pull secrets from your Azure key vaults into the [Vault](/api-client/vault). Azure secrets share the same `{{vault:key}}` namespace as local secrets, so your requests don't need to know where a secret comes from. Each secret row carries its own vault name, so a single connection can read from several key vaults in the same Azure tenant. > [!NOTE] > > **Availability:** External secret providers, including Azure Key Vault, require the desktop app, a signed-in Cloud project, and an eligible plan, and are rolling out gradually. If you don't see the option to add a provider, update to the latest version or contact support. Local vault remains fully functional without signing in. *** ## What you need from Azure Requestly signs in to Azure with the service principal client credentials flow, so you need an app registration and a client secret before you configure anything in the app. **1. Note the key vault name** In the Azure portal, open the key vault holding your secrets and note its **name** (the first label of its URI, for example `my-vault` in `https://my-vault.vault.azure.net/`). You enter this name per secret in Requestly, not once per connection. > [!NOTE] > > Requestly connects to the global Azure cloud only. Sovereign clouds such as Azure Government and Azure China are not supported. **2. Register an application** In **Microsoft Entra ID** (formerly Azure Active Directory), go to **App registrations** and register a new application. From its overview page, copy: 1. The **Directory (tenant) ID**. 2. The **Application (client) ID**. **3. Create a client secret** Under **Certificates & secrets** for that app registration, create a new client secret and copy its **value** immediately. Azure only shows the value once. > [!WARNING] > > Client secrets expire. When yours expires, secret fetches start failing until you create a new one and update the credentials in Requestly. **4. Grant the app access to the secrets** On the key vault, assign the app registration the **Key Vault Secrets User** role so it can read secret values. > [!NOTE] > > If the vault still uses the legacy access policy permission model instead of Azure role-based access control, add an access policy granting the app the **Get** secret permission instead. *** ## Setting up an Azure provider **1. Open the Vault page** Click **Vault** in the app footer. **2. Connect a provider** Click **Connect provider** below the Local Secrets section, or click **Add provider** in the Secret Provider section header if you already have another provider configured. **3. Choose Azure Key Vault and enter credentials** Set **Provider type** to **Azure Key Vault**, then fill in the form: | Field | Required | Description | | - | - | - | | **Instance name** | Yes | A label for this configuration (e.g., "Production", "Staging") | | **Tenant ID** | Yes | The Directory (tenant) ID of your Microsoft Entra ID directory | | **Client ID** | Yes | The Application (client) ID of your app registration | | **Client secret** | Yes | The client secret value you created for that app registration | ![Add provider modal in Requestly with Azure Key Vault selected, showing the Instance name, Tenant ID, Client ID, and Client secret fields](https://mintcdn.com/requestly/KyfY364uen9DZn5h/images/vault-azure-add-provider.light.png?fit=max\&auto=format\&n=KyfY364uen9DZn5h\&q=85\&s=56ba528b36568b70fc839826c3b483b3) **4. Test the connection** Click **Test connection**. Requestly exchanges your credentials for an Azure access token and reports **Connected successfully** or the error Azure returned. You can still save if the test fails and fix the credentials later. > [!NOTE] > > The test only proves the tenant ID, client ID, and client secret are valid. It cannot check whether the app can read a specific vault, because vault names live on individual secrets. **5. Save** Click **Add provider**. The Secret Provider section appears on the Vault page with your configuration selected. *** ## Adding and fetching secrets **1. Add a secret mapping** In the Secret Provider section, click **Add secret** and fill the row: * **Alias**: the key you'll use in `{{vault:alias}}` * **Vault name**: the key vault to read from, for example `my-vault` * **Secret name**: the name of the secret inside that vault ![Requestly Vault page showing the Azure secret table with Alias, Vault name, Secret name, and Secret columns](https://mintcdn.com/requestly/KyfY364uen9DZn5h/images/vault-azure-secrets-table.light.png?fit=max\&auto=format\&n=KyfY364uen9DZn5h\&q=85\&s=e6c7df9d978cb6457b889aef22d53215) **2. Fetch the values** Click **Fetch secrets**. Requestly reads every row that has an alias, a vault name, and a secret name, and stores the values encrypted locally. Rows with a missing field are skipped. **3. Check the result** Each row lands in one of three states: * **Never fetched**: the **Secret** column shows **Not fetched**. * **Fetched**: the **Secret** column shows a masked value. Hover the value and click the eye icon to reveal it. * **Failed**: the **Secret** column shows **Error** in red, with the error message on a line beneath the row. Any value the row showed before is cleared. **4. Use it in a request** Reference the secret using `{{vault:alias}}` in any request field. It resolves on send just like a local secret. *** ## Remove a secret mapping To remove a mapping, open the row menu and select **Delete**. This removes the mapping and its cached value from Requestly. Nothing changes in Azure. *** ## Vault and secret name rules Requestly checks both names before calling Azure, so most typos fail immediately with a clear message: * **Vault name**: 3 to 24 characters, letters, numbers, and hyphens only, starting with a letter and ending with a letter or number. * **Secret name**: 1 to 127 characters, letters, numbers, and hyphens only. A name that breaks these rules shows an `Invalid vaultName` or `Invalid secretName` error on the row. *** ## Reading from multiple key vaults Because the vault name lives on each secret row rather than on the connection, one Azure provider configuration can read from any number of key vaults, as long as the same app registration has access to each of them: | Alias | Vault name | Secret name | | - | - | - | | `DB_PASSWORD` | `prod-data-vault` | `db-password` | | `STRIPE_KEY` | `prod-payments-vault` | `stripe-live-key` | If one vault denies access, only that row fails. The rest still fetch. *** ## Refreshing secrets after rotation Fetched values are cached locally and survive app restarts. Requestly also re-fetches every secret of the active configuration automatically when the app starts, so a secret rotated in Azure overnight is usually current before you send your first request. While that startup fetch runs, the Secret Provider section shows a "Loading secrets from provider at startup" banner. If the startup fetch fails, a warning banner names the affected configuration and offers a **Fetch secrets** button to retry. You can click **Fetch secrets** at any time to pull the current values for every row in the section. The **Last fetched** label next to the configuration selector helps you judge staleness. > [!WARNING] > > There is no scheduled refresh and no per-row refresh for Azure secrets. Fetching always refreshes the whole section. *** ## Multiple Azure configurations You can store several Azure configurations (for example, one per Entra ID tenant) and switch between them: 1. Click the **configuration selector** in the Secret Provider section header. Azure entries are labeled ` (Azure)`. 2. Select a different configuration. The secret table swaps to that configuration's secrets. 3. One Azure configuration is active at a time, and `{{vault:key}}` resolves from that one. Secrets from an active configuration of a different provider, such as AWS Secrets Manager, keep resolving alongside it. To edit or remove a configuration, click **Manage providers**. Editing the credentials discards the cached Azure access token, so the next fetch signs in again with the new values. *** ## Errors and what they mean Fetch errors appear beneath the affected row. A failed fetch also clears that secret's cached value from disk and memory, so `{{vault:alias}}` stops resolving until a fetch succeeds. Only the rows that failed are affected: every other row keeps its value. | Message | Cause | Fix | | - | - | - | | `Access denied - check that the Service Principal has Key Vault Secrets User role, and that the secret is not disabled` | The app registration cannot read the secret, or the secret is disabled in Azure | Assign the **Key Vault Secrets User** role on that vault, and check that the secret is enabled | | `Secret not found - check the vault name and secret name` | The vault name or the secret name doesn't match anything in Azure | Correct the **Vault name** and **Secret name** cells | | `Azure Key Vault returned 401 - token may have been revoked` | The access token was rejected, usually because the client secret was rotated or revoked | Update the **Client secret** in the provider configuration | | `Connection timed out - check your network connection` | Azure did not respond within 10 seconds | Check your network connection, VPN, or proxy | | `Cannot reach Azure - check your network connection` | The Azure host could not be resolved, or it refused the connection | Check your DNS settings, network connection, VPN, or proxy | | `Network error - check your connection` | Any other network failure while contacting Azure | Check your network connection, then fetch again | | An Azure sign-in error on **Test connection** | The tenant ID, client ID, or client secret is wrong | Re-copy the values from the app registration | > [!TIP] > > A 401 is retried once with a fresh token before the row is marked as failed, so a token that simply aged out never surfaces as an error. *** ## FAQ > **Do JSON secrets expand into dot-separated keys?** > > No. An Azure secret is fetched as a single string value and stored under its alias. The JSON auto-expansion available for [AWS Secrets Manager](/api-client/vault/aws-secrets-manager) secrets does not apply to Azure secrets. > **Can I use several Azure tenants at the same time?** > > You can store multiple Azure configurations, but only one Azure configuration is active at a time. Its secrets are the Azure ones that resolve via `{{vault:key}}`, and an active configuration of a different provider, such as AWS Secrets Manager, keeps resolving alongside it. Switch between Azure configurations using the configuration selector in the Secret Provider section header. > **Can I pin a secret to a specific version?** > > No. Requestly always reads the current version of an Azure secret. There is no version pinning for Azure secrets. > **Can I convert an Azure secret into a local secret?** > > Not directly. The Azure row menu offers **Delete** only. To keep a value locally, reveal it in the Secret column, then add it as a new secret in the Local Secrets section. > **Where is my client secret stored?** > > Provider credentials are encrypted alongside your vault data using your operating system's keychain. They never sync to Requestly servers and never appear in collection exports. > **Can scripts modify Azure secrets?** > > No. `rq.vault` is read-only from scripts. Only `rq.vault.get()`, `rq.vault.has()`, and `rq.vault.toObject()` are available. Manage Azure secrets from the Vault page or in Azure directly. *** ## Related Documentation * [Vault Overview](/api-client/vault) * [AWS Secrets Manager](/api-client/vault/aws-secrets-manager) * [`rq.vault` Scripting API](/api-client/rq-api-reference/rq-vault) # Overview Source: https://docs.requestly.com/api-client/vault/vault Store sensitive values locally, pull secrets from external providers like AWS Secrets Manager, and reference them in your API requests without ever exposing credentials in collections, exports, or cloud sync. ## What is Vault ? Vault is a local-first encrypted secrets store built into the Requestly desktop app. It lets you: * **Store secrets locally**: API keys, tokens, and passwords encrypted on your machine via OS keychain. * **Pull secrets from external providers**: connect services like [AWS Secrets Manager](/api-client/vault/aws-secrets-manager) and [Azure Key Vault](/api-client/vault/azure-key-vault) to fetch centrally managed credentials. * **Reference secrets in requests**: use `{{vault:key}}` syntax in URLs, headers, auth fields, and body. * **Share collections safely**: secret references travel with collections, but values stay on each user's machine. > [!NOTE] > > Vault requires the **Requestly desktop app** (Electron) for OS-level encryption via `safeStorage`. Vault features are not available in the web-only mode. *** ## Local Vault The local vault is available to **all users**. No sign-in or paid plan is required. Secrets are encrypted at rest using your operating system's keychain (macOS Keychain, Windows Credential Manager, or Linux Secret Service). ### Creating a local secret **1. Open the Vault** Click the **Vault** button in the app footer to open the Vault page. **2. Add a secret** Click **Add Secret** at the bottom of the Local Secrets table. A new row appears with editable Key and Value cells. **3. Enter key and value** Type a key name (e.g., `my-api-key`) and a value (e.g., `sk-abc123`). Press **Enter** to save. The value masks immediately. ### Using a vault secret in a request Reference any vault secret using the `{{vault:key}}` syntax in any request field: ``` Authorization: Bearer {{vault:my-api-key}} ``` When you send the request, `{{vault:my-api-key}}` resolves to the actual value. The resolved value **never** appears in the editor, console output, collection exports, or cloud sync. Only the `{{vault:key}}` reference is visible. > [!TIP] > > Vault secrets appear in the standard `{{` autocomplete dropdown alongside environment and collection variables, labeled with a **Vault** scope badge. ### Inline editing Click any key or value cell in the vault table to edit it in place. No modals or separate forms are needed. Changes save automatically on blur or Enter. ### Deleting a secret Delete a vault secret from the table. Any `{{vault:key}}` references to the deleted secret become unresolved immediately. *** ## External secret providers Connect centrally managed secret managers to pull secrets into the vault. External provider secrets share the same `{{vault:key}}` namespace as local secrets, so your requests don't need to know where a secret comes from. * [**AWS Secrets Manager**](/api-client/vault/aws-secrets-manager): connect an AWS account to fetch and cache secrets, with support for JSON expansion, multiple configurations, and rotation refresh. * [**Azure Key Vault**](/api-client/vault/azure-key-vault): connect an Azure service principal to fetch secrets, with a vault name per secret so one connection can read from several key vaults. * **HashiCorp Vault** and **1Password** (SDK and Connect) are also supported as providers and are rolling out gradually. > [!NOTE] > > External provider integrations require the desktop app, a signed-in Cloud project, and an eligible plan, and are rolling out gradually. Local vault remains fully functional without signing in. *** ## Scripting API Access vault secrets programmatically in pre-request and post-response scripts using the `rq.vault` API: ```javascript theme={null} // Pre-request script const signingKey = rq.vault.get('signing-key'); const jwt = generateJwt(payload, signingKey); rq.variables.set('auth-token', jwt); ``` Then use `{{auth-token}}` in the Authorization header. The signing key never leaves the vault. See the full [`rq.vault` reference](/api-client/rq-api-reference/rq-vault) for the read-only `get`, `has`, and `toObject` methods. *** ## Importing from Postman Requestly preserves `{{vault:key}}` references when importing Postman collections. No syntax translation is needed. ### What happens on import 1. `{{vault:key}}` references in URLs, headers, auth fields, and body are **preserved as-is**. 2. `pm.vault.get/set/unset/has` calls in scripts are **automatically translated** to `rq.vault.get/set/unset/has`. 3. For each detected `{{vault:key}}` reference, a **local secret is pre-created** with an empty value. 4. A post-import summary lists the pre-created secrets. ### After import Open the Vault page. You'll see the pre-created secret keys with empty values. Fill in the values, and your imported requests will resolve immediately. > [!NOTE] > > Postman collection exports never include vault secret values, only the `{{vault:key}}` references. You'll need to re-enter the actual values in your Requestly vault. *** ## Namespace and resolution ### Resolution priority If the same key exists in both Local Secrets and an external provider (e.g., AWS), the **external secret wins**. The local secret shows an amber "overridden by duplicate key" warning. ### Variable hover Hovering over a `{{vault:key}}` reference in any editor field shows: * The masked value (`••••••••`) * The scope: **Vault** * The source: **Local** or the external provider name Unresolved references show an "Unresolved" diagnostic with guidance. ### Console masking Vault secret values are **always masked** in the console and response viewer. You'll see the `{{vault:key}}` reference or `••••••••`, never the plaintext value. *** ## Security model | Property | Behavior | | - | - | | **Encryption at rest** | All vault data encrypted via Electron `safeStorage` (OS keychain). Files on disk are not human-readable. | | **Device isolation** | Each OS user account has a separate vault. A different OS user on the same machine cannot access your secrets. | | **No cloud sync** | Vault values are never sent to Requestly servers, never included in cloud project sync. | | **No export inclusion** | Collection exports contain `{{vault:key}}` references, never resolved values. | | **Provider credentials** | Stored encrypted alongside vault secrets. Never appear in logs or plaintext files. | | **Session independence** | Local vault works regardless of sign-in state. External provider features require authentication. | > [!WARNING] > > **Linux users:** Vault requires a D-Bus Secret Service implementation (GNOME Keyring, KWallet, or equivalent). If no keyring is configured, vault features are disabled but the rest of the app works normally. *** ## FAQ > **Does vault work in the web app?** > > No. Vault requires the desktop app (Electron) for OS-level encryption. This matches how Postman's vault requires the Desktop Agent. > **What happens if I sign out?** > > Local vault secrets persist and continue resolving. They're tied to your OS user session, not your Requestly account. Previously fetched external provider secrets also remain cached and resolvable. However, you cannot configure new providers or fetch new secrets until you sign back in. > **What happens to vault references in CI/CD?** > > Vault is desktop-only and does not work in CI/CD pipelines. For automated runs, use environment variables or your CI platform's native secret injection. > **Can scripts modify vault secrets?** > > No. `rq.vault` is read-only from scripts for both local and external provider secrets. Only `rq.vault.get()`, `rq.vault.has()`, and `rq.vault.toObject()` are available. To create, update, or delete a secret, use the Vault page. To keep a derived value for the current run, use `rq.variables.set()`. # Verify Your Linux Download Source: https://docs.requestly.com/api-client/verify-linux-download Check that the Requestly AppImage you downloaded is the genuine file signed by Requestly before you run it. Every Requestly Linux release is signed. Before you run the AppImage for the first time, you can check that the file on your machine is exactly the one Requestly published and was not changed on the way to you. This check is optional, and you only need it once. After the first install, the app checks the signature of every update for you before installing it. ## Before you start You need: * The AppImage you downloaded, for example `requestly-api-client-2610.8.1-linux-x86_64.AppImage`. * A terminal with `curl` and `openssl`. Most Linux distributions include both. Run the commands below from the folder that contains the AppImage. ## Step 1: Save the Requestly public key This is the key Requestly uses to sign every Linux release. It is published on this page, separately from the download server, so that a problem with the download server cannot change both the file and the key you check it against. ```bash theme={null} cat > requestly-linux-signing.pem <<'EOF' -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERdJfshk34vq+ORkA+acmSVwXb86f 3EqQJt8IFglNE5qi3fQgBDcZH97TOPQkEzICvbdrtA4RAuD9uUKACy/0rQ== -----END PUBLIC KEY----- EOF ``` ## Step 2: Download the signature for your file Each AppImage has a matching signature file. Set `APPIMAGE` to the name of the file you downloaded, and the commands fetch the signature for that exact version. ```bash theme={null} APPIMAGE=requestly-api-client-2610.8.1-linux-x86_64.AppImage VERSION=$(echo "$APPIMAGE" | sed -E 's/^requestly-api-client-(.+)-linux-x86_64\.AppImage$/\1/') curl -fsSLO "https://assets.requestly.com/assets/desktop/releases/${VERSION}/${APPIMAGE}.sig" ``` ## Step 3: Verify the file ```bash theme={null} openssl dgst -sha256 -verify requestly-linux-signing.pem -signature "${APPIMAGE}.sig" "${APPIMAGE}" ``` If the file is genuine, the command prints: ```text theme={null} Verified OK ``` You can now make the AppImage executable and run it. ## If verification fails Any output other than `Verified OK` means the check failed. Depending on your OpenSSL version, the message is `Verification Failure` or `Verification failure`. If that happens: 1. **Do not run the file.** Delete it. 2. Check that `APPIMAGE` matches your file name exactly, including the version number. A signature only matches the release it was made for. 3. Download the AppImage again from the [Getting Started](/api-client/overview) page and repeat the steps. If a fresh download still fails, contact [Requestly support](mailto:contact@requestly.io) and do not run the file. # Changelogs Source: https://docs.requestly.com/changelogs What's new in the Requestly API Client, grouped by desktop release. Updates to the Requestly API Client, newest first. Each entry is anchored to a desktop release and collects everything that shipped under it. **v2610.23.2** Oct 23, 2026 ### ✨ Improvements * The app now loads up to 35% faster on slower connections by deferring large file-parsing components until they are first needed. ### 🐛 Fixes * The desktop app has been updated to Electron 43, patching a security vulnerability in how compressed server responses were decoded. * Long environment names that were clipped in the project switcher now show a tooltip with the full name. **v2610.23.1** Oct 23, 2026 ### 🚀 New * You can now assign a color to each environment, and the environment picker shows a matching tint around the active one for quick identification. * The AI assistant can now read, edit, rename, duplicate, and delete your saved examples, and save any request as a new example directly from the conversation. * Desktop installations managed by your IT team now show a clear 'Updates are managed by your IT administrator' message in About and during a manual update check, instead of failing silently. ### ✨ Improvements * The Variables list now renders smoothly for large variable sets, loading only the rows visible on screen at a time. ### 🐛 Fixes * Removed Brotli decompression for server responses to address a critical security vulnerability (CVE-2026-111497); servers that follow standard content negotiation will automatically switch to gzip or deflate. * Blocked TLS certificate chains issued through the compromised eMudhra certificate authorities in the app's HTTP request engine. * Extended the eMudhra certificate block to also cover the desktop app's built-in Chromium network layer. * Fixed a bug where very large projects and collections failed to load at all instead of loading in pages. * The 'Contact support' button on the crash screen now opens a pre-filled bug report with crash details attached. * Fixed an issue where the sample collection in a new project could disappear if it arrived after the project finished loading. * The desktop app now shows an error immediately if its background service process fails to start, rather than appearing to hang indefinitely. * Collection runs in the CLI now correctly authenticate requests that use OAuth 2.0. * The CLI now carries cookies set by one request forward to subsequent requests in the same collection run. * The CLI now runs requests in the order you saved in the collection, instead of always using the default order. * The --timeout-request and --timeout-script flags in the CLI now correctly stop requests and scripts that exceed the time limit. * Fixed a CLI crash that occurred when a collection run included previously executed requests or entries that stream their response. * faker-js is now bundled in the CLI so scripts that use it in collection runs work without any extra setup. * The CLI now surfaces specific error details for each failed request, script error, and run-level failure across all output formats. * The environment picker now shows the full environment name in a tooltip when the name is too long to display in full. * Fixed the device authorization flow so that authenticating the CLI with your account works correctly again. * Fixed update status display in the Windows desktop app for managed installs, including a progress bar that was stuck at zero and a 'Restart to update' prompt that appeared when updates were disabled by an IT policy. * Fixed a startup error in web browsers that do not yet support the URL.canParse API used in the version check. **v2610.8.1** Oct 8, 2026 ### 🚀 New * You can now edit a variable's value directly from the inline hover card without opening the environment editor. * The GraphQL schema explorer now has a search box for filtering fields and a toggle to show or hide field descriptions. * You can now share a direct link to any collection with teammates who already have access to the project. * The AI assistant can now read your mock servers and routes to help you understand and debug your mocks. * The AI assistant can now create and save mock servers, including generating one automatically from a collection's saved examples. * Type /debug or /visualize at the start of a chat message to guide the AI assistant toward a specific task. * The AI assistant can now draft, review, and save changes to your API specification files. * The AI assistant can now read your API specifications, manage their published releases, and handle Quick Share links on your behalf. ### ✨ Improvements * The active sub-tab (such as Messages or Headers) is now remembered when you navigate away from a request and come back. * Long URLs in the request bar now wrap onto multiple lines when focused instead of requiring horizontal scrolling. * Pre-request and post-response scripts that exceed their time limit are now stopped immediately instead of continuing to run silently. * The git panel now shows a warning when you are about to commit a local auth file that contains a plaintext credential. * Scheduled runs now retry requests that fail before any data has been sent, reducing unnecessary run failures on flaky connections. ### 🐛 Fixes * Fixed a bug where internal crash-reporting trace headers were being added to the HTTP requests you send. * Fixed a bug where a plus sign in a query string was not being decoded as a space when the URL was split into individual parameters. * Fixed the sidebar in narrow windows so it overlays the main content area correctly, and the toggle button now always responds. * New request drafts now start with the auth configuration inherited from their parent collection instead of no auth. * Fixed an issue where local project auth files were being added to .gitignore automatically, preventing you from tracking them in git. * Postman collections imported with OAuth 2.0 now correctly carry the token header prefix, and unsupported token placements show a warning. * Fixed an issue where Postman query parameter values in nested-object format were being double-encoded after import. * Postman collections now correctly import the OAuth 2.0 redirect URI as the callback URL. * Fixed the OAuth 2.0 callback URL being set to an incorrect address when importing collections. * OpenAPI 3.1.2 and newer patch releases of 3.0 and 3.1 can now be imported. * gRPC request targets that do not include an explicit scheme are now handled correctly when the request is sent. * Fixed a vault issue on Linux where a master key created under a basic keyring was not re-encrypted when a stronger keyring became available. * The parameters table columns can be resized by dragging again. * The GraphQL schema explorer now displays the full type, including list and non-null markers, on argument rows. * The expand arrow in the GraphQL schema explorer now behaves consistently on every click. * Copying a value from the Vault panel now copies the real secret instead of the masked display value. * Local projects on Windows now show the folder name instead of the full file system path in the project switcher. * Fixed a sync issue where environments, packages, message templates, and mock servers created by teammates were not appearing for other project members. * Fixed variable resolution so that collection-level variables are correctly available inside deeply nested sub-collections. **v2609.9.1** Sep 9, 2026 ### 🚀 New * The AI assistant can now connect to live streaming sessions (WebSocket, Socket.IO, MQTT, gRPC, and GraphQL subscriptions), send messages, read incoming data, and disconnect - all through natural language. * The AI assistant can now read your collection structure and reorganize it by moving, renaming, duplicating, or deleting requests and folders. ### 🐛 Fixes * rq.variables.get() now reads from all variable scopes - runtime, environment, collection, and global - matching how pm.variables behaves in Postman. * Fixed a 'Cannot serialize value' error that appeared when a script modified rq.request.body in Developer mode on desktop. * Test results and variable writes that a script collects before throwing an error are now preserved and applied, rather than discarded. * When a new version is deployed while the app is open, you now see an automatic reload instead of an 'App crashed' error. * The tooltip shown before running Update Collection in the API Design editor now correctly lists the collection description as a synced field. * When importing a collection fails due to malformed JSON, you now see a clear 'invalid JSON' error instead of a generic internal error. * Wildcard entries in your organization's package allowlist (such as axios\@1.\*) now correctly approve all matching imported packages. **v2609.3.1** Sep 3, 2026 ### 🚀 New * Variables and helpers you assign in a collection pre-request script are now available to every later script in the same run, matching how Postman handles script scope. * `rq.request.url` is now a URL object with the same interface as Postman's `pm.request.url`, so scripts that call methods like `getHost()` or `getPath()` work after import without modification. ### ✨ Improvements * When the CLI cannot set up a cloud collection before a run, it now reports the specific error so you know exactly what failed. ### 🐛 Fixes * The OAuth 2.0 'Get Token' step now uses your proxy and certificate settings, fixing token acquisition failures on corporate networks. Error details now name the specific cause, such as the proxy host or the TLS error code. * Setting 'No Auth' on a request, folder, or collection now saves correctly, so requests no longer inherit or keep a previously configured token. * More Postman script patterns now convert correctly on import, including optional chaining, class methods, spread arguments, and user-defined variables named `pm` that were previously getting rewritten into broken calls. * Two types of valid Postman collections that were incorrectly rejected during import can now be imported. * A transient network error during the OAuth device login flow no longer ends the session. The app retries automatically and only shows an error if it cannot recover. * The DevTools panel now reopens on the same tab you last had selected instead of resetting to the default tab every time. * Clicking the action button on a load test that has never been run now opens the load tests list instead of an empty runs page. * Pressing Cmd+S or Ctrl+S in the custom package editor no longer triggers a save when there are no unsaved changes. * Running a collection with the CLI no longer exits before network reporters finish writing their results. **v2609.1.1** Sep 1, 2026 ### 🚀 New * You can now import collections from Bruno, including requests, authorization settings, client certificates, and pre/post-request scripts. * You can now disable individual auto-generated request headers, such as Content-Type, directly from the Headers tab. ### ✨ Improvements * Requests now include Accept and Accept-Encoding headers by default, matching standard browser and API tool behavior. * Authorization password fields now mask their content while still resolving references. * When Auto-select is enabled in the Cloud Agent picker, individual agent options are now visually locked so they cannot silently override your selection. * Pre-request and post-response scripts now execute faster using an improved scripting engine. * Projects with large numbers of requests and collections now open significantly faster. ### 🐛 Fixes * Fixed form-data requests failing when the request already included a non-multipart Content-Type header. * Fixed multipart form uploads sending a duplicate Content-Type header that caused some servers to reject the request. * Fixed scripts that write to collection variables updating the wrong collection instead of the intended root collection. * Fixed several display and behavior issues in the Bruno importer. * Fixed OpenAPI imports failing entirely when the spec contained unrecognized root-level fields - they now succeed with a warning instead. * Fixed text with Windows-style line endings (CRLF) being silently dropped when pasted into single-line input fields. * Fixed a script loop guard stopping only the current iteration instead of ending the entire collection run. * Fixed the GraphQL schema explorer showing items in inconsistent order and with alignment issues. * Fixed WebSocket and Socket.IO connections sometimes being initiated when connecting was not yet allowed. * Fixed an error that occurred when dragging a collection folder into one of its own subfolders. * Fixed the Retry button in the response panel not working correctly or being unreachable in some states. * Fixed the API Design editor duplicating an existing top-level key when inserting a new schema entry. * Fixed the cookie manager not allowing you to add a cookie for a domain with no existing cookies. * Fixed Server-Sent Event (SSE) responses that used content-encoding not streaming in real time. * Fixed a false warning about overwriting a variable appearing when saving a response value with Set as Variable. * Fixed the GraphQL schema not being available for autocompletion immediately after opening a request editor. * Fixed OpenAPI files failing to import as a collection when a validation step that applies only to specs was incorrectly triggered. * Fixed collection imports not including global environments. * Fixed scripts that set collection variables by key creating a duplicate variable instead of updating the existing one. * Fixed the cURL importer corrupting request headers when pasting a request copied from browser DevTools. * Fixed the desktop app repeatedly entering GPU fallback mode on every restart and improved startup error reporting. * Fixed the desktop app hanging indefinitely on startup when the web interface failed to load. * Fixed the desktop app re-launching in a continuous loop after recovering from a GPU crash. * Fixed the desktop app failing to start when user data storage was inaccessible - it now starts with safe defaults instead. * Fixed the AI assistant getting stuck when a task required reading both a request and its response in the same step. * Fixed a crash that prevented adding or editing variables in environments with corrupted ordering data. * The app now shows a clear error message when it cannot save data because your disk is full, instead of failing silently. * Fixed deleted items occasionally reappearing in the sidebar after syncing. * Script execution now defaults to a sandboxed mode when the server cannot be reached on startup, instead of falling back to unrestricted access. * The Load Testing performance view now has a refresh button so you can reload the latest data without leaving and revisiting the page. **v2608.25.1** Aug 25, 2026 ### 🚀 New * You can now set a Content-Type on individual form-data fields, letting you mix JSON metadata and file parts in a single request - Postman collections that use per-field types also import without data loss. * Right-clicking a selection in the response body gives you a Set as variable option, so you can save a response value directly to a variable without opening the script editor. * The GraphQL editor now has a Schema tab where you can load a schema from introspection, a URL, or a local file to power query autocompletion. * The Collection Runner now has a Performance tab for starting and reviewing BrowserStack load tests against your collection's requests. ### ✨ Improvements * App Settings gains an About section with version and system info, a toggle to automatically attach a no-cache header to HTTP and GraphQL requests, and now remembers which settings section you last visited within the session. * The Scripts tab now shows Safe, Developer, and Default execution mode options per collection and per request on all current desktop builds, with no extra setup required. * Script execution in Developer mode is now 4.4 times faster, bringing it to parity with Postman's script runner on the same test workload. * Attempting to import a collection that exceeds the size limit now shows the actual converted size and the limit, instead of a generic error - retrying the same file will not help, and the message says so. * Pasting a malformed cURL command now shows a specific reason, such as an unclosed quote or a missing line-continuation backslash, rather than a generic parse error. ### 🐛 Fixes * Cookies scoped to a parent domain are now correctly sent when making requests to subdomains, fixing sessions that were captured but then silently dropped on every request. * Alert banners that have no dismiss action no longer show a close button that does nothing when clicked. * On a local file-system project, saving or renaming a request with characters not allowed by your file system now shows the exact reason instead of silently failing, and the rename input blocks invalid names before you can confirm. * Sending requests from a local file-system project on desktop no longer fails silently due to a file-system bridge error that occurred since the bulk-read compatibility feature became available. **v2608.21.1** Aug 21, 2026 ### 🐛 Fixes * System proxy support now correctly uses the proxy's own scheme (HTTPS proxies connect over TLS instead of plaintext), raises an explicit error for SOCKS proxies rather than silently bypassing them, and logs a reason when the system proxy resolves to nothing. * Importing a Postman collection that contains a folder or request with no name no longer fails - those records are given a default name and the import completes. * Clicking '+ Add More' in the request headers or query parameters table no longer marks your request as unsaved until you actually type something into the new row. * The project-switching overlay now correctly shows the name of the project you are switching to, not the project you are leaving. * The AI assistant no longer hangs permanently when a single response requires reading multiple things at once - all parallel lookups are now resolved together before the reply continues. **v2608.20.1** Aug 20, 2026 ### 🐛 Fixes * Requests whose body uses a variable immediately followed by a closing brace (such as `{ "id": {{userId}}}`) no longer fail with a template parse error before sending. * Intentionally blank auth credential values (API key, Bearer token, or Basic auth) are now forwarded to the server instead of being blocked with a client-side error, so you can test how your server responds to missing credentials. * Responses with a Content-Encoding header but no body (such as a 204) no longer produce a false "Failed to decompress response body" error and now display correctly. * When a configured proxy hostname cannot be resolved, the error now identifies the proxy as the source of the failure instead of showing an unfamiliar hostname you did not type in the URL bar. * The Certificates and Proxy settings pages are now always accessible regardless of your chosen execution target, and requests that require a client certificate now show a clear explanation when run via Cloud Agent instead of failing with a generic handshake error. **v2608.19.1** Aug 18, 2026 ### 🚀 New * You can now check for updates on demand from the app menu on macOS or the Help menu on Windows and Linux, and see a confirmation when your app is already on the latest version. * Each mock in Mock Server now has a Logs tab showing every incoming request, with filters for status, match result, and time range, plus request and response details on expand. * A new Resources page under Organization in Settings lets admins view and manage policies for their organization. * Admins can now set an allow or deny policy for external packages from the Organization Resources settings page, controlling which npm packages members can install and use in scripts. * When your organization restricts scripts to Safe mode, the mode control now shows the restriction with an explanation rather than appearing available and failing silently when you try to switch. ### ✨ Improvements * The desktop app now detects and downloads new releases while it is running, so a version published while you are working appears as a restart prompt without requiring you to relaunch first. * Your organization's package policy is now enforced at install time and when scripts run, with a message that names the blocked package and attributes the restriction to your organization. * Running a collection with the CLI in Developer mode now requires you to be signed in, so your organization's script execution policy applies in CI and other automated contexts. ### 🐛 Fixes * The cloud connection icon in the agent picker now accurately reflects whether your cloud connection is healthy rather than always appearing as unchecked. * The AI assistant no longer retries indefinitely when asked to send a GraphQL request that has no query, and now offers to save your work rather than directing you to a keyboard shortcut. * Custom packages that use ES module import syntax for external libraries now prepare correctly and respect the organization package policy, instead of silently bundling the library or failing to build. **v2608.17.1** Aug 14, 2026 ### 🚀 New * The chat assistant can now send a request on your behalf and read its response, so you can ask it to run a request and explain what came back. ### ✨ Improvements * Console log entries now show whether they came from your pre-request or post-response script, making it easy to tell which script produced a given line when both phases log to the same panel. ### 🐛 Fixes * `setTimeout` and `setInterval` in pre-request and post-response scripts now work correctly in all scripting modes - previously they resolved immediately or did nothing in Safe script mode. * Fixed multiple controls in the web app that appeared interactive but silently discarded your input, including the Developer script mode toggle, multipart file attachment picker, and per-protocol settings; `rq.cookies` access in web scripts is also restored. * The Scheduled Runs list now shows a Retry button when it fails to load, so you no longer need to close and reopen the collection tab to recover. * Importing a collection no longer fails in environments where corporate security tools block background browser workers - the app now falls back to parsing automatically so imports complete as expected. **v2608.14.1** Aug 13, 2026 ### 🚀 New * You can now route requests through a cloud-hosted static IP, making it possible to test APIs that restrict access by IP address without changing your local network or firewall configuration. * OAuth 2.0 works in the web app across all grant types, including authorization code, PKCE, client credentials, password, and implicit flow. * You can now run a full collection in the web app, with support for iterations, delays, data files, and error-handling modes. * Digest authentication is now supported when sending requests through the cloud path. ### ✨ Improvements * Cloud requests now follow redirects and respect per-request settings such as timeout and SSL verification, matching the behavior you get on local requests. * App settings are now editable in the web app, letting you configure script timeouts, SSL verification, and protocol defaults without the desktop app. * Desktop app updates now download only the portions of the package that changed, reducing typical update download sizes by around 60-70%. ### 🐛 Fixes * Creating or importing requests that contain null characters in their content no longer fails with a validation error. * The `to.have.header(name, value)` assertion in test scripts now correctly validates the header value in all scripting environments, not just the header's presence. * Disabled variables no longer appear inside scripts, so toggling a variable off now takes effect consistently regardless of which scripting mode is active. * Scripts attached to incoming gRPC messages now execute correctly, fixing a bug where they appeared to do nothing after any live data update. * The app now starts correctly when it finds saved data in an unexpected format from a previous version, rather than showing an error screen on the first launch after upgrading. **v2608.12.1** Aug 12, 2026 ### 🚀 New * The AI chat assistant can now write test scripts for your requests and save the changes directly, without leaving the chat. ### 🐛 Fixes * Renaming a collection variable's key no longer causes a server error. * Several gRPC fixes: pasting a grpcurl command now imports correctly, timeout errors show the configured duration, and setting a timeout to 0 resets to the transport default instead of failing immediately. * Importing cURL commands copied from Windows Command Prompt, PowerShell, and other tools now works correctly, including commands with curly quotes that previously imported a broken URL without warning. * Request failures now show the correct error message and are properly recorded in History and DevTools, instead of showing a misleading 'Check the URL' prompt. **v2608.11.1** Aug 11, 2026 ### 🐛 Fixes * Setting Request Timeout to No limit now truly removes the timeout cap, so long-running requests no longer fail unexpectedly after 5 minutes. * Variable names containing special characters such as parentheses, dots, or spaces now resolve correctly in request templates, and errors caused by a bad variable name no longer appear as pre-request script failures. **v2608.10.1** Aug 7, 2026 ### 🚀 New * The DevConsole now includes log-level filters (Log, Info, Warning, Error), a timestamps toggle, copy-all and per-entry copy buttons for both the Console and Network panels, and a per-entry toggle to switch between the formatted view and the raw HTTP wire log. * You can now mark a cloud mock as Private, which generates a secret token that callers must include in requests to access it - the mock URL stays the same, but requests without the token receive a 404. ### 🐛 Fixes * Connection errors such as DNS lookup failures or TLS handshake issues now appear in the DevConsole by default, so you no longer need to manually enable network sources to find out why a request failed. * Collection runs using OAuth 2.0 now correctly carry variable values set by pre-request scripts from one request to the next, so you no longer need to run a collection multiple times for earlier script outputs to reach later requests. * Typing in the middle of a variable name field no longer jumps the cursor to the end on every keystroke, making existing variable names editable as expected. * The 'Use system proxy' setting now correctly routes requests through your OS-configured proxy when 'Use environment variables' is also enabled, fixing an issue that caused requests to bypass corporate proxies silently. **v2608.6.2** Aug 6, 2026 ### 🚀 New * You can now use `xml2Json` as a bare global in request scripts to parse XML responses, matching the scripting environment you may know from Postman. * You can now write an On Message script for gRPC server-streaming and bidirectional calls - the script runs once per received message and its assertions appear individually in the collection runner. * You can now import a gRPC request by pasting a grpcurl command, the same way HTTP requests can be imported from a cURL command. ### 🐛 Fixes * gRPC server reflection now uses the authentication credentials you have configured on the request, so reflection works correctly against servers that require auth. **v2608.6.1** Aug 6, 2026 ### 🚀 New * Your pre- and post-request scripts now have access to CryptoJS (crypto-js) as a built-in global, with no require call needed. * Lodash is now available as \_ in your pre- and post-request scripts without requiring it first. * Importing an OpenAPI spec now lets you create both a collection and a mock server in one step. * When you save a request example, its endpoint is now automatically added as a route in your mock server. ### ✨ Improvements * You can now reach App Settings from a dedicated button that is always visible in the header, without needing to open a menu. * When importing a Postman collection that contains some malformed entries, Requestly now imports everything it can parse and shows you a list of items that were skipped, instead of rejecting the whole file. * cURL imports now correctly handle digest and NTLM auth, multipart form data, and no longer include curl's automatic Accept and User-Agent headers in your imported request. * Duplicating a request now copies its advanced settings alongside it, and WebSocket and Socket.IO handshake header values now support variable and vault references. * The Visualize button now shows a highlighted state when the visualization panel is open, so you can tell at a glance whether it is active. * The desktop app now keeps its theme in sync with your OS color scheme, so system dark and light mode preferences are reflected consistently across the app. ### 🐛 Fixes * Importing a large local project no longer fails silently with no error or progress shown. * gRPC requests on desktop now respect your OS certificate store, and disabling TLS verification correctly skips the full certificate chain check. * Calling rq.visualizer.clear() in a post-response script now correctly clears any visualization that a pre-request script set. * The desktop app now recovers automatically if the main window fails to load at startup, instead of appearing stuck. * Visualizations now render with the correct colors for your current light or dark theme. * Saving a request on Windows with OneDrive-synchronized project folders no longer fails with a directory error. * The AI assistant no longer repeats the same lookup in a loop when you ask a question from a collection tab. **v2608.5.1** Aug 4, 2026 ### 🚀 New * You can now generate a cloud mock server from any collection in one click - every request becomes a route and each saved example becomes a served response. * Scripts can now use `rq.visualizer.set()` in pre-request scripts, and `rq.response.stream` gives you the raw response body as a Buffer for reading binary data, both matching Postman behavior. * When you upload a file using the wrong importer, the app now detects the actual format and lets you switch to the correct importer in one click without re-uploading the file. ### ✨ Improvements * Import warnings are now shown only on the result step and grouped by type, so each kind of issue appears once instead of repeating across multiple steps. * The scheduled run creation form no longer shows a pre-flight run count estimate, keeping the configuration focused on just the schedule settings. ### 🐛 Fixes * Fixed an issue where scripts using `rq.sendRequest` or `fetch` would silently drop query strings, ignore your proxy and SSL settings, and return corrupted binary response bodies. * Fixed three issues: exporting an environment with secret values now prompts for confirmation before downloading, a single over-long name no longer causes an entire Postman collection import to fail, and saving collection-scoped variables from example tabs now works correctly. * When an import fails to save, you now see the actual HTTP status code and server response details instead of a generic 'Unknown error' message. * The AI assistant now shows a specific error message based on what went wrong, instead of a single generic failure notice. * Fixed the AI assistant's chat input so that Enter sends your message and Mod+Enter inserts a new line. * The AI assistant now shows a loading indicator when you switch to a conversation thread that is still loading its messages. * Fixed an issue where the AI assistant could get stuck if a tool action was interrupted mid-session. **v2607.31.1** Jul 31, 2026 ### ✨ Improvements * The desktop app now installs custom script packages through a safer channel, closing a potential security gap without changing how packages work. * The AI chat assistant now limits messages to 10,000 characters and shows a clear message when you send requests too quickly. * When a project search finds no results, the message now names which team and local projects were searched, so you know exactly where to look. ### 🐛 Fixes * Single-team accounts now appear correctly in the team switcher, and team memberships are cleaned up when a user is removed from a team. **v2607.30.4** Jul 30, 2026 ### 🐛 Fixes * Fixed a bug where the embedded terminal could show ghost tabs or connection errors on recently released desktop versions. * Fixed an issue where importing certain valid OpenAPI specifications would fail; the importer now succeeds on any spec that passes initial parsing, extracting what it recognizes rather than rejecting the whole file. **v2607.30.3** Jul 30, 2026 ### 🚀 New * You can now render a custom HTML visualization of response data by calling `rq.visualizer.set(template, data)` in a post-response script, then selecting Visualize in the response panel. Use `Mod+Shift+Enter` to send and visualize in one step. ### ✨ Improvements * The Sharing tab now displays a note clarifying exactly what your documentation share links include (read-only docs) and exclude (scripts and auth), so you know what recipients will see before you share. **v2607.30.2** Jul 30, 2026 ### 🐛 Fixes * The desktop app now blocks secondary listeners from attaching to the background bridge, closing a gap where injected scripts could silently read all background service traffic, including stored secrets and credentials. * Deleting all requests from a collection while the runner is open now correctly shows the empty state and disables the Run button instead of displaying stale entries from the deleted requests. **v2607.30.1** Jul 30, 2026 ### 🐛 Fixes * Importing a collection exported from the old Requestly app no longer rejects the entire file when individual requests are missing header or auth fields - valid requests are imported and any unrecoverable ones are reported by name. * Script `rq.sendRequest` calls on desktop now honor your system certificate store, custom CA certificates, SSL verification toggle, and proxy settings, fixing silent failures on corporate or TLS-intercepting networks. * Starting to rename a chat history thread and then dismissing the popover without saving no longer leaves that thread stuck in its rename input the next time you open chat history. * Pressing the save shortcut immediately after editing a request body, query parameters, or script field now reliably saves your latest content instead of silently reverting to the previous value. * Changing a query parameter's type annotation (for example from "string" to "integer") is now saved correctly and no longer reverts to the original type on reload. * Running the Requestly CLI on Windows no longer fails with a JSON parse error caused by an incorrectly formatted internal build file. **v2607.29.2** Jul 29, 2026 ### 🐛 Fixes * The desktop terminal now supports multiple tabs again, restoring the ability to run separate terminal sessions side by side. **v2607.29.1** Jul 29, 2026 ### 🐛 Fixes * When you restore a tab for a request, collection, or environment that was deleted on another device or by a teammate, you now see a clear not-found message with a Close tab button instead of an infinite loading spinner. **v2607.28.1** Jul 27, 2026 ### 🐛 Fixes * Scripts using `rq.sendRequest` with a callback now correctly wait for the callback to complete, so environment variables set inside the callback are applied and test assertions run as expected. **v2607.27.1** Jul 27, 2026 ### 🐛 Fixes * You can now import OpenAPI specs that previously failed due to non-standard but commonly produced field formats, such as boolean required fields or shorthand type strings generated by real conversion tools. * The desktop app no longer freezes or becomes unresponsive when you open or create a local project with a large amount of saved data. * The CLI no longer crashes on startup when running under Node 18, restoring all commands including collection run. * The scheduled run form no longer shows requests from a previously viewed collection when you open it in a different collection. * Sending a request immediately after editing the body now correctly uses your latest edits instead of the version saved a moment before. **v2607.23.1** Jul 23, 2026 ### 🚀 New * The AI Assistant now has an auto mode that skips individual approval prompts for tool actions; you can toggle it with Shift+Tab or by clicking the status indicator in the chat panel. * You can now open the AI Assistant directly from the app footer. * A read-only keyboard shortcuts reference overlay is back, showing all your shortcuts at a glance. ### ✨ Improvements * Scheduled Runs now shows an Active/Paused badge on each schedule in the list, lets you search run history by run ID, and opens the Tests tab first when a run finishes with failures. * The request Settings tab now shows an indicator dot when you have active overrides, offers an inline retry button when a request fails due to an SSL or parsing error, and displays a settings summary in the collection runner before you start a run. * Your desktop login session is now encrypted when stored on disk, so it cannot be read if someone accesses your local files. * For teams using TestHub, member and access management is now under Project Settings in a Members and access section and opens in your system browser. ### 🐛 Fixes * The auto-generated Content-Type header is no longer added when you have already set one explicitly on the request. * Saving a request as new now carries over the description and clears leftover data from body tabs you are not actively using; requests skipped by a pre-request script now show a dedicated skipped panel instead of a blank response. * Variable names are now trimmed of surrounding whitespace when you save them. * Editing the URL bar no longer duplicates existing query parameters; matching parameters are now updated in place. * MQTT connections now work when the broker URL is a single variable placeholder such as . * Message editors in WebSocket and Socket.IO requests now scroll correctly when working with large payloads. * The AI Assistant panel no longer flickers or reloads your conversation when you close and reopen it. * The duplicate variable name warning now correctly treats names that differ only by letter case as distinct. * Cmd/Ctrl+0 (Reset Zoom) is now correctly treated as a reserved shortcut and cannot be rebound in keyboard settings. * The Git panel now shows the correct branch name on empty repositories, auto-fetches in the background to keep the behind counter accurate, and hides the Push button until the repository has at least one commit. * Importing an OpenAPI collection no longer fails on long example names, and validation errors now include the field names needed to identify the problem. **v2607.21.1** Jul 21, 2026 ### ✨ Improvements * The desktop app's initial load is now up to 76% smaller on the wire, making startup noticeably faster. * Scheduled run results now show the actual headers that were sent, including values resolved by pre-request scripts and auth, instead of unresolved template placeholders. ### 🐛 Fixes * Collapsing and re-expanding the sidebar no longer resets your open editors, response panels, or tab state. * In scripts, setting a variable to null or undefined now clears it instead of storing the literal string, matching Postman's behavior. * The light, dark, and system theme options now work correctly on the sign-in screen. * Pressing Cmd+F (or Ctrl+F) while editing in the request body or a scripts editor no longer steals focus to the sidebar search. **v2607.20.1** Jul 19, 2026 ### 🚀 New * The AI assistant can now read and edit your requests, collections, and environments - when it suggests a change, you see an inline diff to accept or reject before anything is saved. ### 🐛 Fixes * Fixed several WebSocket and Socket.IO reliability issues, including a freeze when receiving large payloads, query params no longer syncing with the URL bar, vague connection failure messages, and a missing Cancel button during connection. **v2607.17.1** Jul 17, 2026 ### 🚀 New * Signing up is now required to use the app, and the onboarding experience has been redesigned to guide you through initial setup more clearly. * You can now switch between your teams directly from within the app using the new in-product team switcher. * A new Scheduled Runs tab in the Collection Runner lets you discover and manage scheduled runs per collection alongside a Manual run sub-tab. * You can now create and configure scheduled runs directly from the app, with settings for schedule frequency, retry policy, and request selection. * Scheduled runs now include a history list showing past executions and a drill-down view with per-request results. * You can pause, resume, delete, or immediately trigger a scheduled run directly from the run list. * A re-run button lets you re-execute a previous scheduled run, and an inline config pane lets you adjust settings without navigating away. * Scheduled runs can now automatically retry failed requests based on a configurable retry policy and attempt limit. * The scheduled run detail view now shows per-request results in a two-pane layout with headers, payload, response, and test tabs, and the create form has been reorganized with clearer sections. * Scheduled run results are automatically uploaded to BrowserStack Test Hub for centralized test tracking. * Each `rq.test` assertion in a scheduled collection run now appears as its own result in BrowserStack Test Hub instead of being grouped under a single request. * You can now export and import scheduled run configurations using the REST API or the CLI. * You can now manage scheduled runs from the command line using the new `rq scheduled-run` subcommands. * When publishing a release in API Design, the version is now automatically derived from the `info.version` field in your OpenAPI spec. ### ✨ Improvements * The team-switching overlay has been polished and is now hidden when you are working in a local project. * Vault access from scripts is now disabled by default and can be re-enabled from the Vault settings page. * Import warnings are now cleaner, with redundant low-value notices removed and the remaining ones made more actionable. * In-progress scheduled runs now appear in the run history, and runs are ordered by when they actually ran rather than when they were created. * Realtime and gRPC requests are now excluded from scheduled run request selection, preventing unsupported configurations from being saved. ### 🐛 Fixes * A tooltip was covering the create-project button in the project switcher settings area, making it impossible to click. * Switching the body type in an HTTP request no longer leaves behind stale values from the previous type. * OpenAPI collections with XML request bodies now import correctly with the proper content type applied. * The collection runner now correctly records and displays results from WebSocket, Socket.IO, and gRPC requests. * Clicking 'Try it' on an example multiple times in quick succession no longer opens duplicate draft tabs. * Adding a request to a scheduled run and saving it now works correctly, and the run detail view no longer renders broken components. **v2607.15.1** Jul 15, 2026 ### 🐛 Fixes * The sidebar toggle button now correctly reports its open or closed state to screen readers and other assistive technologies. * The array variable type now only appears in the type picker when your installed desktop version supports it, preventing silent data corruption when scripts read or write array variables on older builds. **v2607.14.1** Jul 14, 2026 ### 🚀 New * You can now choose how a response body is displayed using the new format selector in the response toolbar, with options for JSON, XML, HTML, YAML, JavaScript, Markdown, Raw, Hex, and Base64. * Variables now support an array data type, so scripts can store and retrieve real arrays with `.first()` and `.last()` instead of having them flattened to comma-joined strings. ### ✨ Improvements * The API Docs publishing flow now shows Copy link and View actions in the success toast, the empty-state primary button highlights the most useful next step, and the Components Library in the API Design sidebar is collapsed by default. ### 🐛 Fixes * Secret vault references in OAuth 2.0 and JWT Bearer auth fields now resolve correctly when sending requests, instead of being passed as literal template strings to the token endpoint. * The Run via CLI command generated by the collection runner now uses the environment name instead of its internal ID for local projects, so the copied command works when you run it. * Keyboard shortcuts rebound to punctuation keys such as semicolons, periods, slashes, and brackets now fire correctly after being configured in the desktop app's shortcut settings. * A security vulnerability in the desktop app's git integration has been patched, and remote URLs are now validated to allow only standard schemes such as https, http, and ssh. **v2607.13.1** Jul 12, 2026 ### 🚀 New * You can now collapse the Collections sidebar to give your request editor more room, and restore it with a click or Cmd/Ctrl+B. * A new Keyboard Shortcuts page in Settings on desktop lets you view all available shortcuts, reassign any of them directly in the list, and reset everything to defaults. ### ✨ Improvements * Script errors in pre- and post-request scripts now show line numbers and column positions in the Response panel, DevTools console, and Collection Runner, so you can pinpoint mistakes faster. ### 🐛 Fixes * Changing a team member's role no longer fails with an error when the member has been invited but has not yet logged in. **v2607.10.1** Jul 10, 2026 ### 🚀 New * You can now delete all variables at once from the Environment, Global, and Collection variable tables using the new Delete All button, which asks for confirmation before clearing. * Users who are not signed in now see a notification banner with a Sign in option, giving advance notice that a free account will soon be required. ### ✨ Improvements * When a mandatory update is detected while the desktop app is running, the download now starts automatically so you can install it without any extra steps. ### 🐛 Fixes * Fixed a bug where the Clone repository modal immediately closed after clicking Clone from the project switcher. * The collection runner now executes requests in the same order they appear in the sidebar, including reorders made by dragging. * Fixed a regression on desktop where the sign-in notification banner remained visible after logging in. * Fixed the embedded terminal on desktop appearing as a blank panel, so it now correctly renders text using the app's current light or dark theme. * Fixed Quick Share links returning errors for visitors - shared links now load reliably. * Fixed three Postman scripting issues: skipped tests no longer silently discard their function body, response body assertions now require an exact match instead of a substring match, and false warnings about unsupported Postman APIs have been removed. * Fixed the desktop auto-update getting stuck on an error state after a download completed, by adding a verification step between download and success. **v2607.8.2** Jul 8, 2026 ### 🐛 Fixes * Requests with an empty body no longer send a spurious Content-Type header, preventing failures on servers that reject unexpected content types. **v2607.8.1** Jul 8, 2026 ### 🐛 Fixes * Deleted specs, components, and linked specs in API Design no longer reappear in the sidebar after a page reload. * Using 'Save as new' on an HTTP or GraphQL request now carries all Settings overrides, including SSL verification, redirect policy, and timeout, over to the duplicate. * Pre-request scripts that call rq.collectionVariables.set(), unset(), or clear() on a standalone request no longer abort the send with an error - the call is silently skipped and the request proceeds normally. * Collection variables defined on a parent or ancestor folder are now visible to pre-request and post-response scripts, matching what you already see in the URL and header preview. * Importing Postman collections now correctly infers the raw body content type from the Content-Type header when Postman's format hint is missing, and the Body tab shows a warning when your selected body language and Content-Type header disagree. **v2607.7.1** Jul 7, 2026 ### 🚀 New * You can now sign in to your Git provider with an OAuth device-code flow, in addition to a personal access token. ### ✨ Improvements * The API Client sidebar now shows a Git status indicator for Git-backed projects. * Improved keyboard navigation across the app. * Extended the scripting API with `rq.response.headers` accessors, and brought Safe-mode scripts to parity for `rq.response.to.have.jsonSchema` and the JSON body helpers. ### 🐛 Fixes * Example "Try it" now resolves collection-level variables. * Collection variable default values are now applied when exporting a collection to OpenAPI. * Older Requestly exports that omitted query parameters, headers, or enabled flags now import correctly. * Fixed an error when using "Go to source" after the source specification had been deleted. * AI requests are now rate-limited per user to keep the service responsive. **v2607.6.1** Jul 6, 2026 ### 🚀 New * You can now create private, scoped share links for a single endpoint or folder in your published API docs, with optional password protection and an expiry, and revoke them at any time. * You can now connect a GitLab account with a personal access token for Git-backed projects. ### ✨ Improvements * Large collection trees that span multiple projects now scroll smoothly. ### 🐛 Fixes * Fixed a freeze in single-line fields when a value containing line breaks was entered. * Fixed Requestly-format imports that could fail to save, and the app now shows the actual reason when an import fails. * Generated code snippets now render multipart file fields as file uploads. * Fixed local projects occasionally reporting data as corrupted after a transient read failure; these reads are now retried. * AI features now redact request and response bodies before any data leaves your machine for quality evaluation. **v2607.2.1** Jul 2, 2026 ### 🚀 New * You can now right-click items in the sidebar tree and open tabs to rename, duplicate, delete, and run other actions from a context menu. * You can now copy, cut, and paste requests and folders, within a collection or across collections, using the right-click menu and the usual keyboard shortcuts. * You can now add descriptions to requests and examples across every protocol, and they render in your published API docs. ### ✨ Improvements * The request history list now loads and scrolls smoothly even with thousands of entries, and history search no longer stutters as you type. * The Collection Runner and large request lists feel more responsive thanks to reduced re-rendering. ### 🐛 Fixes * The desktop app now opens external links only over secure HTTPS connections and restricts in-app navigation to trusted origins, protecting you against malicious links. * Desktop vault files are now readable only by their owner, so your stored secrets stay private on shared machines. * Fixed a freeze in the API specification editor caused by an infinite render loop in the governance flow. * The desktop terminal now closes its sessions when you delete a project, and new terminal sessions are limited to local projects. * Fixed a server-side issue where saving role or permission changes at the same time could fail. * Added safeguards that limit the number of concurrent import tasks per user and project, keeping imports reliable under load. **v2606.30.2** Jun 30, 2026 ### 🚀 New * When importing an OpenAPI file, you can now choose to create a collection, an API specification, or both together in a single step. ### 🐛 Fixes * On Windows, the sign-in dialog now stays open and offers a "Copy the URL" option when your default browser fails to launch, so you can complete the login without getting stuck. * Pasting a cURL command whose URL contains unencoded spaces now imports correctly instead of being rejected. * Importing a Postman collection now correctly preserves query parameters defined in request examples. * Signing up with an email and password now requires at least 8 characters, preventing accounts with weak credentials from being created. * Adding a new route in the Mock Server now automatically selects it so you can start editing immediately, and the rule row controls are visually aligned. **v2606.30.1** Jun 30, 2026 ### 🚀 New * If your organization is subject to data-residency restrictions, you now see a clear compliance notice on sign-in with a sign-out option, instead of hitting an unexpected error. ### 🐛 Fixes * Importing a Postman data-export ZIP no longer shows a false error for the archive metadata file bundled by Postman, and imports that finish with warnings now display a 'What needs attention' summary instead of a generic success message. * Fixed a server-side issue that caused login failures and widespread errors when multiple users signed in at the same time. **v2606.29.2** Jun 29, 2026 ### 🚀 New * You can now click 'View changelog' in the desktop update notification to read what changed before restarting to install the update. ### 🐛 Fixes * Fixed security issues in the desktop vault where a crash during startup could erase your stored secrets, vault folders were readable by other users on shared machines, and crafted symbolic links could affect files outside the vault. * When adding a team member or resending an invitation fails, you now see the specific reason from the server instead of a generic error message. * Fixed a bug in the desktop terminal where commands installed via login-profile tools (such as Homebrew, nvm, or Volta) were not found, and fixed a separate issue where the cursor would jump unexpectedly when resizing the terminal panel. * Fixed an error that prevented 'Update Collections' from applying content changes when syncing a collection from an API specification. **v2606.29.1** Jun 29, 2026 ### 🚀 New * You can now open an embedded terminal in the Dev Tools panel of the desktop app, with support for multiple concurrent sessions in tabs. * Each operation in the published API docs reader now has its own shareable URL, so you can link teammates directly to a specific endpoint. ### ✨ Improvements * Press Mod+K while viewing published API docs to jump straight to the outline search field. * Published API docs now render oneOf and anyOf schema compositions with clearly labeled sections, making complex request and response shapes easier to read. * Schema property descriptions in published API docs now render markdown formatting, so code snippets, bold text, and links display as intended instead of as raw markup. * Published API docs now correctly display response headers and link sections, and resolve schemas that are defined at the top level of your spec. ### 🐛 Fixes * Proxy settings now show a clear validation error for out-of-range port numbers, automatically remove any http\:// or https\:// prefix you type in the host field, and require both username and password when authentication is turned on. * Fixed an issue where triggering a scheduled run returned a permissions error immediately after signing in. **v2606.26.1** Jun 26, 2026 ### ✨ Improvements * Collection imports now show a real progress bar with live status instead of a bare spinner. * Invalid project names are now flagged with a clear message before you create or rename a project, instead of failing afterward. * Legacy Postman scripts that use deprecated variables now keep working in the default safe sandbox, with a deprecation warning instead of a silent error. * In published API docs, the outline now highlights and follows the section you are reading as you scroll. ### 🐛 Fixes * Markdown editing is now readable in light mode, with syntax markers that match your theme. **v2606.25.1** Jun 25, 2026 ### ✨ Improvements * Published docs render OpenAPI schemas more faithfully. ### 🐛 Fixes * You can now unstage files in a brand-new repository that has no commits yet. **v2606.24.2** Jun 24, 2026 ### 🚀 New * View specs from multiple projects together in the Specs sidebar. ### ✨ Improvements * Published docs now group endpoints by tag for easier navigation. ### 🐛 Fixes * Viewer-role users no longer see create and edit actions they cannot perform. * GraphQL request variables now keep their typed values intact when saved. **v2606.23.1** Jun 23, 2026 ### 🚀 New * Scripts gain a full request-execution namespace with setNextRequest, skipRequest, runRequest, and location. * Scripts can now clear request headers for Postman parity. * Scripts can now clear environment, global, and collection variables for Postman parity. * Bulk-delete mock routes by path prefix. ### ✨ Improvements * The API Design versions pane now shows documentation status and has a collapsible header. * The Specs and Components sidebar is now collapsible and resizable. **v2606.22.2** Jun 22, 2026 ### 🚀 New * Configure proxy settings in the desktop app. * Run a collection from the command line with a new Run via CLI option on the Collection Runner. * Copy a request's ID with a new Copy Request ID button in every protocol editor. ### 🐛 Fixes * Fixed the URL field freezing when you switch tabs quickly. * Fixed collection variables being incorrectly read-only in safe mode. **v2606.19.3** Jun 19, 2026 ### 🚀 New * Request capture now follows redirect hops and handles Digest/NTLM challenges and GraphQL introspection. * Create multiple mock routes at once, including their nested responses and rules. * Stash your Git changes from a new stash view, with indicators shown across the app. ### ✨ Improvements * Scripts can now modify request headers in both scripting engines. * The Git sidebar panel is tidier with collapsible sections, a change-count badge, and clearer error messages. ### 🐛 Fixes * Importing a partial Requestly export now re-parents orphaned items so nothing goes missing. **v2606.18.2** Jun 18, 2026 ### 🚀 New * Cloning a repository now discovers and sets up any Requestly project it contains automatically. * Resolve merge conflicts with a new two-way conflict resolution view. ### ✨ Improvements * Scripts now run on a faster, more reliable safe-mode engine, including full support on Windows. ### 🐛 Fixes * Fixed duplicate key-value row identifiers that could appear when loading a request. * Fixed a false Body-tab indicator dot and corrected the skipped-request count in Run History. **v2606.17.2** Jun 17, 2026 ### 🚀 New * DevTools now captures OAuth token fetches that the app makes on your behalf. * A new Git Providers settings page lets you connect accounts, and you can enter or update a personal access token mid-operation when authentication is needed. * Create, switch, and pick Git branches directly from a branch picker. * Browse and select GitHub repositories from a built-in repo picker. ### ✨ Improvements * Search your projects and see them sorted alphabetically. **v2606.16.2** Jun 16, 2026 ### 🚀 New * You can now publish collection documentation and share it via a public reader page with public, internal, or password access. ### ✨ Improvements * Scripts now show a deprecation warning when using old Postman-style identifiers. ### 🐛 Fixes * Fixed four API client bugs across request and collection workflows. * Fixed JSONPath navigation for bracketed keys and a missing duplicate-example notification. * Local file moves now report all naming conflicts instead of failing silently. **v2606.15.4** Jun 15, 2026 ### 🚀 New * You can now download a response body directly to a file. * Added Postman-like JSONPath filtering to the response Pretty view. * Added a line-wrap toggle to the JSON Pretty view in the response viewer. ### 🐛 Fixes * JWT auth now shows the signed preview token in auto-generated headers and query params. * Long lists such as projects, mocks, and specifications now load every page instead of stopping short. * Fixed key-value rows that could share an id and behave incorrectly. **v2606.11.3** Jun 11, 2026 ### 🚀 New * Binary response bodies are now preserved losslessly, with image previews in the response viewer. * Added a Commits view with a commit-graph rail for Git-backed projects. ### 🐛 Fixes * OAuth2 now shows the fetched token in the panel and the auto-generated Authorization header. * Fixed several MQTT issues including auth on connect, a tab-close leak, and publishing with embedded variables. **v2606.10.1** Jun 10, 2026 ### 🚀 New * Added App Settings rows to configure eight default behaviors for HTTP and GraphQL requests. * Added rq.sendRequest in scripts for parity with Postman's pm.sendRequest. * Added several quality-of-life improvements to the WebSocket and Socket.IO editors. ### ✨ Improvements * Importers now show clearer, more accurate reasons when an import fails. ### 🐛 Fixes * Imports no longer fail on partial legacy auth objects, placeholder cookies, or null key names. * Fixed drag-and-drop reordering of collections reverting when items had tied ranks. **v2606.5.1** Jun 5, 2026 ### ✨ Improvements * Hardened sign-in and mock server handling against abuse. ### 🐛 Fixes * Duplicate request headers that differ only in letter case are now collapsed correctly. **v2606.4.2** Jun 4, 2026 ### 🚀 New * The Tests tab now shows how many tests passed out of the total, with pass and fail color coding. ### ✨ Improvements * Projects now open faster by deferring background data loading until it is actually needed. ### 🐛 Fixes * Fixed several desktop app crashes during startup, shell loading, and when a config file was corrupt. * Re-imported global variables now correctly merge instead of losing their global scope. * Searching collections now shows a clear empty state when no results match. **v2606.3.1** Jun 3, 2026 ### ✨ Improvements * You now get a success toast when switching environments. * The active history entry is now highlighted and its font matches collections. * Template variables are now highlighted in HTTP and GraphQL examples. * MQTT expanded timeline messages now show the retain flag. ### 🐛 Fixes * GraphQL variables editor now accepts template tokens. * Switching an MQTT request from v5 to v3 now correctly removes the Properties tab from the URL. **v2606.2.2** Jun 2, 2026 ### 🚀 New * HTTP and GraphQL requests now have a per-request Settings tab with values that can inherit from parent levels. * Manage reusable message-body templates in a dedicated Message Templates library. ### 🐛 Fixes * Fixed sending GET requests with a body over HTTP/2. * Switching authorization type now correctly drops stale fields from the previous type. * The Vault now surfaces the real reason when an operation fails. * The WSDL import button now enables only when the URL matches a valid pattern as you type. **v2605.30.1** May 30, 2026 ### 🚀 New * Save and reuse WebSocket and Socket.IO examples. * gRPC proto file content now persists across sessions and syncs to the cloud. ### 🐛 Fixes * Fixed gRPC stream panel preview, trailer overflow, and reflection method reset issues. * Saving an HTTP, GraphQL, or gRPC request as new now keeps it in the right collection. * GraphQL Send is now blocked when the query body is empty. * URL-bar encoding is preserved when you toggle a query parameter on or off. **v2605.28.2** May 28, 2026 ### 🚀 New * Reuse saved message templates, beautify XML, and get clearer connection-state feedback in realtime clients. ### ✨ Improvements * Added a Skip link to onboarding. ### 🐛 Fixes * Discarding or saving variable edits no longer leaves phantom rows behind. * The authorization info banner now shows the correct text when an API key is placed in query params. * URL fragments are now stripped from query-parameter parsing so they no longer pollute your params. * Validation errors are now shown verbatim when saving, so you know exactly what went wrong. **v2605.27.1** May 27, 2026 ### 🚀 New * Build and send Socket.IO requests with a dedicated editor. * Import environment variables directly from a .env file. * Save and reuse MQTT examples on both cloud and local projects. * Import and export WebSocket and Socket.IO requests in Requestly's native format. ### 🐛 Fixes * XML responses now keep leaf elements inline for easier reading. * Scripts now preserve boolean and number types when reading values instead of converting them to strings. **v2605.26.1** May 26, 2026 ### 🚀 New * Connect a local project to Git directly inside the desktop app. * MQTT requests can now be imported and exported in Requestly's native format. ### ✨ Improvements * MQTT message timelines now display byte-probed formats and MQTT v5 properties more clearly. ### 🐛 Fixes * MQTT topic subscriptions stay stable and reconcile correctly when you reconnect. * The JSON editor no longer flags placeholders as syntax errors. * You can now select multiple files at once in the import drop zone. **v2605.25.1** May 25, 2026 ### 🚀 New * Added the WebSocket request editor with a live message timeline and connect/disconnect controls. * MQTT requests can now be saved to cloud and local projects. ### 🐛 Fixes * Collections now warn when you try to save an empty name in the overview editor. * Renaming an item now blocks saving and shows an error when the name is left empty. * gRPC error responses now preserve trailers and report the correct status. **v2605.22.1** May 22, 2026 ### 🚀 New * Added the MQTT request editor with message, topics, authorization, properties, and last will tabs. * Added a keyboard shortcuts modal you can open from the Help menu or with Cmd+/. ### ✨ Improvements * gRPC service discovery now supports importing a proto file. * gRPC requests now support pre and post scripts and per-protocol editor autocompletion. ### 🐛 Fixes * The collection runner now clamps out-of-range iteration and delay values and warns you. * Fixed Mock Server showing blank responses and rule errors after editing. **v2605.20.1** May 20, 2026 ### 🚀 New * Added the Mock Server with a sidebar, editor, and drag-to-reorder for routes. * You can now drag to reorder environment variables. ### ✨ Improvements * Expanded the gRPC client with a config panel, authentication, custom metadata, and message template generation. * Added grpcurl code generation for gRPC requests. * Response header details now collapse progressively to fit narrower panels. **v2605.19.1** May 19, 2026 ### 🚀 New * Added an MQTT client for connecting to brokers and publishing messages. ### ✨ Improvements * Exports to Postman and OpenAPI now carry over five additional authentication types. * gRPC requests now support saved examples, variable interpolation, and persistence. ### 🐛 Fixes * Inherited OAuth 2.0 authentication now resolves correctly and renders its config variables. * Fixed a Windows issue where renaming files in a local project produced broken paths. * Generated client code no longer percent-encodes your template variables incorrectly. **v2605.15.1** May 15, 2026 ### 🚀 New * Added AWS Signature v4 authentication with both live and presigned URL modes. * Added NTLM authentication support on the desktop app. ### ✨ Improvements * Added a report-issue entry to make it easier to send us feedback. ### 🐛 Fixes * Importing older Requestly exports now restores environment variables that were missing an identifier. * Empty or corrupt local project files no longer break loading. **v2605.14.2** May 14, 2026 ### 🚀 New * Added app-wide back and forward navigation buttons so you can move through screens you've visited. * Introduced the gRPC client with support for streaming requests. ### ✨ Improvements * Opening a specification tab for the first time is now faster. ### 🐛 Fixes * Creating a custom package with a duplicate name now shows a clear conflict message instead of a server error. * GraphQL responses that return HTML no longer crash response parsing. **v2605.13.1** May 13, 2026 ### 🚀 New * Send and inspect gRPC requests with the new gRPC support. ### ✨ Improvements * Environments are now sorted alphabetically in the selector. * Clearer drag-and-drop indicators when reordering collections. * Bottom panel dock preferences now persist across sessions. ### 🐛 Fixes * The app now reloads automatically instead of erroring after a new version is deployed. **v2605.12.2** May 12, 2026 ### 🚀 New * Added SSL certificate support, including client certificates and custom CA certificates. * Authenticate requests using HTTP Digest authentication. * Design and edit OpenAPI specifications with a dedicated editor, issues panel, and governance checks. **v2605.11.1** May 11, 2026 ### 🚀 New * The Requestly CLI now supports running cloud collections. * Added five new authentication types for securing your requests. * Authenticate requests using JWT Bearer tokens with configurable payload directives. ### ✨ Improvements * Collection trees now remember expansion state per project and added a collapse-all button. ### 🐛 Fixes * The desktop window can now be dragged while the app is loading. * Pasting a cURL command that is not a valid request no longer fails silently. **v2605.5.2** May 5, 2026 ### 🚀 New * The desktop app now downloads updates in the background with a progress bar. * Configure OAuth 2.0 and view the resulting token directly in the Authorization tab. ### 🐛 Fixes * Requests and environments now appear correctly when viewing multiple projects. * Variable values are now preserved when migrating local projects from the previous app. * Aligned the sidebar default sort order with the previous app. **v2605.3.1** May 4, 2026 ### 🚀 New * Migrate your local projects from the previous desktop app into Requestly. * Complete interactive OAuth flows through a hosted callback so login redirects work on desktop. ### 🐛 Fixes * Fixed imports of older collections and environments that previously failed to load. * Importing now merges into your existing global environment instead of failing with a conflict. **v2604.30.1** Apr 30, 2026 ### 🚀 New * Run your collections from the command line with the new Requestly CLI. * Authenticate requests with OAuth 2.0, including a token service and orchestration. * Use non-interactive OAuth 2.0 grants with automatic token refresh. * Sign requests with OAuth 1.0 directly from the Authorization tab. ### ✨ Improvements * Added contextual help hints across the API client. ### 🐛 Fixes * Older imported records without an explicit type now correctly default to HTTP requests. **v2604.28.1** Apr 28, 2026 ### 🚀 New * An app-wide cookie jar lets you manage cookies with a Postman-style experience. * Import much larger files, with the limit raised from 30 MB to 100 MB. * Import API definitions from SoapUI projects. * Import an exported Requestly project archive directly. ### ✨ Improvements * Add a description column to the request headers editor. * Clear the script package cache with a new button to reclaim disk space. **v2604.21.2** Apr 21, 2026 ### 🚀 New * Use npm packages directly in your scripts, with search and one-click install. ### ✨ Improvements * Postman imports now translate npm and jsr package requires in scripts. * The package library now always shows its split layout for a steadier view. ### 🐛 Fixes * The package library Save button now matches the size of other editors. **v2604.20.1** Apr 20, 2026 ### 🚀 New * Run GraphQL subscriptions on the desktop app. * Create and reuse custom script packages across your requests with a new package library. * An SSL verification indicator now appears in the footer. ### 🐛 Fixes * Postman export now preserves template-prefixed URLs. * Scripts that use a top-level return now have their Postman-style calls transformed correctly. **v2604.17.1** Apr 17, 2026 ### 🚀 New * Import HAR files directly, with captured requests turned into examples. * Local filesystem projects now detect and sync changes made outside the app. ### 🐛 Fixes * The Debug tab stays accessible even when a response returns an error. * HTTP/2 pseudo-headers are now filtered out of requests imported from HAR. * Postman export no longer wraps the collection in a duplicate root entry. **v2604.16.1** Apr 16, 2026 ### 🚀 New * Inspect outgoing requests with new DevTools Console and Network panels. * Toggle SSL certificate verification on or off per request. ### ✨ Improvements * Empty projects now show helpful call-to-action prompts, and project creation is simpler. ### 🐛 Fixes * Template variables in the URL bar are now preserved, and dynamic variables resolve in code snippets. * Postman imports with array-based form-data file sources now parse correctly. * Root collection descriptions now import from Postman, and the overview scrollbar is hidden. **v2604.14.1** Apr 14, 2026 ### 🚀 New * Run bulk operations on examples and import them from supported formats. * Create examples instantly from the sidebar and save them from a new dropdown. ### ✨ Improvements * Persisted example tabs now show a "Try it" button in place of Send. * Redesigned confirmation dialogs for clearer, more readable prompts. ### 🐛 Fixes * Variables now resolve correctly in generated code snippets, and request body content type is set properly. * Invalid GraphQL variables now show an inline validation error instead of failing silently. * Importing from cURL no longer carries over a stale Content-Length header. # Team projects Source: https://docs.requestly.com/collaboration/how-to-get-started-with-shared-workspace Learn how to set up a team project in Requestly Requestly’s **team and shared projects** make collaboration easy by **syncing** all **project data** so members can work together on **HTTP rules, mock APIs, the API client, and sessions**. Whether you're debugging, testing, or managing API workflows, a shared project keeps your team in sync and productive. ### Setting up a shared project Let's create a shared project and invite teammates to collaborate in real time. Follow these simple steps to get started. [https://www.youtube.com/embed/Lv19\_pZQ6gg](https://www.youtube.com/embed/Lv19_pZQ6gg) ### Create a project **1. Open project switcher** In the top-left corner of the sidebar, find the project dropdown (you start in a project named **Default Project**). ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/3bf05219-44ea-43a1-847e-3e0c7f90f852.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=92f185480edadf7c34c4dcec026f94ea) **2. Open the create options** Click the project dropdown. The switcher lists your **Local projects** and **Team projects**, each with a create option. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/d9a760e4-9511-415e-bce6-1a2b2052047f.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=7eaa36ec07531c5f37b149be29398fa1) **3. Create a new project** Click **Create a team project** to make a shared project (or **Create a local project** for a device-only project). Enter a name for your project in the provided field and click **Create project**. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/81a0eeee-4622-4de1-b15e-dd48a798ddac.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=c8190607d902e52aa35527511ee4c568) > [!TIP] > > You can also check the checkbox at the bottom of this popup to invite your entire team while creating the project. ## Managing team members > [!NOTE] > > If your account is managed through a **BrowserStack organization**, project creation and member management happen on the **BrowserStack projects dashboard** instead of in the app. In that case the create and member controls open the BrowserStack dashboard, and your changes sync back into Requestly automatically. To effectively manage access, admins can add team members, update their roles, or remove team members within a project. Below are the steps to perform these actions. ### Adding new members **1. Switch to the project** Navigate to the Requestly dashboard and switch to the project where you want to add members. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/233f23c4-d4ef-4dee-aed4-837c800f4cdb.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=887192ec5deaa8e62349bdb2840dcef8) **2. Open project settings** In the project switcher, hover the project row and click the **Project settings** gear (or **Add members**). ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/a5671767-467d-4b76-8a4d-31d7c774dd11.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=b018279df44d4343d1ad7a47228783bd) From here you can open the **Members** tab to see the current members before inviting. **3. Invite people** In the **Members** tab, use the **Add member** form. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/9dc9e35b-51ad-4eb2-b0b8-dcc3661102f0.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=b4d039a2317d81844de5e76d55eb1442) **4. Invite teammates and set roles** Enter your teammates email addresses and assign them specific roles. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/62157e63-6fcf-4c07-a28d-4deb833a49f4.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=16cb94f53cb9923d0275ff22e27bc392) **5. Await confirmation** Invited members will receive an email to join the project. Once they accept, they will appear in the members list. ### Removing members **1. Switch to the project** Navigate to the Requestly dashboard and switch to the project where you want to remove members. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/c2f2b1e9-1cab-4f6e-bfd4-86c1dd1a0fb6.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=fe603b18bca3a450817ddddd7bfda16e) **2. Open project settings** In the project switcher, hover the project row and click the **Project settings** gear (or **Add members**). ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/3f8b873f-cff4-4f02-8044-63ecd70a12f2.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=e6f9ebea8e7feff110d70a65824f730b) **3. Remove the member** Locate the member you want to remove from the members’ list. Click the 3-dot menu next to their role and select **Remove user from project**. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/53da708b-c0bf-44b5-b1b1-68be9493cd7c.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=a3dd15d80c31fc521636aa75bafd9dfe) **4. Confirm the removal** A confirmation prompt will appear. Confirm the action to remove the member successfully. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/64736a55-a369-47b7-9df1-1c9ddd68ced0.webp?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=24fdb3428dcc3ab100b45d2a7dd229a2) **5. Revoke pending invites** If a member has been invited but not yet joined, you can revoke their invite from the same dropdown. ![](https://mintcdn.com/requestly/J2qFDsPkU9iKOyXZ/images/how-to-get-started-with-shared-workspace/aef144cf-cf9c-403a-99bc-87ba10866a29.png?fit=max\&auto=format\&n=J2qFDsPkU9iKOyXZ\&q=85\&s=27468c0f87aaaa399560cb9a7ff151ce) # Managing your project Source: https://docs.requestly.com/collaboration/how-to-get-started-with-shared-workspace/managing-workspace Learn how to manage projects in Requestly ### Renaming a project Projects can be renamed by following these steps **1. Click on your project name** In the Requestly dashboard, locate and click on your project name at the top. ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/managing-workspace/accab303-1b56-4aad-ab0a-5d980d0e3b8a.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=7fa161817df18fef98790f460959fecb) **2. Go to project settings** From the dropdown or navigation menu, select **Project Settings**. ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/managing-workspace/70a6a9b8-aab7-47a0-ac53-0e70b834b877.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=00bba33cae6bbdc6d310e1a969d1bc24) **3. Edit the project name** In the **Project Settings** section, find the **Project Name** field and enter the new name ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/managing-workspace/92a2fbd9-e625-454f-a48e-30924ebb0d55.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=2ae9a013ad256073a7120849fee9fe56) **4. Save changes** ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/managing-workspace/45d67893-3956-419a-bab8-f157379c8bd6.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=1134b7875336cabaaeb40df12b9796a0) Click the **Save Changes** button to apply the new project name. ### Delete a project Projects can be deleted using the **Delete Project** button in the project settings ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/managing-workspace/66f74419-1f92-4623-bff4-d3b8762c6d8d.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=e704914d1d4e7df27365916da2ae99c9) > [!NOTE] > > Deleted projects and their contents are retained for 7 days before being permanently removed. See the [Data Recovery Policy](../../account/data-recovery) if you need to restore a deleted project. # User Roles and Permissions Source: https://docs.requestly.com/collaboration/how-to-get-started-with-shared-workspace/user-roles Learn how to manage team collaboration securely in Requestly with Role-Based Access Control (RBAC) by defining roles and setting permissions. *** Requestly enhances collaboration and security by allowing project admins to assign specific roles to users. This role-based access control (RBAC) ensures that only authorized members can access sensitive configurations, such as API keys and authentication tokens, and helps prevent unauthorised modifications. In this doc, you'll learn how Requestly's RBAC works, the specific roles available, the permissions associated with each role, and how to change user roles within your project ## How RBAC Works in Requestly Requestly uses role-based access control (RBAC) to ensure that every team member only gets access to what they need. It has three roles, **Admin**, **User**, and **Viewer**, each with permissions that protect sensitive data like API keys and tokens and reduce mistakes or unauthorised changes, making teamwork smoother and more efficient. ## User Roles and Their Permissions Each project has three roles, each with distinct permissions: #### **Admin** * Full control over **project settings, member management, and permissions**. * Can **create, edit, delete, and execute** API requests, collections, and environments. #### **User** * Can **create, edit, delete, and execute** API requests, collections, and environments. * **Cannot** manage team settings, members, or project-wide configurations. #### **Viewer** > [!TIP] > > Viewers cannot edit API requests, but they can **execute** them. * **Read-only access**. * Can **view and execute** API requests, collections, and environments but **cannot make any changes** or access sensitive project settings. ### Permissions Table Below is a table that outlines key permissions for each role: **Project** | **Permission** | **Admin** | **User** | **Viewer** | | - | - | - | - | | Add a new user | ✅ | ✅ (Add as a user) | ❌ | | Remove a user | ✅ | ❌ | ❌ | **API Client** | **Permission** | **Admin** | **User** | **Viewer** | | - | - | - | - | | Send a request | ✅ | ✅ | ✅ | | Save, update, or delete a request | ✅ | ✅ | ❌ | | Create, update, or delete a collection | ✅ | ✅ | ❌ | | Switch an environment | ✅ | ✅ | ✅ | | Create, update, or delete a Environment variable | ✅ | ✅ | ❌ | | Define current/local values in a Environment variable | ✅ | ✅ | ✅ | | View secrets | ✅ | ✅ | ❌ | | Export Requests, Collections and Environment | ✅ | ✅ | ❌ | | Create new draft requests | ✅ | ✅ | ❌ | | Import collection/environments from Requestly and Postman | ✅ | ✅ | ❌ | | Import cURL | ✅ | ✅ | ❌ | ## Changing Roles At times, you may need to update a team member’s role. Follow these steps to change roles within your project: **1. Switch to the project** Navigate to the Requestly dashboard and switch to the project where you want to add members. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/user-roles/d26f4d28-084f-4277-bcf1-abafe660efec.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=c1a101d281cc71c3e4fb87234d9f6d02) **2. Open project settings** In the project switcher, hover the project row and click the **Project settings** gear. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/user-roles/0b2e28a4-07c3-44a8-b35c-34cf0908a18a.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=37f49c344b3fb85540d4909442f7e74a) **3. Select a Member** Find the member whose role you want to change in the members list. **4. Update Role** Use the dropdown next to their name to select the new role (e.g. Admin, User, or Viewer) and confirm the change. ![](https://mintcdn.com/requestly/nBAzlC6Az5-SAqsk/images/user-roles/64491626-b123-4083-a67d-d3563ed0e51a.png?fit=max\&auto=format\&n=nBAzlC6Az5-SAqsk\&q=85\&s=88fa5aae6ecbfadbfbbfe0fde59a96f1) # Local project Source: https://docs.requestly.com/collaboration/local-workspace Learn how to set up local projects in Requestly **Local project** in Requestly, like [team projects](https://docs.requestly.com/collaboration/how-to-get-started-with-shared-workspace), is a way to isolate your work. The key difference is that it stores all your data on your local system, ensuring full privacy. Your collections, requests, and environment data stay on your device and can’t be accessed by anyone else > [!WARNING] > > Local project data lives entirely on your device, so it is not backed up by Requestly and cannot be restored by our team if deleted. See the [Data Recovery Policy](../account/data-recovery) for details. ## **How to create a local project** **1. Open the project menu** Click on the **current project name** at the top-left corner of the app to open the project dropdown. ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/local-workspace/01b903a5-2eba-4d09-8dc7-8697391d8758.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=3f1e4e15416b8d3396ef8b2cf4368600) **2. Create a local project** In the project switcher, click **Create a local project** to start the setup. ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/local-workspace/89475a10-fd52-4d31-8a50-64359b5e937d.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=91198e2dd72a0a8f61568eab137a4487) **3. Choose Create a new local project** In the **Add a local project** dialog, select **Create a new local project**, then click **Create project**. Pick an empty folder in the system dialog. You name the project after choosing the folder. ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/local-workspace/1f51bb22-2fef-416c-b236-726161797fc6.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=a33b850c97daf6d262e39314266f5076) **4. Name the project and create it** Enter a **Project name**, then click **Create project** to finalize the setup. Your local project is now ready to use! ![](https://mintcdn.com/requestly/1os8lH_VUE6QydeH/images/local-workspace/743377e3-339f-4e7c-8273-9f7cf0c57d97.png?fit=max\&auto=format\&n=1os8lH_VUE6QydeH\&q=85\&s=ea77279b6600b828cdb903c4e84645fe) ## **How to delete a local project** **1. Open project menu** Click the **current project name** in the top left to open the project dropdown. ![Project menu](https://mintcdn.com/requestly/52w1DNjxRJa_PDPS/images/workspace-menu.png?fit=max\&auto=format\&n=52w1DNjxRJa_PDPS\&q=85\&s=fa481d42b2f83f466eff5e822c382bae) **2. Go to project settings** Select the local project you want to remove and open its **Settings**. > [!TIP] > > You can also delete any related files or folders stored on your device if you want to clean up everything linked to that project ![Project settings delete](https://mintcdn.com/requestly/52w1DNjxRJa_PDPS/images/workspace-settings-delete.png?fit=max\&auto=format\&n=52w1DNjxRJa_PDPS\&q=85\&s=146c7e023e0a5ea8aefa58fae13fd33a) **3. Delete project** Click **Delete Project** and confirm the action by entering the project name. Then click the **Delete Project** button to complete the removal. ![Delete project modal](https://mintcdn.com/requestly/eshUk3ocQ60UPiC4/images/delete-workspace-modal.png?fit=max\&auto=format\&n=eshUk3ocQ60UPiC4\&q=85\&s=5bd92b03291178fb9877e95443160a6e) # Working with multiple projects Source: https://docs.requestly.com/collaboration/multiple-workspaces Requestly allows you to **work with multiple local projects at once**. This makes it easier to collaborate across services (Auth, Payments, Orders, etc.) without merging everything into a single project. > [!WARNING] > > **Note:** Multi-project view works only with **local projects** at this time. ## How to use multiple projects Follow these steps to open multiple local projects in one view: **1. Open the API tab** Open Requestly and navigate to the **API tab** from the sidebar. **2. Open the project selector** In the top-left corner, click on your current project name to open the **project selector** dropdown. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/fb94f8c2-6c48-4935-b058-06844c154fe0.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=4953a39667942acec86c6cdd9984a8ae) **3. Select multiple projects** Check the boxes next to the local projects you want to load together. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/0d2cc730-080d-40ac-9355-4ab1c7d6ea50.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=e29322cfc4f65c5c095655f1bcb26015) **4. View projects in the selector** Your chosen projects will appear grouped in the selector. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/8abc940c-2520-4915-b68a-a08cfdea0d6f.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=4cef4fc7884a2faf18e15c9462b955fe) That’s it! You can now test APIs across multiple projects in one seamless view. ## Using environments in multi-project view When working with multiple projects, each project keeps its own **separate environment**. This ensures that variables from one project do not interfere with another. ### **Switching environments** You can switch environments using the **dropdown below the project name** in the sidebar. This lets you quickly toggle between different setups for the same project. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/d1037ea6-e3c5-4134-b7d2-655034740c40.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=54bbcf88d40f9e62000c2ec9e709644a) ### **Editing environment variables** To edit variables for a project: 1. Go to the **Environments tab**. 2. Select the project whose environment you want to edit. 3. You’ll see all variables for that project listed, and you can add, update, or remove them as needed. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/60cea11b-0135-4d76-ae7e-51845142f3a3.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=f19ee2539265d3f46edd413e2d0e2f53) ## Moving requests across projects You can easily move or share requests between different projects in multi-project view. There are two ways to do this: ### **Method 1: Drag and drop** ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/3e18caf2-cb3a-404b-8133-d882ae9e2410.gif?s=3ab47a0b1efad17307f19edd9afb6228) ### **Method 2: Move via menu** **1. Open the request menu** Click on the **three dots** menu next to the request you want to move. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/a26eaf76-dae1-4ad6-924a-b92b90df9481.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=03122ab442b57e250b81d74364b87635) **2. Select “Move to Collection”** Choose the **Move to Collection** option from the menu. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/61b77b01-58ea-4fe3-8b4b-53505b04b69b.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=2556381c8ea9f761921a92eedb197cd4) **3. Choose project and collection** Select the target project and the collection within it where you want to move the request. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/ecd11d53-178d-4337-8d20-25b586246cd8.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=53b581600f67a3535a736c6d9f161845) **4. Confirm move** Click **Move** to complete the action. The request will now appear in the selected project and collection. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/1114b6e6-ab46-4710-9866-0bf88514724e.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=d3a1432284952490dafe12b3810ce928) ## Sharing data across projects To share values (like tokens) across different projects, you can use [**Runtime Variables**](/api-client/environments-and-variables/runtime-variables). These act as **super-global variables** that are accessible across all projects. They can be created as temporary values for quick testing or persisted for longer use. You can view, edit, or clear them anytime from the **Runtime Variables tab** on the left. ![](https://mintcdn.com/requestly/eSOeLVkmwVPWjPJw/images/multiple-workspaces/23463a1c-cdde-4070-b4b3-93e9b230d24a.png?fit=max\&auto=format\&n=eSOeLVkmwVPWjPJw\&q=85\&s=c5793aa7dccaef67ea53b8112c7d791d) # Introduction Source: https://docs.requestly.com/collaboration/workspaces Learn about projects and workspaces in Requestly, how to organize your rules, mocks, and API requests and collaborate with your team. A **project** in Requestly (also called a **workspace** in the HTTP Interception section) is where you store all related rules, mock APIs, API requests, and collections in one place. It helps keep everything organized and easily accessible for better management and collaboration. > [!NOTE] > > The API Client refers to these as **projects**. The HTTP Interception section refers to the same concept as **workspaces**. They are the same thing. ### Understanding projects A Requestly project contains HTTP rules, API requests, collections, and mocks. By default, you start in a **private project**, where no other user can view or access your rules. This setup is ideal for personal work or testing. However, you can create additional **team projects** and invite other users to collaborate in real time, sharing rules, APIs, and mocks effortlessly, or create a **local project** to keep all your data on your machine. ### Types of projects Requestly offers two main types of projects: **Team project**, A team project is cloud-based: all your data is securely stored and synced across teams and devices. This is ideal when you work with a team and need everyone to stay in sync. **Local project (beta)**, A local project stores all your data on your computer, giving you complete control and privacy. It is designed for individual use rather than team collaboration. Choose this option if you prefer local storage over the cloud. ## Explore > **[Local Project](/collaboration/local-workspace)** > > Create and manage a local project that stores data on your device. > **[Multiple Projects](/collaboration/multiple-workspaces)** > > Work with several local projects side by side and move requests between them. > **[Shared Team Project](/collaboration/how-to-get-started-with-shared-workspace)** > > Invite teammates and collaborate in real time with a shared cloud project. > **[User Roles](/collaboration/how-to-get-started-with-shared-workspace/user-roles)** > > Understand the Admin, User, and Viewer roles within a shared project.