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

# Self-Serve Ticket Dispatch in Teams

> Let your technicians ask Neo for their next ticket in Microsoft Teams, and have Neo pick the most urgent eligible one and assign it to them

## Overview

This recipe builds a **technician-facing** chat agent that hands out work on demand: an engineer messages Neo in Teams — *"give me my next ticket"* — and Neo finds the most urgent eligible ticket in your helpdesk queue and assigns it to **them**. It's pull-based dispatch — technicians take work when they're ready, instead of a dispatcher (or an automation) pushing it to them.

<Info>
  This is an **Internal** [chat agent](/chat-agents/overview) deployed as a [custom internal bot](/integrations/teams/internal-bot) — your prompt, your tools, your branding, running with your full MSP toolbox. New to chat agents? Start with [Building a chat agent](/chat-agents/building-a-chat-agent).
</Info>

## Why a chat agent — and not a "request ticket" workflow

It's tempting to build this as a **workflow** triggered off a ticket: give each technician a permanent "status ticket" they flip to *"Request Next Ticket"*, and let the change fire an agent that assigns them work. **Don't.** Neo's agents keep conversation continuity *per ticket by design*, so a single ticket re-triggered for every request accumulates history until the agent loses track of the live queue and starts reporting *"no tickets available"* when eligible ones are sitting there.

A chat agent is the right model:

* Each request is a normal chat turn — no long-lived entity to accrue stale state.
* The technician is identified automatically from their Teams sign-in, so Neo can assign to "them" without anyone typing a resource ID.
* `/reset` (or `/new`) starts a clean conversation whenever a technician wants one.

## How it works

1. A technician messages your branded internal bot in Teams (*"what should I work on next?"*).
2. The agent queries your live helpdesk queue for eligible, unassigned tickets and orders them by SLA.
3. It re-checks the top candidate is still free, then assigns it to the **requesting** technician and replies with the ticket to start on.
4. If nothing qualifies right now, it says so and asks them to check back shortly.

## Setup

