> This page is for Assistant Platform.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.moveworks.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.moveworks.com/_mcp/server.

# Optional Lab: Live Agent Handoff

> **Warning**
>
> **This optional Live Agent Handoff lab cannot be fully tested in the cohort training instances.** Those ServiceNow instances do not permit outbound REST traffic, so the live agent message-brokering callbacks to Moveworks (`api.moveworks.ai/rest/LiveAgentService/...`) fail at the network layer. The configuration walkthrough remains useful, but **2.1: Test the Handoff** will not succeed in a cohort training instance.
>
> Use the walkthrough as an implementation reference for your own ServiceNow tenant where outbound REST is permitted. See [Configure ServiceNow Live Agent Message Brokering](/service-management/live-agent-handoff-assistant/live-agent-message-brokering-assistant/how-to-guides-for-message-brokering) for the canonical product documentation.

> **Note**
>
> **This lab is optional and isn't part of the standard ILT flow.** It needs a ServiceNow instance with the Moveworks Live Agent update sets and a second ServiceNow user to act as the agent. Confirm with your ILT host before starting.

> **Info**
>
> ## Overview
>
> * **Learning Objectives:** Configure Moveworks to broker live agent chat sessions between users and ServiceNow agents using the Virtual Agent API integration.
> * **Estimated Time:** 30 minutes
> * **Prerequisites:**
>   * [Lab #8](/ai-assistant/getting-started/labs/moveworks-setup/lab-8-ticketing-core) complete
>   * A ServiceNow instance with these update sets applied (your ILT host provides them):
>     * `Moveworks Live Agent VA API Config` (Virtual Agent API scope)
>     * `Moveworks Live Agent AWA Config` (Global scope)
>   * Access to **Tool Studio** in My Moveworks (for the API key)
>   * ServiceNow admin credentials for your lab instance
>   * A ServiceNow instance that allows outbound REST traffic to `api.moveworks.ai`. The cohort training instances do not; see the warning above.

---

### Key Concepts

Live Agent Message Brokering allows Moveworks to act as a bridge between end users in their chat platform (Slack, Teams, etc.) and live agents in ServiceNow's Service Operations Workspace. When the AI Assistant can't resolve a user's issue, it hands the conversation to a human agent.

* **Message Brokering vs. Deep Link:** Message brokering keeps the conversation in the user's chat platform (Slack or Teams). The deep link approach sends users to a ServiceNow portal instead.
* **Virtual Agent API:** Moveworks uses ServiceNow's Virtual Agent Bot-to-Bot API (`/api/sn_va_as_service/bot/integration`) to initiate conversations and relay messages between users and agents.
* **Agent Availability:** Moveworks checks the `awa_agent_presence_capacity` table to determine if agents are available before offering the handoff option.
* **AWA Routing:** Interactions must be routed through Advanced Work Assignment (AWA) queues. Without a properly configured queue, assignment rule, and eligibility pool, interactions will immediately close.

---

> **Note**
>
> **Relevant documentation:**
>
> * [Configure ServiceNow Live Agent Message Brokering](/service-management/live-agent-handoff-assistant/live-agent-message-brokering-assistant/how-to-guides-for-message-brokering) — the canonical product reference for implementing this flow in your own tenant.
> * [How To Guides for Handoff Plugin](/harness/agentic-reasoning-engine/smart-handoff-assistant/how-to-guides-for-handoff-plugin) — configuration for Agent Broker Handoff and other handoff types.
> * [Exploring Advanced Work Assignment (ServiceNow docs)](https://docs.servicenow.com/bundle/washingtondc-servicenow-platform/page/administer/advanced-work-assignment/concept/awa-overview.html) — queue and routing behavior.

## 🛠️ 1: Walkthrough

### 1.1: Verify ServiceNow Prerequisites

> **Error**
>
> **The update sets handle most of the ServiceNow configuration.** Verify they were applied correctly before continuing.

#### Verify Virtual Agent API Plugin

1. In your ServiceNow instance, navigate to **System Applications > All Available Applications > All**
   ![](/_fern-files/_img/98dc94e57cc32044f668a426ec4bd9ee2378232c0b0e67eef709aaed906194ca.webp)

2. Search for **Virtual Agent API** and confirm it is installed
   ![](/_fern-files/_img/7135fcfa454a98a94f759fae01e1cf0a27397574f31ee6599fba3882da5d0894.webp)

3. Search for **Agent Chat** plugin and confirm it is installed
   ![](/_fern-files/_img/caf313e848e25d18930a521ff07ecf30966f62b237e4539b41ad6afcbd8b91c6.webp)

#### Verify Update Set Configurations

Run the following script in **Scripts - Background** to confirm the update sets were applied correctly:

![](/_fern-files/_img/a767abfbaba3026de8de2655d3f7347117dbea5ec565c35e39e9f8e3be215998.webp)

```javascript
(function() {
    gs.print('=== Verifying VA API Config ===');

    var rest = new GlideRecord('sys_rest_message');
    rest.addQuery('name', 'VA Bot to Bot');
    rest.query();
    if (rest.next()) {
        gs.print('VA Bot to Bot endpoint: ' + rest.rest_endpoint);
    } else {
        gs.print('ERROR: VA Bot to Bot REST message not found');
    }

    var post = new GlideRecord('sys_rest_message_fn');
    post.addQuery('rest_message', rest.sys_id);
    post.addQuery('http_method', 'POST');
    post.query();
    if (post.next()) {
        gs.print('POST endpoint: ' + post.rest_endpoint);
    } else {
        gs.print('ERROR: POST method not found');
    }

    gs.print('\n=== Verifying AWA Config ===');

    var q = new GlideRecord('awa_queue');
    q.addQuery('name', 'Moveworks Labs Live Agent Chat Queue');
    q.query();
    if (q.next()) {
        gs.print('Queue: ' + q.name + ' | active=' + q.active + ' | channel=' + q.service_channel.getDisplayValue());
    } else {
        gs.print('Chat queue not found');
    }

    var ar = new GlideRecord('awa_assignment_rule');
    ar.addQuery('name', 'Chat - Most Capacity');
    ar.query();
    if (ar.next()) {
        gs.print('Assignment Rule: ' + ar.name + ' | active=' + ar.active);
    } else {
        gs.print('Assignment rule not found');
    }

    var ep = new GlideRecord('awa_eligibility_pool');
    ep.addQuery('display_name', 'Agent Chat Group : Chat - Most Capacity');
    ep.query();
    if (ep.next()) {
        gs.print('Eligibility Pool: ' + ep.display_name);
    } else {
        gs.print('ERROR: Eligibility pool not found');
    }

    gs.print('\n=== Verification Complete ===');
})();
```

**Expected Output:**

> **Note**
>
> Every line should match. If any line shows `ERROR`, the update set may not have been applied correctly. Contact your ILT host.

```
*** Script: === Verifying VA API Config ===
*** Script: VA Bot to Bot endpoint: https://api.moveworks.ai
*** Script: POST endpoint: https://api.moveworks.ai/rest/LiveAgentService/SnowSendMessageToUser
*** Script: 
=== Verifying AWA Config ===
*** Script: Queue: Moveworks Labs Live Agent Chat Queue | active=true | channel=Chat
*** Script: Assignment Rule: Chat - Most Capacity | active=undefined
*** Script: Eligibility Pool: Agent Chat Group : Chat - Most Capacity
*** Script: 
=== Verification Complete ===
```

---

### 1.2: Generate an API Key

1. In My Moveworks, open **HTTP Connectors** from the waffle menu.

2. Click **Credentials**, then **Create**.
   ![](/_fern-files/_img/117ee2d806f288a7c43e8279ff9a621ef4558bf75b40471d37040fca082f23b2.webp)

3. Enter a **Credential Name** (for example, `ServiceNow Live Agent API Key`).

4. Choose **API Key**.
   ![](/_fern-files/_img/ce2abe055277ea0689b70494fd61f3e3d84714e9d794142447888b6ffb47bb81.webp)

> **Error**
>
> **Copy the API key as soon as you click Publish** and save it somewhere secure. It isn't displayed again.

5. Click **Publish** and save the API key.
   ![](/_fern-files/_img/8d50bceb68a92e352351bd4dab7db6e6a03859aaeaa7db3877c9b486ca9812eb.webp)

---

### 1.3: Set the Auth Profile Password in ServiceNow

The update set creates the auth profile but **cannot transport the password**. You must enter the API key you just generated.

1. In your ServiceNow instance, navigate to **Outbound > REST Message**
   ![](/_fern-files/_img/5ab650405f7d3d50f32ca4f6a52af9911de7296f7131067d1cc7dcd7d46d4fe7.webp)

2. Click into **VA Bot to Bot**
   ![](/_fern-files/_img/5d8585f63dac65799ad1096b3bb7acf1fc886ce9f8e1fb618db3b2ca9c82d628.webp)

3. Open the **POST** method record called `postMessage` (listed under HTTP Methods)
   ![](/_fern-files/_img/72f454c869f756ddf3f8e9a1c41894620cf445acd48f45aaa58c8fa93d72c90f.webp)

4. Go to the **Authentication** tab and open the auth profile **Moveworks Live Agent Auth** (click the "i" icon and select open record)

> **Note**
>
> These records live in the **Virtual Agent API** application scope, not **Global**. See [ServiceNow application scopes](https://www.servicenow.com/docs/r/xanadu/servicenow-platform/proactive-service-experience-workflows/c_ApplicationScopes.html?contentId=2yXhmVG58QtS4oKeyJGmgA).
>
> Click the link shown below to switch to the **Virtual Agent API** scope before editing.
>
> ![](/_fern-files/_img/a0d9515b1829199c39d075a8c3a4e481884351b7a46cfd9dd764b8ad892e6508.webp)

![](/_fern-files/_img/f7d51398cf0ec988ec39400e7131a80c41b0a30061dac7a9df4217456ba36394.webp)

5. Enter the API key from Section 1.2 as the **Password**

![](/_fern-files/_img/4b29a8599de5803f845e6e3a14bd2ece9604679ca3a053025bbe7587ba521d84.webp)

6. Click **Update**

---

### 1.4: Set the Token Verification Password in ServiceNow

The update set creates the token verification record but **cannot transport the password**. You must set it manually.

1. Navigate to `https://[your-instance].service-now.com/token_verification_list.do`

2. Open the record named **Moveworks Live Agent Message Brokering - IT**
   ![](/_fern-files/_img/409c07197fadfd1b4a07ef8a7b7f8089c88ce90958791d5937fa993e147e43b1.webp)

3. Set a secure password in **Token**. **Save it; you need it in Section 1.7.**

4. Click **Update**

---

### 1.5: Configure Live Agent Handoff

1. In Moveworks Setup, navigate to **Handoff > Live Agent Handoff**

2. Click **Create** to add a new configuration

3. Set **Configuration** to **Agent Broker Handoff**
   ![](/_fern-files/_img/f6f37cd8d738703f2f56df732d67c56bf1f5fb4159e0eb5526500f30050fbc42.webp)

4. Open the **Live Agent Handoff** dropdown and set the **Handoff Identifier** (e.g., `agent_broker_instance_1`)
   ![](/_fern-files/_img/0e9ebe74ba29b1801acf54e9ad5f4d1c662224137c3785181d76430cc4ff026c.webp)

5. Configure the **Snow Handoff Config Context Bender** with the following default payload:

```javascript
{
  "language": "language OR null",
  "liveagent_optional_skills": "domain OR null"
}
```

![](/_fern-files/_img/1595470f4f7a93a7feeab8d03d74b7412327addadd6cf834305dd76ecabfd51e.webp)

6. Set the **Integration ID** to `snow` (the connector from Lab #3)
   ![](/_fern-files/_img/9d2e80acbdc0e4a8054e29c28b94e1ceefea1c1686e11b657c62081465545333.webp)

7. Set **Enable Live Agent** to **TRUE**
   ![](/_fern-files/_img/5ea02755bbd170e01ad4394a5be5a2e1ec92fa17575a1b85405882551bf6de5e.webp)

8. Click **Run** and enter your email to confirm the rule evaluates to `TRUE` for you.
   ![](/_fern-files/_img/0354bcb2199cb5f543f9db11a511794d36e6c32bc61628d5e3a8a8362a2e9fa2.webp)

| **Field Name**         | **Action / Value to Enter** |
| ---------------------- | --------------------------- |
| **Configuration**      | Agent Broker Handoff        |
| **Handoff Identifier** | `agent_broker_instance_1`   |
| **Integration ID**     | `snow`                      |
| **Enable Live Agent**  | TRUE                        |

---

### 1.6: Configure Smart Handoff

1. Navigate to **Handoff > Handoff Settings**
2. Expand **Setup items for categories**, then add a new **Item Display Key** with the following values (you may need to scroll to the bottom and click **Add +**)

| **Field Name**            | **Action / Value to Enter**                                                              |
| ------------------------- | ---------------------------------------------------------------------------------------- |
| **Item display key**      | `agent_broker_instance_1`                                                                |
| **Metadata Domain**       | `IT_DOMAIN`                                                                              |
| **Handoff Type**          | `AGENT_HANDOFF`                                                                          |
| **Live Agent Handoff**    | `agent_broker_instance_1` (the configuration from 1.5; required, or the item won't save) |
| **Pretrigger Rule**       | `IF (context.domain_candidates[0].domain == "IT_DOMAIN") THEN 1.0 ELSE 0.5`              |
| **Category display keys** | IT                                                                                       |

![](/_fern-files/_img/08400759a93dbd4ae61e6ba92275d0977273f27873de1026b975650beb67538f.webp)

![](/_fern-files/_img/c5a904744e84c4337607184ce45365a89affb7bc1abc8a5dfca458289d6c5d1b.webp)

3. Navigate to **Display Configurations > Handoff**
4. Scroll down within the Handoff configurations and ensure the **Item display key** (`agent_broker_instance_1`) is set under **Map of actions for handoff items**
5. Set the **Value** field to a user-friendly name (for example, `Live Chat`). Users see this name when they choose the handoff option. If the values are already set, continue to the next section.
   ![](/_fern-files/_img/fc014b63bda36e1291b9eec0401e2d7f3505972583262e4de77629726377c6a2.webp)

> **Note**
>
> If the item display key has no action text in Display Configurations, the **Start agent chat** button doesn't appear in the AI Assistant.

---

### 1.7: Add the Token to the ServiceNow Connector

1. In Moveworks Setup, navigate to **Connectors > Built-in Connectors**

2. Find the `snow` connector and click **Edit**
   ![](/_fern-files/_img/acf15a87b6cc65050bab3b8270384675b6b0142a8489188914fa5e15806c5db2.webp)

3. Add the token password from **Section 1.4** to the **ServiceNow Virtual Agent API Token** field
   ![](/_fern-files/_img/86c86994ea9b98e411111f9814982f48af95e5a2968748968264fada79f7b5eb.webp)

4. Click **Save**

---

### 1.8: Set Up Your Agent in ServiceNow

Run this script in **Scripts - Background** to configure the live agent user. Set `userName` to the ServiceNow user ID of the agent:

> **Note**
>
> Set the instance to **Global** scope first.
>
> You can't answer your own live agent chat, so the agent must be a different user from the one starting the handoff. If your instance doesn't have a second user, create one in **User Administration > Users** first. The script is preset to `moveworks.admin`; change `userName` to your agent's user ID.

![](/_fern-files/_img/c20692f4d4c51a018b3ab9e8f5a03abca648e827eaaaf16e860c01bb2abc7a3a.webp)

```javascript
(function() {
    var userName = 'moveworks.admin';  // <-- Set your agent's user ID here

    var user = new GlideRecord('sys_user');
    user.addQuery('user_name', userName);
    user.query();
    if (!user.next()) { gs.print('User not found: ' + userName); return; }
    gs.print('Setting up agent: ' + user.getDisplayValue() + ' (' + userName + ')');

    // Add to Agent Chat Group
    var grp = new GlideRecord('sys_user_group');
    grp.addQuery('name', 'Agent Chat Group');
    grp.query();
    if (!grp.next()) { gs.print('ERROR: Agent Chat Group not found'); return; }

    var gm = new GlideRecord('sys_user_grmember');
    gm.addQuery('group', grp.sys_id);
    gm.addQuery('user', user.sys_id);
    gm.query();
    if (!gm.next()) {
        gm.newRecord();
        gm.group = grp.sys_id;
        gm.user = user.sys_id;
        gm.insert();
        gs.print('  Added to Agent Chat Group');
    } else {
        gs.print('  Already in Agent Chat Group');
    }

    // Grant awa_agent role
    var role = new GlideRecord('sys_user_role');
    role.addQuery('name', 'awa_agent');
    role.query();
    if (role.next()) {
        var hr = new GlideRecord('sys_user_has_role');
        hr.addQuery('user', user.sys_id);
        hr.addQuery('role', role.sys_id);
        hr.query();
        if (!hr.next()) {
            hr.newRecord();
            hr.user = user.sys_id;
            hr.role = role.sys_id;
            hr.insert();
            gs.print('  Granted awa_agent role');
        } else {
            gs.print('  Already has awa_agent role');
        }
    }

    // Create agent presence
    var ap = new GlideRecord('awa_agent_presence');
    ap.addQuery('agent', user.sys_id);
    ap.query();
    if (!ap.next()) {
        ap.newRecord();
        ap.agent = user.sys_id;
        var ps = new GlideRecord('awa_presence_state');
        ps.addQuery('name', 'Available');
        ps.query();
        if (ps.next()) ap.current_presence_state = ps.sys_id;
        ap.insert();
        gs.print('  Created agent presence (Available)');
    } else {
        gs.print('  Agent presence exists | state=' + ap.current_presence_state.getDisplayValue());
    }

    // Create Chat capacity
    var ch = new GlideRecord('awa_service_channel');
    ch.addQuery('name', 'Chat');
    ch.query();
    if (ch.next()) {
        var ac = new GlideRecord('awa_agent_capacity');
        ac.addQuery('user', user.sys_id);
        ac.addQuery('channel', ch.sys_id);
        ac.query();
        if (!ac.next()) {
            ac.newRecord();
            ac.user = user.sys_id;
            ac.channel = ch.sys_id;
            ac.applied_max_capacity = 4;
            ac.insert();
            gs.print('  Created Chat capacity (max=4)');
        } else {
            gs.print('  Chat capacity exists');
        }

        // Create Chat availability
        var aca = new GlideRecord('awa_agent_channel_availability');
        aca.addQuery('agent', user.sys_id);
        aca.addQuery('service_channel', ch.sys_id);
        aca.query();
        if (!aca.next()) {
            aca.newRecord();
            aca.agent = user.sys_id;
            aca.service_channel = ch.sys_id;
            aca.available = true;
            aca.insert();
            gs.print('  Created Chat availability (available=true)');
        } else {
            gs.print('  Chat availability exists');
        }
    }

    gs.print('\nDone! Set your status to Available in Service Operations Workspace.');
})();
```

**Expected Output:**

![](/_fern-files/_img/3eb78defc0cefe88412d2af4151705f381b24a93c23c7ef0176cab6babfc19b5.webp)

**Impersonate** your agent user (shown here as `moveworks.admin`).

![](/_fern-files/_img/06e9189621aee71eae5487aa64a551ac7b65763326623a315307de54187409b9.webp)

After running the script, open **Service Operations Workspace** in ServiceNow and set your status to **Available**.

![](/_fern-files/_img/e79c6bbaa47c29bda26bf039209c121e470daabdf1a215003227df3f99e7422a.webp)

![](/_fern-files/_img/a883c7a8dd141ef5da7613f71123c3cf25c40bc8999a57cc1427344f9850651c.webp)

---

## ✅ 2: Verification & Testing

### 2.1: Test the Handoff

> **Warning**
>
> **This test requires a ServiceNow tenant that allows outbound REST traffic.** The cohort training instances do not. In those instances, handoff initiation succeeds until ServiceNow tries to call back into `api.moveworks.ai`; the chat session is then not brokered into Service Operations Workspace. Skip this test in a cohort training instance, or run it in your own tenant where outbound REST is permitted.

1. Open your AI Assistant

2. Start a conversation and click **Get Help**
   ![](/_fern-files/_img/548396b6e6a58b5c9df33e9154ad8f890ae12faae385a456dbc5fcefcc7e6da4.webp)

3. Select **Start agent chat**
   ![](/_fern-files/_img/107b88349d12e93fa508a4485e2d948bfde299a726ff5c4ad8a7cbaf90c6d9c5.webp)

4. Verify the description and click **Submit**

5. The live agent session starts. Check Service Operations Workspace for the incoming chat.

> **Note**
>
> Impersonate the agent user (for example, `moveworks.admin`) to receive the chat in Service Operations Workspace.

![](/_fern-files/_img/6d3a247e043939fe1dcc11446abd4a18b475c287d2f200d16507b2423917db49.webp)

---

### 2.2: Troubleshooting

| **Symptom**                                | **Likely Cause**                                                      | **How to Check**                                                                                                                                                                                                                                                                                                                             |
| ------------------------------------------ | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "No agents available"                      | Agent not set to Available in SOW, or schedule config blocking        | Verify agent status in SOW; check `awa_agent_presence_capacity` API. In ServiceNow, navigate to **Service Operations Workspace**, set your status to **Available**, then run `GET [your_instance]/api/now/table/awa_agent_presence_capacity?sysparm_query=aca_available=true`. You should see at least one result with `aca_available: true` |
| Interaction created but immediately closes | AWA queue, assignment rule, or eligibility pool missing/misconfigured | Check `interaction.list`. If `active=false` and `queue` is empty, AWA routing is broken                                                                                                                                                                                                                                                      |
| "Start agent chat" button doesn't appear   | Item display key has no action text in Display Configurations         | Verify Display Configurations > Handoff has an action text for the item display key                                                                                                                                                                                                                                                          |
| Auth errors from ServiceNow                | API key not set in auth profile, or token mismatch                    | Verify auth profile password and connector token match                                                                                                                                                                                                                                                                                       |

> **Success**
>
> **Next:** Return to the [Moveworks Setup labs](/ai-assistant/getting-started/labs/moveworks-setup) to continue with the core labs or pick another optional lab.

---

## 🪞 3: Reflecting on This Configuration

Through this lab, you've learned the following:

* How to configure Moveworks Live Agent Handoff to broker chat sessions between users and ServiceNow agents
* How to connect Moveworks and ServiceNow using the Virtual Agent Bot-to-Bot API with proper authentication (API key + token verification)
* How to configure Smart Handoff rules to control when the live agent option appears based on domain context
* How to verify agent availability and troubleshoot common issues like missing AWA queue configuration, closed interactions, and authentication mismatches
* How the end-to-end flow works: availability check → interaction creation → AWA routing → agent assignment → message brokering

---

## ⚙️ 4: Configuration Details

| **Component**                   | **Where**                                          | **What**                                                               |
| ------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------- |
| **API Key**                     | My Moveworks > HTTP Connectors                     | Generated credential for ServiceNow auth profile                       |
| **Auth Profile Password**       | ServiceNow > VA Bot to Bot > POST > Auth Profile   | API key entered as password                                            |
| **Token Verification Password** | ServiceNow > `token_verification_list.do`          | Password set on Moveworks token record                                 |
| **Live Agent Handoff**          | Moveworks Setup > Handoff > Live Agent Handoff     | Agent Broker Handoff config with handoff identifier and integration ID |
| **Smart Handoff**               | Moveworks Setup > Handoff > Handoff Settings       | Item display key and display configuration                             |
| **Connector Token**             | Moveworks Setup > Connectors > Built-in Connectors | Token verification password added to ServiceNow connector              |
| **Agent Setup**                 | ServiceNow > Scripts - Background                  | Agent added to Chat queue with roles, presence, and capacity           |