<Steps>
  <Step title="Create the Internal chat agent">
    [**Chat**](https://dashboard.neoagent.io/chat) → **New Chat Agent**. Set **Audience** to **Internal** — this is a technician-facing agent that runs with your full MSP toolbox (an End-user agent is locked to one company and can't dispatch).

    * **Name**: "Next Ticket" (or whatever your team will recognize in Teams)
  </Step>

  <Step title="Enable the toolbox">
    The agent needs to read the queue and write the assignment — nothing else:

    * **PSA integration** (ConnectWise / Autotask / Halo) → **Tickets: Read & Write**. Read lets the agent query the live queue; write covers setting the owner, moving the status, and adding an audit note. The agent assigns by writing to the ticket directly — it's given the requesting technician's PSA resource ID (from [Technician Mapping](#connect-technician-mapping-required-to-assign-to-the-requester), below), so there's **no separate assignment tool to add**.

    Keep the toolbox tight: a dispatch agent only needs to find tickets and assign them. Don't add M365, RMM, or other write tools it won't use.

    <Info>
      **Autotask only:** assigning an owner needs the resource *and its role* together — `assignedResourceID` + `assignedResourceRoleID` — Autotask rejects one without the other. Two things make this just work:

      * Neo allows the `assignedResourceRoleID` field automatically whenever you allow `assignedResourceID`, so if you scope the Tickets permission to specific fields, list `assignedResourceID` and `status` — the role rides along, nothing else to configure.
      * Also enable **Resources: Read** so the agent can look up the engineer's default service-desk role to send alongside.

      ConnectWise and Halo have no such pairing — Tickets: Read & Write is enough.
    </Info>
  </Step>

  <Step title="Write the dispatch policy">
    This is the part that matters most — the rules that decide *which* ticket and *how* it's assigned. Adapt the queue ID, statuses, and classifications to your PSA (the example uses fictitious values):

    ```
    # Next-Ticket Dispatch — 1st-Line Helpdesk

    You hand one 1st-line ticket to the technician who is asking, on request.

    ## How you're used
    A technician messages you (e.g. "give me my next ticket"). Treat each message as one
    request: find the single best eligible ticket and assign it to them. Never assign more
    than one ticket per request.

    ## Who is asking
    The requester is identified from their verified Teams identity, and their details — including
    their PSA resource ID — are given to you in the Requesting Technician section. Assign the ticket
    to that resource ID. Never ask the technician for, or guess, a PSA resource ID.

    ## Eligibility (hard rules — never override)
    A ticket qualifies only if ALL of these are true:
    - It is in the 1st Line Helpdesk queue (queue ID 12345).
    - Its status is one of: New, New - Customer Note Added, Approval Required.
    - It is unassigned (no current owner).
    - It is not completed or closed.
    - Its company's classification is Gold or Silver.
    Assigned, completed, closed, or an out-of-scope classification are hard stops — never
    work around them.

    ## Choosing the ticket
    1. Query the live helpdesk queue for eligible tickets. Always pull fresh from the PSA —
       never reuse a list from memory or an earlier message.
    2. Order the results by first-response SLA target, soonest due first.
    3. Take the most urgent candidate, then re-fetch THAT ticket live and confirm it is still
       eligible (unassigned, allowed status, not completed, in-scope classification) right
       before assigning — another technician may have just taken it.
    4. If it no longer qualifies, discard it and move to the next candidate. Repeat until one
       passes or the list is exhausted.

    ## Assigning
    - Assign the confirmed ticket to the requesting technician as the primary owner — using their
      PSA resource ID from the Requesting Technician section — and set its status to In Progress.
    - Reply in the chat with the ticket number, title, a one-line summary, and a
      clickable link to the ticket in the PSA so the technician can open it in one
      click. Always include the link.
    - Add a short internal note on the ticket noting it was self-dispatched via Neo.

    ## When nothing qualifies
    Only after re-validating live that no candidate qualifies, tell the technician there are
    no eligible tickets right now and to ask again shortly. Never invent or assume a ticket.
    ```

    The two load-bearing rules are **"always pull the queue fresh"** and **"re-fetch and confirm the candidate is still unassigned right before assigning."** Together they keep the agent honest about the live queue and safe when several technicians ask at once — that second re-check is what stops two simultaneous requests from double-booking the same ticket. See [Writing effective agent instructions](/core/writing-agent-instructions) for the general guide.
  </Step>

  <Step title="Connect Technician Mapping (required to assign to the requester)">
    "Assign to me" only works if Neo knows which PSA technician each Teams user is. Connect the [Microsoft Teams — Technician Mapping & Availability](/integrations/teams/workforce-availability) integration in your **own** tenant and run its auto-map — it links each technician to their Microsoft account.

    A technician who isn't mapped gets a clear message asking their Neo admin to set this up, rather than a wrong assignment. (Connecting this integration only does the mapping; it doesn't change anything about Ticket Dispatch unless you separately turn on Teams availability there.)

    The same mapping is what lets Neo load the requesting technician's profile — name, IDs, and their custom instructions — into the conversation, which the next section builds on.
  </Step>

  <Step title="Test in the dashboard">
    Chat with the agent on the **Chat** page and ask for a ticket. Confirm it queries the queue, picks the most urgent eligible ticket, and — when you turn off [test mode](/chat-agents/building-a-chat-agent) — actually assigns it. With test mode on, it describes the assignment instead of making it, so you can tune the policy safely first.
  </Step>

  <Step title="Deploy it to your technicians">
    [**Chat** → **Channels**](https://dashboard.neoagent.io/chat?tab=channels) → **New Channel**: **Audience: Internal**, transport **Teams**, assign this agent, set your branding. Then follow the [custom internal bot guide](/integrations/teams/internal-bot) to **Install in your tenant** and roll it out to everyone — an Internal bot installs only in your own Microsoft 365 tenant.
  </Step>
</Steps>

## Per-technician rules (e.g. by customer classification)

The policy above applies the same eligibility to everyone. If different engineers handle different work — say each team only takes certain **customer classifications** — you don't need a separate rule per person in the agent prompt. On every turn, Neo automatically gives the agent the **requesting technician's profile**, including their **custom instructions**, resolved from the same Teams mapping above. So you can scope per technician on the profile, and have the policy defer to it:

1. On each technician's **profile** (the Technicians area / Profiles tab), set their **custom instructions** — e.g. *"Only assign tickets where the company classification is Gold."*
2. In the dispatch policy, treat the requester's standing instructions as additional eligibility:

```
## Per-technician scope
The requesting technician's standing instructions (their profile custom instructions, shown
to you in the Requesting Technician section) may narrow what they can take — e.g. to certain
customer classifications, queues, or companies. Apply them as extra hard-eligibility rules for
this request. If they don't restrict anything, fall back to the eligibility above.
```

Because the rule lives on the profile, onboarding an engineer is just setting their instructions — no agent edit, and a blank profile falls back to the agent's default eligibility. The technician must be mapped (previous step) for their profile to load; an unmapped technician is asked to get mapped rather than dispatched against the wrong scope.

## What technicians experience

A technician opens your bot in Teams and asks for work in their own words. Neo replies with the ticket to pick up — number, title, a one-line summary, and a clickable link straight to it in the PSA — and the ticket is already assigned to them and In Progress. When the queue is empty, Neo says so and to check back shortly. `/reset` starts a fresh conversation any time.

## Keeping it reliable

* **One ticket per request.** The policy assigns exactly one ticket per message — technicians come back for the next one when they're ready.
* **Fresh queue every time.** The agent must query the live PSA on every request; never let it reuse an earlier result.
* **Re-validate before assigning.** The candidate is re-fetched and confirmed unassigned immediately before the write, so two technicians asking at the same moment can't be handed the same ticket. This re-check is the safeguard against double-booking — keep it in the policy.
* **Keep technicians mapped.** Coverage depends on the Technician Mapping auto-map. When you onboard an engineer, re-run it (or add a manual mapping on the Profiles tab) so "assign to me" works for them on day one.

## Troubleshooting

| What you see                                                                     | Why                                                                                                                   | Fix                                                                                                                                                                                  |
| -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| *"Ask your Neo admin to map your account"*                                       | The technician isn't linked to a Microsoft account                                                                    | Connect [Technician Mapping](/integrations/teams/workforce-availability) and run auto-map, or add a manual mapping on the Profiles tab                                               |
| "No eligible tickets" when you can see some in the PSA                           | Your eligibility rules don't match the queue's reality (wrong queue ID, status names, or classifications)             | Re-check the hard-eligibility section against your PSA's actual queue, statuses, and company classifications                                                                         |
| The agent assigns to the wrong person                                            | It used a name or guessed an ID instead of the requester's identity                                                   | Make sure the policy says to assign using the PSA resource ID from the Requesting Technician section — never a name or a guessed ID                                                  |
| Autotask: assignment fails / "must assign both a resource and a role"            | The agent set the resource but not the required role, or Resources read is off so it can't resolve one                | Confirm **Resources: Read** is enabled; Neo already allows `assignedResourceRoleID` automatically when `assignedResourceID` is allowed, so no field-list change is needed            |
| The same ticket goes to two technicians                                          | The candidate wasn't re-checked before assigning                                                                      | Confirm the "re-fetch and confirm still unassigned right before assigning" rule is present in the policy                                                                             |
| A technician gets tickets outside their scope (or their profile rule is ignored) | The policy doesn't defer to the requester's standing instructions, or the technician isn't mapped so no profile loads | Add the [per-technician scope](#per-technician-rules-eg-by-customer-classification) rule to the policy, set the technician's profile custom instructions, and confirm they're mapped |

## Related

* [Custom internal bot](/integrations/teams/internal-bot) — how the Teams deployment works
* [Assign Technician (Basic)](/recipes/assign-technician-basic) — the **push** alternative: Neo assigns automatically on a trigger or schedule, no one asks
