# Creating & Managing Skills Source: https://docs.neoagent.io/agents/skills/creating-skills Ask Neo Support to build a skill from a description or a past run, then view and fine-tune it in the Skills tab You don't write skills by hand. You create them by **asking [Neo Support](/chat-agents/neo-support-agent)** — the chat assistant built into your dashboard — and you read and fine-tune them in [**Skills**](https://dashboard.neoagent.io/skills) under **Data** in the left navigation. ## Creating a skill Open Neo Support — the **Need help?** button in the bottom-right corner of any dashboard page, or the first card on the [**Chat**](https://dashboard.neoagent.io/chat) page — and ask it to build a skill. There are two ways to do it. ### From a past run (recommended) The best skills come from a job an agent has already done well. If a run produced exactly the output you want, ask Neo Support to turn that exact run into a reusable skill. It combines what the run actually did — the steps it took and the code it ran — with the relevant rules from the source agent, including rules for branches that this run did not need to exercise. Neo Support shows you the proposed skill before saving it. The fastest way: find the run in your agent's execution history and click **Skillify** on it. That opens Neo Support with a pre-filled request pointing at that exact run — review the message and send it. Or do the same by hand: Open [**Executions**](/product/executions) and find the run that did the job well. Click **Skillify** on it — or copy its link or run ID. If you didn't use the Skillify button, paste the run into a Neo Support chat and ask for a skill. For example: > Turn this run into a reusable skill so my weekly ticket summary comes out the same way every time: `https://dashboard.neoagent.io/execution-reviews/…` Neo Support explains which parts came from the run and which came from the source agent's instructions. Check the proposal and confirm it before Neo Support writes the procedure and code, tests the new skill, and saves it. It'll tell you the skill's name when it's done — you'll find it in the Skills tab. ### From a chat conversation Chat agents get the same treatment. When a conversation with one of your chat agents went the way you wanted, click **Skillify** under the message box to turn it into a skill — no need to copy the conversation or look up any IDs. Go to [**Chat**](https://dashboard.neoagent.io/chat), open the agent, and select the conversation that went well. **Skillify** sits under the message box. It's greyed out while the agent is still replying, and until the agent has answered at least once — there's nothing to compile before that. It doesn't appear on Neo Support itself (that's the agent doing the compiling), on [end-user agents](/chat-agents/how-end-user-bots-work) (skills are shared across your whole organisation, so they're built from your technicians' agents, not your clients'), on a conversation someone shared with you read-only, or if your organisation doesn't have Neo Support. **Conversations from Teams.** A conversation held with an internal agent in Microsoft Teams is not one you started from the dashboard, so the message-box button above does not show it. Open the **History** tab on the [Chat](https://dashboard.neoagent.io/chat) page instead (visible to workspace owners), select the conversation, and click **Skillify** at the top of the transcript. The rest of the flow is the same. End-user agents still show no Skillify action. Neo Support opens on a new conversation with the source agent and conversation already attached, and the message box empty. Nothing is sent until you send it. Add a line if you want the skill focused on something specific, then send. Same as above — Neo Support reads the conversation together with that agent's own instructions, then shows you the proposed skill and waits for your confirmation before saving. ### From a description If you don't have a run to point at, describe the procedure in plain English and let Neo Support build it from scratch: > Build a skill that, every Monday, lists our open tickets grouped by client and priority, with totals and the ten oldest tickets, and formats it as a short summary. Pointing Neo Support at a real run almost always gives a better skill than describing one from memory — the run shows it exactly which data to pull and how, so there's nothing to guess. ## Viewing and editing your skills Open the [**Skills**](https://dashboard.neoagent.io/skills) tab to see every skill in your tenant. The left side lists your skills; click one to expand it and see its files — the `SKILL.md` procedure and any scripts. Click a file to open it on the right. ### Display name and slug Each skill has a display name and a slug. The display name is the human-friendly label and can be updated by asking Neo Support. The slug is the permanent identifier agents use to load the skill and is shown with a lock in the Skills tab; it cannot be changed after the skill is created. If you need a different slug, ask Neo Support to create and verify a replacement first. Any agent instructions that name the old slug must be updated before the old skill is deleted. Neo Support will explain the tenant-wide impact and wait for your confirmation before replacing it. ### Editing the procedure `SKILL.md` — the plain-English procedure — is fully editable. Tweak the wording, add a step, or adjust how the output should be formatted, then click **Save**. The Skills tab with a skill open. The left tree shows the skill expanded into SKILL.md and a locked script; the right pane shows SKILL.md open in the editor with an Edit/Preview toggle, a Save button, an 'Available to all agents' label, and a version number. Use the **Edit** / **Preview** toggle to switch between editing the raw text and seeing the formatted result. Each save creates a new version (v1, v2, v3…), shown next to the file name — so you always have a record of what changed. ### Editing a script The scripts inside a skill are editable too. Open a script and it appears in a code editor with line numbers and syntax highlighting. Change what you need and click **Save**, or press **⌘/Ctrl + S**. Like the procedure, each save creates a new version, so a tested script is never more than one **Restore** away. An edited file shows an **Unsaved** marker until you save it, both in the top bar and next to the file in the tree. Editing several files? **Save all** writes them together. ### Asking Neo to make the change Prefer to have Neo do it? Click **Adjust with Neo** in the top bar of any skill. Neo Support opens with that skill attached — say what you want changed, and it reads the whole skill, proposes the edit, and saves it once you confirm. When the change touches a script, it runs the script in the sandbox first. One button covers the whole skill, whichever file you have open, because the procedure and the scripts that carry it out have to agree. Save your work first. The button is switched off while a file has unsaved changes, since Neo reads the saved skill: it would work from one text while your screen shows another, and your next save would overwrite what it wrote. ### Going back to an earlier version Click **History** on any file to see every saved version, newest first, with when it was saved. Pick **Restore** on an older version to load it back into the editor; save it to make it the current version again. Nothing is lost — restoring simply brings an earlier version forward as a new one. ### Running a script to check it Before you rely on an edit, run it. Open a script and click **Run** (or press **⌘/Ctrl + Enter**). Neo runs the script in the same secure sandbox your agents use, so it reaches your real systems, and streams the output as it goes. * **Choose which agent to run as.** A script reads from your PSA, Microsoft 365, RMM and the rest through the permissions of one of your agents. Pick that agent in the **Run as** box — Neo defaults to your internal chat agent and remembers your last choice. The run is always **read-only**: it can look at your systems but never change anything, so testing a script is safe. * **It runs what's in the editor.** You don't have to save first — Run uses your current edits, so you can try a change, see the result, and only save once it works. * **When a run fails, Neo tells you why** — a syntax error with the line, a permission the agent is missing, a timeout — in plain language above the output. If a run fails and you'd like Neo to fix it, click **Ask Neo Support to fix this**. Neo Support opens with the failed run already attached — it reads exactly what ran and what went wrong, explains the cause, and proposes a fix for you to confirm. ### Available to all agents Every skill shows an **Available to all agents** label. That's the rule for custom skills: once a skill exists, every agent in your tenant can load and use it, automatically. There's no per-agent toggle to manage. ### Deleting a skill Open the skill and select **Delete** in the top bar — you'll be asked to confirm, since the skill disappears for every agent in your tenant at once. If an agent tries to remove a skill on your behalf (through Neo's API), a technician has to approve it first. ## Keeping your skills healthy Neo Support tests a skill before saving it, but it's always worth watching the first real run after you create or edit one — open it in [Executions](/product/executions) and confirm the output is what you expect. A skill works best when it does one well-defined thing (one report, one reconciliation). If a procedure is really two jobs, ask Neo Support to split it into two skills. Small wording and formatting tweaks: edit `SKILL.md` yourself and save. Anything that changes what the code does: ask Neo Support, so the change is tested before it goes live. For a [scheduled agent](/core/scheduled-agents) whose whole job is one procedure, name the skill in its custom instructions (e.g. *"Load and run the `weekly-ticket-summary` skill"*) so it's used on every run. Loading the skill is free; each tool the skill calls still bills at the rates on [Tool credit costs](/agents/tools/credit-costs). Build the skill here with Neo Support rather than by re-running the scheduled agent — those runs spend credits, including in test mode. New to custom skills? Start with the concept page. # Custom Skills Source: https://docs.neoagent.io/agents/skills/custom-skills Capture a proven procedure once so your agents run it the same reliable way every time Built-in skills cover general MSP best practices. **Custom skills** capture *your* repeatable procedures — the specific multi-step jobs your agents do again and again, like a weekly service-desk report or a monthly license reconciliation. Once one of those jobs works the way you want, you turn it into a skill. From then on, every run follows the exact same steps and produces the same dependable output — instead of the agent figuring the job out from scratch each time. ## Why custom skills make outputs reliable When an agent takes on a complex, multi-step task, it normally works out the approach *each time it runs* — which data to pull, how to crunch it, how to format the result. That flexibility is exactly what you want for one-off problems. But for a job you run every week, you want the opposite: the **same proven steps, every time, no surprises**. A custom skill gives the agent a fixed recipe to follow instead of reinventing it. The result: * **Consistent** — the Monday report looks the same every Monday, in the same shape and format. * **Reliable** — the tricky parts (a fiddly query, a specific calculation) were worked out and tested once, then reused. The agent doesn't re-derive them and occasionally get them wrong. * **Faster** — the agent follows the recipe rather than reasoning the whole job out from first principles. A good rule of thumb: if you find yourself running the same kind of job over and over and wishing it came out *identical* each time, that job is a great candidate for a skill. ## What's inside a skill A skill is a small bundle of files. There are two kinds: | File | What it is | Can you edit it? | | - | - | - | | `SKILL.md` | The procedure written in plain English — the steps the agent follows, and when to use the skill | **Yes** — edit it any time | | `scripts/…` | The code the skill runs (for example, to pull and crunch data) | **Yes** — edit and run it in the Skills tab | Not every skill has scripts. A skill can be just a `SKILL.md` — a written procedure the agent reads and follows. Skills that do real data work usually include one or more scripts that the agent runs in its secure [code sandbox](/agents/tools/built-in/overview). The Skills tab in the Neo dashboard. The left panel lists the tenant's skills; one is expanded to show its SKILL.md procedure and a script underneath. The right panel shows the SKILL.md procedure rendered as formatted text. Every file in a skill is editable in the Skills tab — the plain-English procedure (`SKILL.md`) and the scripts alike. Every save keeps the previous version, so a change is one **Restore** away, and you can **Run** a script to check it before it goes live. When you would rather Neo make the change, [ask Neo Support](/agents/skills/creating-skills) — and if a run fails, one button hands the failed run straight to Neo Support to fix. ## Skills that read an outside website Most skills only talk to the systems Neo already connects to — your PSA, Microsoft 365, your RMM, your documentation. Some need a public web page as well: a vendor status page, a utility's outage map, a supplier price list. Two separate things control this, and it helps to know which is which: * **The skill records the sites it needs.** Neo Support fills this in when the skill is created. It is a statement of what the scripts fetch — nothing more. * **Each agent is allowed to open sites in its own settings.** Open the agent, find the **Web Fetch** tool, and add the site there. This is the permission, and it is per agent, so you stay in control of what each agent can reach. When an agent loads a skill, Neo compares the two and tells the agent up front if a site the skill needs is not on that agent's list. You get a clear message naming the site, instead of a failed run that looks like the site is down. So for a skill that reads an outside page: * **Give the address when you ask for the skill**, so it is recorded. * **Add that site to the Web Fetch settings of the agent that will run the skill.** Until you do, the agent reports the missing site rather than fetching it. * **A saved skill may come back marked "unverified".** Neo Support's own agent is limited to Neo's documentation sites and cannot open your vendor's page, so it saves the skill and tells you which site to allow. That is expected, and the skill is not faulty. ## How your agents use a skill * **Available everywhere.** Every skill you create is automatically available to **every agent in your tenant** — there's no per-agent setup or toggle. * **Loaded when relevant.** When an agent takes on a task that matches a skill, it loads that skill, reads the procedure, and runs any scripts — instead of working the task out from scratch. * **Guaranteed for a scheduled job.** For a [scheduled agent](/core/scheduled-agents) whose entire job is one procedure (say, a weekly report), name the skill in the agent's instructions — for example, *"Load and run the `weekly-ticket-summary` skill"* — so it's used on every run. Loading a skill is free. The tools the skill uses are not — on a scheduled or chat agent each call bills at its per-call price. [External API Request](/agents/tools/management/external-api-request) is 3 credits per call; the API *skills* under Built-in Capabilities do not change that. Build and edit skills with [Neo Support](/chat-agents/neo-support-agent): that work is free, and only its calls into your own systems bill. Iterating by running the scheduled agent spends credits. See [Tool credit costs](/agents/tools/credit-costs). ## A typical example Say every Monday a scheduled agent builds an open-ticket summary for your team — grouped by client and priority, with totals and a short list of the oldest tickets. It works, but you notice small differences week to week: the grouping order shifts, the wording changes, occasionally a count looks off. Turn that job into a skill, and it stops drifting. The procedure and the code are fixed, so the report comes out in the same shape — same sections, same calculations, same format — every single Monday. New technicians reading the report always see the layout they're used to, and you can trust the numbers because the same tested logic runs each time. ## Skills vs. instructions & memory A skill, custom instructions, and [memory](/core/memory) all shape how an agent behaves, but they do different jobs: | | Best for | | - | - | | **Custom skill** | A specific, repeatable *procedure* you want done the same way every time (a report, a reconciliation, a multi-step routine) | | **Custom instructions** | Ongoing rules and preferences that apply across an agent's work (tone, sign-off, which clients to prioritize) | | **[Memory](/core/memory)** | Facts about your company and clients the agent should remember and reuse | The full decision guide — including [intents](/chat-agents/intents), the fourth piece — is on [Teaching Neo](/core/teaching-neo). Ask Neo Support to build a skill, then view and fine-tune it in the Skills tab # End User Communication Source: https://docs.neoagent.io/agents/skills/end-user-communication Professional communication guardrails for end user messaging ## What It Does The skill provides the agent with: * **Message structure**: a format for acknowledgments, clarification questions, and troubleshooting instructions * **Tone and language guidelines** for warm, professional communication * **Smart question filtering**: prevents the agent from asking users about things the MSP can check internally, such as account status or license assignments * **Safety guardrails**: prevents the agent from sharing unconfirmed diagnoses, internal analysis, credentials, or unrealistic timeline promises with end users * **User-safe steps only**: the agent gives end users safe steps, such as a restart, a cable check, or a sign-out. Registry edits, PowerShell, policy changes, and other admin-level work stay with the MSP. * **Situation templates** for common scenarios such as outages, vendor escalations, and resolution confirmations Custom instructions take priority over the skill's defaults. Use them to add a specific sign-off, adjust the greeting format, or define how your team handles scheduling requests. # Skills Overview Source: https://docs.neoagent.io/agents/skills/overview Skills are packages of guidance — and sometimes code — that Neo Agents load on-demand for specific types of tasks Skills guide an agent's approach to a task. Unlike tools, which perform actions, skills provide guidance and, in some cases, code. ## Two kinds of skills Shipped and maintained by Neo. Available without setup. Skills you create for repeatable procedures. ## How skills work When an agent starts a task, it evaluates the available skills and loads those relevant to the task. A loaded skill gives the agent a methodology to follow and, for some skills, code to run. For example, when an agent picks up a ticket about a malfunctioning printer, it loads the **Resolve Issue** skill to follow a diagnosis methodology. When it needs to message the end user, it loads the **End User Communication** skill to guide that message. An agent's prompt describes the skills its own tools can use, so the list differs per agent: an agent on ConnectWise reads the **CW PSA API** skill in full, and reads no description of **Autotask API**. Every skill stays loadable whatever the toolbox holds, so an agent can still load one to answer a question about a system it cannot call. Skills are always available when the agent is enabled. They don't need to be individually toggled on or off. ## Built-in skills Neo ships and maintains built-in skills. They apply to every MSP and need no configuration. Neo also ships **internal reference skills** for the PSA, RMM, Microsoft 365, and documentation integrations. Agents load these automatically when they use the matching tools, so you may see them in a run's log without having set anything up. Structured diagnosis and resolution methodology built for MSP workflows Communication guardrails for end user messaging ## Your own skills Create skills for recurring jobs, such as a weekly report, a monthly reconciliation, or another multi-step procedure. Capture a procedure as a skill after it works well so future runs follow the same steps. Learn what custom skills are and how to create and manage them ## Skills vs. custom instructions & memory Built-in skills provide **general best practices** across MSPs. Custom instructions and [memory](/core/memory) are **specific to your workflows and company**. When there is a conflict, **your instructions always win**. For example: * The End User Communication skill says to use "we" language * Your custom instructions say "always sign off as the technician's first name" * The agent follows your custom instruction For the full picture of where each kind of knowledge belongs - instructions, skills, memory, and intents - see [Teaching Neo](/core/teaching-neo). # Resolve Issue Source: https://docs.neoagent.io/agents/skills/resolve-issue Structured diagnosis and resolution methodology built for MSP workflows The Resolve Issue skill gives the agent a structured, proven methodology for diagnosing and resolving technical issues — the same approach an experienced MSP technician would follow. ## What It Does Instead of jumping straight to a fix, the agent follows a systematic process: 1. **Gathers context** — searches your documentation, finds similar resolved tickets, and reviews device configurations before acting 2. **Diagnoses root causes** — uses first-principles reasoning to distinguish symptoms from actual causes, ranking possibilities by evidence 3. **Resolves with minimal risk** — starts with safe, reversible fixes and escalates only when needed 4. **Validates and documents** — confirms the fix worked and documents everything for the technician ## Why It Matters * **Fewer misdiagnoses** — the agent doesn't guess. It researches first, then forms a hypothesis backed by evidence from your own documentation and ticket history. * **Consistent quality** — every ticket gets the same thorough analysis, whether it's a password reset or a complex networking issue. * **Faster resolution** — by following a proven methodology rather than trial-and-error, the agent reaches the right fix faster. * **Built-in safety** — the skill enforces guardrails like never sharing unconfirmed diagnosis with end users and never making irreversible changes without approval. The Resolve Issue skill works best when your documentation and past ticket notes are well-maintained. Better data in means better diagnosis and resolution. # Request Technician Approval Source: https://docs.neoagent.io/agents/tools/approvals/request-technician-approval Get human approval before the agent takes sensitive actions The Request Technician Approval tool enables the Technician-in-the-Loop workflow, requiring human approval before the agent takes certain actions. ## What It Does When enabled, the agent can: * Send an approval request to your configured technicians via Teams, or post it in a Teams channel or group chat where anyone can approve * Read the decision — approved, rejected or still pending — on a later step * Carry out the approved action The tool sends the request and returns straight away, and it does not carry out the action it describes. To hold a write until a technician approves it, require approval on the *write* — see [How to Use](#how-to-use). Once the agent finishes its turn, the run waits for the answer, with no timeout: see [If nobody answers](/core/technician-in-the-loop#if-nobody-answers). **Setup Required:** Follow the [Teams integration guide](/integrations/teams/intro#install-the-app) to allow Neo to ask approval in Teams. An approver can use their own Microsoft Teams account from another directory after accepting an invitation to this workspace. See [cross-workspace approvers](/core/technician-in-the-loop#approvers-from-another-workspace). ## How It Works 1. Agent analyzes the ticket and determines an action is needed 2. Agent prepares the action and explains what it wants to do 3. A Teams message with approve/reject buttons is sent to the configured technicians, and posted in the configured channels and chats 4. Technician reviews and makes a decision 5. Agent proceeds or aborts based on the response ## How to Use This tool is automatically enabled when you enable "Require Technician Approval" on other tools like: * Execute RMM Script * Add Client-Facing Note * Microsoft Graph API writes, such as creating a user * And many others It is also enabled on any agent that holds a write permission, so a high-impact write can still ask for a technician when you left approval off for that group. Pick the approvers on this tool — an agent with none has nobody to ask, and the request fails. To require approval before a write **and** still have that write happen, switch **Require Technician Approval** on for the write tool's permission group. Neo then holds the write until a technician approves, and runs it. An approval request on its own leaves the action undone. ### One approval for the same change to several records When the agent makes the same kind of change to several records, such as correcting twelve memories or disabling five users, it reads the records first and then asks once. The approval card shows the agent's summary, which names the records, and Neo stores the exact change for each record with the request. After you approve, each stored change runs exactly as stored, with no further check, and can be used again for the same change, for example when the agent retries after an error. A change that is not stored with the request, or that differs from it in any value that changes the call, needs a new approval. The one exception is a password or key in its own field: it is stored as a placeholder, so a change that sends a newly generated one still matches. Neo records each time a stored change runs. An approval with a note is checked the usual way, so your note is always read. For a single change, the agent writes the request as a summary without a list. A password or key in its own field of a stored change is kept as a placeholder. Neo recognises such fields by their names, as it does in the run's step trace, so this is best effort. Neo refuses to list a change when it detects a secret anywhere else, such as a message that delivers a password it generated, and the agent describes that change in the summary instead. The summary and the name of each change are text the agent writes, and it is instructed never to put a secret in them. ### Example Approval Message Learn more about Technician-in-the-Loop ## Best Practices Have multiple technicians available to avoid delays when someone is unavailable. Pick a channel or group chat in **Teams channels & chats that can approve** when a team shares approvals. Neo posts one card there, anyone in it can answer, and the first answer wins. See [Approvals in a Teams channel or chat](/core/technician-in-the-loop#approvals-in-a-teams-channel-or-chat). A request waits until someone answers it; there is no timeout, and the agent cannot wait inside the run to ask someone else. To bring in a second approver after a set time, have the agent schedule a check-back: see [If nobody answers](/core/technician-in-the-loop#if-nobody-answers). Guide the agent on when to seek approval vs. proceed autonomously. A request asks a technician to approve changes the agent will make. When your rule leaves a choice open, such as two contacts that both fit, the agent proposes one and names the other, and the technician can pick the other in a comment. A review, a manual step for the technician, or a "flag for review" goes in the internal note; when your PSA has no review status the agent can set, that note is the flag. A triggered agent with no way to add a ticket note puts these items in its dashboard summary instead, and a chat agent puts them in its reply. To have the agent notify a technician through this tool anyway, say so in the instructions, for example: "When the company is not linked to a tenant, use Request Technician Approval to notify Joe." If your instructions give one approval wording for a specific end client and another for everything else, state each condition and keep the two texts apart. The agent writes only the branch whose conditions are met, in that branch's own words, and does not name the other branch in the request — not as a heading, and not as a note saying it does not apply. The approver reads the request on its own, so a label from a branch that did not apply would tell them the wrong thing about what they are approving. Regularly check what's being approved to identify automation opportunities. # Supervised run checkpoints Source: https://docs.neoagent.io/agents/tools/approvals/supervised-run-checkpoints Submit Run Plan and Report Instruction Gap: the two pauses of a supervised run, where the agent shows its plan or asks how to read an instruction. **Submit Run Plan** and **Report Instruction Gap** exist only on a [supervised run](/core/supervised-mode), whether the agent is always supervised or you supervised [a single run](/core/supervised-mode#supervise-one-run-or-every-run) from **Run now**. Neo adds both to the agent for the run. They are not in the tool list of the agent builder, and both are **Free**, so they never raise the per-run price. Each one sends an approval card to the same technicians who approve the agent's changes, and the run waits for the answer. Neither one approves a change. Every change on a supervised run still asks for its own approval. ## Submit Run Plan The agent calls it once, before its first change. The card shows: * **Plan for this run**: how the agent reads the ticket and which of its instructions apply. * **Changes I intend to make**: every change, in order, one line each. | Your answer | What the agent does | | - | - | | **Approve** | Starts the changes, asking for approval of each one. | | **Approve with note** | Starts the changes and applies your note. | | **Ask for changes** | Revises the plan to answer your note and sends it again. | | **Reject** | Stops, and makes no change. You pick why (**Wrong steps**, **Not needed on this ticket** or **Just a test**) and can add details. [Train](/core/supervised-mode#after-the-run-train-the-agent) reads the reason. | ## Report Instruction Gap The agent calls it when its instructions leave a decision open and the choices lead to different changes. That is when two instructions conflict, when one instruction can be read two ways, or when no instruction covers a choice on which MSPs differ. It does not ask when one reading is plainly right or standard practice settles the choice. The card shows: * **Decision**: what the agent must choose before its next change. * **Your instructions say**: the instruction text, quoted, or that none covers the decision. * **I can read this as**: the choices, each written as the change it leads to. * **If you approve, I will**: the choice the agent follows by default. * **Suggested wording for your instructions**: new wording that settles the decision for later runs. | Your answer | What the agent does | | - | - | | **Approve** | Follows its default choice. | | **Approve with note**, or **Ask for changes** | Follows the choice in your note, and does not ask the same question again. | | **Reject** | Stops, and makes no change. | The suggested wording is not applied for you. To keep it, paste it into the agent's instructions, or use [Train Neo](/product/train-neo) on the run: Neo reads your answer and proposes the wording that matches it. What a supervised run is and how to turn it on The approval card each change asks for # Datto BCDR API Source: https://docs.neoagent.io/agents/tools/backup/datto-bcdr-api Read Datto SIRIS, ALTO and NAS appliances, their last backups and Datto's screenshot verification, so an agent can check a Datto alert and close the ticket once the backup recovers; read and change SaaS Protection seats The Datto BCDR API tool gives Neo agents access to the Datto Partner Portal API: SIRIS, ALTO and NAS appliances, Endpoint Backup for PCs and Direct-to-Cloud agents, and SaaS Protection. The common use is a Datto alert ticket: the agent finds the appliance, checks whether the alert is still active, reads the last backups of the protected machine, and closes the ticket or explains why it is still failing. Automatically enabled when you configure Datto BCDR permissions in your agent workflow. ## What It Does * Find the appliance from the serial number in the ticket title or the ticket's configuration item * Read an appliance's last check-in, storage and active alerts * Read a protected machine's last backups, local verification and Datto's screenshot verification result * Read Endpoint Backup for PCs and Direct-to-Cloud agents and their last backups * Read the Partner Portal activity log * Set a Direct-to-Cloud agent's bandwidth limit * Read SaaS Protection customers, seats and backup history for Microsoft 365 and Google Workspace * License, pause or unlicense SaaS Protection seats Neo does not start a backup, run a screenshot or clear an alert in Datto. When a backup is still failing, the agent reports what it found. The screenshot result is Datto's own verdict: the appliance boots the backup and judges the screenshot itself. The agent reads that result; it does not look at the image. ## How the agent checks a Datto alert The agent takes the appliance serial from the ticket and reads the appliance and its active alerts. For a backup or screenshot alert, it finds the protected machine and reads its last backups. If a backup newer than the alert succeeded, its screenshot verification passed and the alert is no longer active, the alert has recovered. Otherwise the agent notes the error and the time of the last good backup. If more than one machine could match, the agent lists them in an internal note and routes the ticket to a technician instead of guessing. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | BCDR Appliances | Disabled, Read Only | Appliances, their agents and shares, backups, verification, alerts and VM restores | | Endpoint Backup | Disabled, Read Only, Read / Write | Endpoint Backup for PCs and Direct-to-Cloud agents; the write sets an agent's bandwidth limit | | Activity Log | Disabled, Read Only | The Partner Portal activity log | | SaaS Protection | Disabled, Read Only, Read / Write | SaaS Protection customers, seats, backup history and stats; the write licenses, pauses or unlicenses seats | A bandwidth limit of zero, or pausing on metered connections, stops an agent's backups. The Helpdesk and IT Admin profiles ask a technician before that change. Pausing or unlicensing a SaaS Protection seat stops that user's backups, and Datto deletes an unlicensed seat's backed-up data 30 days later, so both ask a technician under every profile. Licensing a seat asks under Helpdesk and runs on its own under IT Admin and Full Automation. ## SaaS Protection The agent finds the customer by the user's email domain, reads the user's seat and its state, and reads the last backups of each service. To onboard a user, it licenses their seat. To offboard one, it pauses or unlicenses the seat after a technician approves. Neo does not read the screenshot image or the RMM deploy templates, which carry agent deploy tokens. ## Setup See [Connecting Datto BCDR to Neo](/integrations/datto-bcdr/connecting-to-neo). # Uniview API Source: https://docs.neoagent.io/agents/tools/backup/uniview-api Read backup status from the Uniview portal (Unitrends and Kaseya backup) so an agent can confirm a backup failure and close the ticket once the device backs up again The Uniview API tool gives Neo agents read access to the Uniview portal at backup.net, which covers Unitrends appliances, Kaseya endpoint backup and Spanning Microsoft 365 backup. The common use is a backup-failure ticket: the agent finds the device, checks whether it has backed up since the alert, and closes the ticket or explains why it is still failing. Automatically enabled when you configure Uniview permissions in your agent workflow. ## What It Does * Find an endpoint by its device name and read its last successful backup, its online status and when it was last online * Read the backup jobs of a server or VM protected by a Unitrends appliance, newest first, with their status and replication status * List BackupIQ alerts by client, device, job and severity * Check appliances for free space and online status * Read the last Microsoft 365 backup of a tenant or one user * Find the client from the [Organization Mapping](/integrations/uniview/overview#your-clients-are-mapped-automatically), or by name The Uniview API is read-only. Neo cannot start, retry or dismiss anything in Uniview; when a backup is still failing, the agent reports what it found. ## How the agent checks a backup failure The agent reads the device name and the alert time from the ticket and looks the device up. If the device has a successful backup later than the alert, the failure has recovered. If the device was offline, the agent says when it was last online, because a device that is off cannot back up. If more than one device could match, the agent lists them and asks instead of guessing. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Customers | Disabled, Read Only | The clients in your portal | | Backups | Disabled, Read Only | Endpoints, appliance-protected assets, backup jobs and appliances | | BackupIQ Alerts | Disabled, Read Only | BackupIQ alerts | | Microsoft 365 Backup | Disabled, Read Only | Spanning tenants and users, Entra ID tenants | Every group is read only, because the Uniview API has no write. ## Setup See [Connecting Uniview to Neo](/integrations/uniview/connecting-to-neo). # Subagent Fan-Out Source: https://docs.neoagent.io/agents/tools/built-in/dispatch-subagents Let an agent split a job into parallel pieces and work on them at the same time Some jobs are naturally repetitive — produce a tailored summary for each company on a list, sweep ten devices for the same condition, or research a question from several angles at once. Subagent Fan-Out lets the agent split the work into pieces and tackle them in parallel instead of one after another. When all the pieces are done, the agent comes back with the results bundled together. Subagent Fan-Out belongs to [scheduled agents](/core/scheduled-agents). There's nothing to enable — the agent decides on its own when a given job is a good fit for fanning out. No other kind of agent has it. A triggered agent doesn't, because the capability would weigh on every triggered run across the fleet and those runs almost never split their work — if one of your tickets does need parallel pieces, run that job as a scheduled agent. A [supervised run](/core/supervised-mode) makes one approved change at a time, and a parallel piece would have nobody to ask. A [Chat Agent](/chat-agents/building-a-chat-agent) can't wait for parallel runs to finish. For a job that big in chat, ask the Chat Agent for a sample first, then run the full job on a schedule. ## When It Helps Fan-out shines when the pieces of work are **independent** — each piece doesn't need to know what the others are doing. * **One output per item** — a tailored note per company, a check per device, a summary per ticket cluster. * **Multiple angles on the same question** — investigate a topic from several sides at once and aggregate the findings. * **Bulk audits** — sweep many systems for the same condition without waiting for each one in turn. ## When It Doesn't Fit | Workload shape | Why fan-out hurts | | - | - | | **Building something that has to fit together** | A coherent app, a single long document, or a refactor across files — parallel pieces make conflicting choices and don't compose. | | **Sequential work** | If step 2 depends on step 1, there's nothing to parallelise. A regular agent run is the right shape. | | **A handful of API calls** | If the work is "make ten quick calls and combine the results," a single agent with the right tools is cheaper than spinning up parallel runs. | | **Writes against shared records** | Two parallel runs updating the same ticket or the same document can step on each other. Keep writes single-threaded. | If you want to nudge the agent toward (or away from) fanning out on a particular workflow, say so in the agent's custom instructions — e.g. "when generating per-company summaries, do them in parallel." ## Safety | Control | Behaviour | | - | - | | **Capped parallelism** | An agent can't spin up more than 10 parallel pieces in one fan-out, and an agent run can fan out at most 5 times — so a single run is capped at 50 subagents total. If a job genuinely needs more, the agent splits it into batches; if it would exceed the 5-wave limit the run fails clearly rather than spawning indefinitely. | | **No runaway runs** | Each parallel piece has a runtime ceiling. Anything that overshoots is stopped and reported back as a timeout rather than quietly burning resources. | | **No nesting** | A piece that's running in fan-out can't fan out again. This keeps the worst-case cost and complexity bounded. | ## Billing Each subagent counts as its own agent execution. The cost of a fan-out run is the parent agent's normal cost **plus one execution per subagent** — same rules you already know from [Billing & Credits](/product/billing-and-credits). A scheduled agent is billed per tool it actually used — 1 / 2 / 3 credits per Basic / Standard / Advanced tool call — and each subagent is billed the same way, against the tools it called. **Worked example.** A scheduled agent makes 1 Basic tool call, then dispatches 3 subagents, each of which makes 2 Basic + 1 Standard call. Fanning out is itself a Standard call, so the parent pays 1 + 2. Cost = 1 + 2 + 3 × (2 + 2) = **15 credits**. Failed or timed-out subagents are still billed — they consumed work even if they didn't return a useful result. The agent's own *self-assessment* of execution quality (visible on the execution log) is separate from the credit charge. Fan-out is a power tool. The agent reaches for it only when the job has the shape of "do the same thing N times" — most workflows still run as a single agent. # Built-in & Internal Tools Source: https://docs.neoagent.io/agents/tools/built-in/overview Tools the agent always has, or gets automatically — you don't enable or configure these Not every tool shows up in the workflow's tool list. Some are **always available**, some are **auto-injected** when you turn on an integration, and some are **internal helpers** the agent uses behind the scenes. They still appear in [Executions](/product/executions) when the agent uses them, so this page explains what each one is. ## How a tool ends up "automatic" | Property | What it means | | - | - | | **Always available** | Provided to every agent; you can't toggle it. Things like documentation search, password generation, and short pauses. | | **Auto-injected** | Turned on when you configure the related integration's permissions. The big API tools (PSA, RMM, Microsoft Graph, IT Glue, Hudu, ScalePad) and the RMM-script tools work this way — see their own pages. | | **Dependency** | Pulled in automatically because another enabled tool needs it (e.g. a "get available options" helper for update/create tools). | | **Internal** | Plumbing the agent uses to do its job — not configurable, not shown in the dashboard. | ## Always-available tools | Tool | What it does | Has its own page? | | - | - | - | | **Find Documentation** | Search your connected documentation (IT Glue, Hudu, synced docs) | [Find Documentation](/agents/tools/search/find-documentation) | | **Find Tickets by Content** | Semantic search over past ticket content | [Find Tickets by Content](/agents/tools/search/find-tickets-by-content) | | **Find Configurations / Devices** | Look up configuration items / devices | [Find Configurations](/agents/tools/search/find-configurations) | | **Find PSA Contacts** | Look up contacts in your PSA | [Find PSA Contacts](/agents/tools/search/find-psa-contacts) | | **Resolve Company** | Resolve a customer company's IDs across connected systems (e.g. its IT Glue organization ID) so the agent reads that system by ID instead of an unreliable name search — `hidden_from_ui`, always-on, read-only. See [Company Mapping](/product/company-mapping). | — | | **Recall Memory** | Recall durable facts Neo has learned about your MSP and the end client (environment, conventions, past resolutions) before asking or re-deriving — read-only and free, scoped to your account | — | | **Generate Password** | Generate a strong random password | [Generate Password](/agents/tools/management/generate-password) | | **Generate Secure Link** | Wrap content in a one-time secure link | [Generate Secure Link](/agents/tools/management/generate-secure-link) | | **Get Ticket Summaries** | Fetch AI summaries for a set of tickets so the agent can scan them quickly | — | | **Get PSA Ticket Link** | Turn one or more ticket **or project** IDs into clickable deep-links into your PSA (ConnectWise, Autotask, Halo, ServiceNow, Syncro) so the agent can point a technician straight at the ticket or project — `hidden_from_ui`, always-on, read-only. Derives the links from your stored PSA URL, and builds a whole batch in one call. The agent already has the link to the ticket it was triggered on and to each ticket a ticket search returns with a link, so it calls this only for the other tickets and for projects. | — | | **List End Client Companies** | List the end-client companies under your account | — | | **Lookup Available** | List available resources by category (Teams users, [Teams channels & chats](/integrations/teams/intro#post-to-a-teams-channel-or-chat), technicians-in-the-loop, triggerable workflows, configured external APIs, reference skills) before acting on them. One call can cover several categories. For channels & chats, an agent that has the [Send Teams Message](/agents/tools/communication/send-teams-message) tool sees only the ones its channel scope allows; an agent without that tool sees everything registered, read-only. An agent with the [Read Teams Channel Messages](/agents/tools/communication/read-teams-channel-messages) tool also sees the channels it may read. The skills category lists every reference skill, including ones for systems the agent cannot call | — | | **Delay** | Pause execution for a set duration (up to 30 minutes) — used for "wait, then re-check" patterns. After a pause, Get Ticket, the PSA API tools and sandbox scripts read your PSA afresh, so notes, time entries and screenshots added during the wait reach the agent. In a **chat** agent each pause is capped at 60 seconds, because someone is waiting for a reply; the agent pauses repeatedly and keeps you updated instead of going quiet for minutes | — | | **Business Hours Elapsed & Chase Timing** | Compute business hours elapsed between two timestamps and decide whether a customer chase is due yet — the agent passes when the wait began, the current time, and the chase threshold in business hours, and gets back the elapsed business hours, a chase-due flag, the exact datetime the next chase window opens, and a plain-language explanation. The explanation always matches those numbers: it states the elapsed value against the threshold, gives the chase window in both the configured business-hours timezone and UTC, and says that the window instant itself counts as due. Removes error-prone manual timezone/weekend math from Waiting-Customer-Response follow-ups. Measures against **your own business hours and timezone** (the values on your Settings page) on a Mon–Fri week by default, and the agent can override timezone, working days, hours, and holidays per end company when one of them works a different window — always-on, free, read-only. | — | | **Load Skill** | Load one of the agent's [skills](/agents/skills/overview) on demand for task-specific guidance — `hidden_from_ui`, internal | — | ## Added for one kind of run Neo adds these only where they can work: the intent loaders when an intent applies, and the question buttons on chat agents. | Tool | What it does | Has its own page? | | - | - | - | | **Load Intent** | On a ticket-triggered agent, load the intake questions for one of your [intents](/chat-agents/intents) so the agent asks the end user only for the details the ticket is missing — `hidden_from_ui`, free, read-only. It only appears on runs where an intent with the **Triggered agents** surface applies to the ticket's company; you manage intents themselves, not this tool. | — | | **Load Intent (Internal Chat)** | The same for an internal chat agent: loads one of your [intents](/chat-agents/intents) as a form the user fills in, or as questions for the agent to ask where the intent has no form — `hidden_from_ui`, free, read-only. It only appears when an intent with the **Internal chat** surface applies to that agent. Separate from the tool above so each agent is told what its own surface can do; no run ever has both. | — | | **Ask User Questions** | When a chat agent asks a question with a small set of likely answers (a board, a status, yes/no), it offers them as clickable options — chips in the dashboard, Adaptive Card buttons in Teams. When several answers can apply at once (which boards, which statuses), you pick as many options as apply and they go back as one reply: in the dashboard each pick lands in the message box as a chip you can remove, you type anything of your own next to them and send as usual; in Teams they are checkboxes with a field for your own value and a Submit button. The agent can also put several independent questions on one card — the board, the statuses and who to notify: as many as it needs in the dashboard, up to four in Teams. In the dashboard the card shows one question at a time, with arrows to move between them: pick an option (a pick moves you to the next question), tick as many as apply where several can, type your own answer under **Something else**, or **Skip** a question. Your answers go back as one reply after the last question. In Teams you answer them together and send with one Submit. A go-ahead ("Create it", "Apply it") is a single button. On a chat surface that does not render buttons, the agent names the options in its message instead. Clicking one sends that text as your reply; you can always type something else instead. `hidden_from_ui`, free — it renders options and reads nothing. Every chat agent has it, and no other agent does. | — | ## Neo Support Agent tools Only the Neo Support Agent has these. No other agent gets them, and you can't add them to one. | Tool | What it does | Has its own page? | | - | - | - | | **Offer Agent Setup To Builder** | When you ask the Neo Support chat to help you build an agent, it works the agent out with you and then offers one button that sets up the agent builder you have open — the instructions, the name, what starts it, the ticket filter, the tools with their settings, and the integration permissions the work needs. The button fills the form without saving it, so anything you configured yourself survives and the save stays yours. `hidden_from_ui`, free — it writes nothing and reads nothing. | — | ## Dependency helpers These are added automatically when an enabled tool needs them — you never select them. | Tool | Added for | | - | - | | **Get Field Options** | Update / create tools — supplies the valid values for one or more fields (statuses, priorities, types, …) in a single call. Sub-types come back grouped under their parent type (Autotask sub-issue types under issue types, ConnectWise subtypes under types), so the agent picks both from one result. Custom (user-defined) fields are listed too. On Autotask, a pick-list custom field also carries its configured values, so the agent writes an exact label instead of guessing one. On Halo, a dropdown custom field with a fixed option list carries its options. On a single-select dropdown, Neo rejects a value that is not one of them or empty, because Halo would save it and show the field empty. The device/asset link field (ConnectWise Configuration, Autotask Configuration Item, Halo Asset, ServiceNow CMDB CI) has no value list — the tool points the agent at Find Configurations / Devices to resolve the record's ID, which the update then writes | | **Lookup MS License Names** | The Microsoft Graph API tool — resolves friendly license names from SKU IDs — `hidden_from_ui` | | **List Scheduled Workflow Runs** | [Trigger or Schedule Workflow](/agents/tools/management/trigger-or-schedule-workflow) — lists the Neo workflow runs already scheduled for your account (filterable by workflow, ticket, status, and time window) so the agent can enforce spacing / avoid duplicate scheduling before it queues another run. Read-only, free, `hidden_from_ui`. Covers Neo's own schedule only — PSA-native and RMM-native scheduled jobs are checked through their own APIs. | | **Get Technician-in-the-Loop Approval Status** | [Request Technician Approval](/agents/tools/approvals/request-technician-approval) — reads the decision status (pending / approved / rejected) and metadata of the TIL approval requests the agent already raised for a ticket, so a staged or multi-step approval flow can check whether an earlier request was decided before sending another. It reports the actual approval decision (ticket activity is not a substitute). Read-only, free, `hidden_from_ui`. | | **Get Workflow Run Status** | [Trigger or Schedule Workflow](/agents/tools/management/trigger-or-schedule-workflow) — reads the status and outcome of the most recent run of a workflow on a ticket, so a **chat** agent can report what a workflow it triggered actually did. In a chat conversation the trigger tool never waits for the workflow to finish, because someone is waiting for a reply; this is how the agent reports the result afterwards. Chat agents only — a scheduled or ticket-triggered agent can still wait for completion and gets the outcome directly. Read-only, free, `hidden_from_ui`. Honours dashboard access: it only reports runs of a workflow the person in the chat can open in the dashboard. | ## Auto-injected integration tools These turn on when you configure the matching integration's permissions on the workflow's **Integrations** tab. They're `hidden_from_ui` (you manage them via the integration, not a tool toggle): | Tool | Auto-injected when | Documented at | | - | - | - | | **ConnectWise / Autotask / Halo / ServiceNow PSA API** | a PSA is connected | [PSA API](/agents/tools/psa/psa-api) | | **NinjaOne / Datto / N-Sight / N-Central / ConnectWise Automate / ConnectWise Asio API** | the matching RMM is connected | [RMM API](/agents/tools/rmm/rmm-api) | | **Microsoft Graph API** | Microsoft Graph permissions are set | [Microsoft 365 Tools](/agents/tools/m365/overview) | | **IT Glue API** | IT Glue permissions are set | [ITGlue API](/agents/tools/documentation/itglue-api) | | **Hudu API** | Hudu permissions are set | [Hudu API](/agents/tools/documentation/hudu-api) | | **Vendor API** (ScalePad, Huntress, ThreatLocker, Ubiquiti UniFi, AutoElevate, Proofpoint Essentials, Hornetsecurity, Mimecast, SentinelOne, Wizer, Uniview, Datto BCDR, BeyondTrust EPM, CIPP, Domotz, SaaS Alerts, Auvik, Cisco Meraki, ConnectWise CPQ, Kaseya Quote Manager, myITprocess, QuoteWerks, Datto EDR, WatchGuard, RoboShadow, Duo, CyberQP, TP-Link Omada, OpenText Secure Cloud, Zabbix, CentralReach, Sophos) | any of those vendors' permissions are set | [Vendor API](/agents/tools/vendor-api) | | **Elastic Search** | PSA ticket read is enabled | this page (the search backend for ticket-history lookups; not selected directly) | | **Execute RMM Script** family | RMM script execution is enabled | [Execute RMM Script](/agents/tools/rmm/run-rmm-script) | | **Execute PowerShell (Exchange / Active Directory)**, **Trigger Azure AD Connect Sync** | Exchange / AD permissions are set | [Microsoft 365 Tools](/agents/tools/m365/overview) | | **Verify Dispatch Decision** | the agent has [Get Technician Context](/agents/tools/psa/get-technician-context) switched on | this page (see below) | ### Verify Dispatch Decision Neo runs one agent per ticket, and those runs happen at the same time. Two runs that read the same technician calendar a few seconds apart both see the same free slot, and both assign it — a double-booked engineer. Before a dispatch agent writes an assignment, this tool reserves that technician and slot for 10 minutes so no other run can take them, re-reads the calendar, and reports anything it finds wrong: leave, an overlapping appointment, a slot outside the technician's working hours, a slot past the SLA deadline, or a technician who has just been given several tickets. When the agent books a time slot, Neo re-reads that technician's schedule entries for the slot straight from your PSA, with no cache. It runs last, right before the agent writes, so it can find a booking your run's earlier calendar reads were too early to see. That matters because the technician who books their own meeting is not a Neo run, and the reservation does not cover them. The report names each clashing entry by its PSA schedule entry id, so your agent can compare it against the entry your PSA quotes if it rejects the write, and can put the id in the ticket note. The reservation stops other Neo runs and nothing else — it books no time in your PSA. Your PSA can still refuse a schedule entry over something created outside Neo, and the receipt tells the agent what to do about it: read the calendar again, pick a slot that clears the entry your PSA named, and write it. One refused slot is a second attempt, not a ticket handed back for manual dispatch. Most assignments set an owner and book no time slot, and on **Autotask** those get a check of their own: whether the new owner is on leave between now and the end of the next business day. A ticket assigned in the evening reaches its owner on their next working day, which the agent's earlier calendar read often stopped short of — and the engineer who is off tomorrow has the fewest open tickets today, precisely because they are away. This one is Autotask-only on purpose. Autotask records leave as a time-off request, so "on leave" is unambiguous. On ConnectWise the same calendar flag also covers lunch breaks, end-of-shift markers and all-day onsite visits, so the check would report engineers who are simply out at a customer site as unavailable. The slot checks are unaffected on every PSA — they only report a conflict when your booked slot actually lands on the blocked time. Before it picks anyone, the agent writes a short roll-call: each candidate's hours today, worked out from your custom instructions and calendar markers, and whether they are working right now. It sends that roll-call with its pick. When the tool reads the calendar (every booked slot, and an owner-only assignment on Autotask), it reports a pick the roll-call marks as off while another candidate is working, or a pick marked as working outside the hours on its own line. The tool does not decide who is on shift; your instructions do, so describe your shift markers there. The working-hours check earns its place on a retry. Your PSA checks a new schedule entry for **overlap only**, so it accepts a booking half an hour after the engineer went home and reports success. When the PSA rejects the first slot for a clash and the agent picks another, that replacement clears the clash and can still land outside the working day. A reported problem does **not** cancel the assignment. Your agent reads the report and decides, because your custom instructions say what your business accepts — "never book over an existing appointment", or "a P1 may take the next free hour even if it misses the SLA goal". You see each decision, and the agent's reason for it, in [Executions](/product/executions). There is nothing to switch on, nothing to configure, and it costs no credits. Two things are worth knowing: the tool cannot force the agent to call it, so write the call into your dispatch instructions; and only the ticket owner is reserved, not any extra resources added alongside them. ## Analytics category tools | Tool | What it does | Availability | | - | - | - | | **Generate Artifact** | Save a written report — findings, analysis, recommendations — that renders on the run in the dashboard | Listed under **Analytics** as always on; it can't be switched off | **Generate Artifact is always available, but agents don't file a report unless the work calls for one** — instructions that ask for a report or analysis, or a result someone will read later. For routine task execution the agent just writes its dashboard summary. To make an agent always produce a report (or never), say so in its custom instructions. Each saved report gets a link that opens it on the run's page in the dashboard, so an agent that tells someone about the report in Teams, Slack or email puts the link in the message. Only people who can see that agent's runs can open it. A chat conversation or a subagent has no run page of its own, so a report saved there has no link. It is also not the only thing that shows up under **Artifacts** on a run: any file an agent leaves in its [sandbox](/agents/tools/built-in/sandbox) is attached there as a download. Generate Artifact writes a report you read in place; the sandbox produces files you download. Want fine-grained control over the auto-injected integration tools? You don't toggle them off — instead set the relevant **permission groups** to **Disabled** on the workflow's **Integrations** tab. See [Tools Overview](/agents/tools/overview). # Sandbox Source: https://docs.neoagent.io/agents/tools/built-in/sandbox Give the agent a scratch Linux sandbox — run shell commands, read and write files, process data too large for a single reply The sandbox gives a Neo Agent a temporary, isolated Linux environment for the run: a shell, plus simple file read and write. Use it for data wrangling that doesn't fit a fixed tool — parsing an export, running a bulk script across many records, transforming a file, assembling a report. Every agent has a sandbox — the agent reaches for it on its own when the work calls for it. It's created fresh for the run and discarded afterwards. The three Sandbox tools appear in the agent's tool list as **always on** and can't be switched off, because every agent gets a sandbox regardless. To steer an agent toward or away from using it, use custom instructions. ## What It Does | Tool | What it does | Tier | | - | - | - | | **Sandbox Bash** | Run a shell command in the sandbox and read its output | Standard | | **Sandbox Read File** | Read a file from the sandbox | Free | | **Sandbox Write File** | Write a file in the sandbox | Free | | **Load Chat Files into Sandbox** | Copy files a user attached in chat into the sandbox, so the agent can read them with code. Chat Agents only | Free | Because the sandbox is on every agent whether you enable it or not, it never sets an agent's per-run price — see [Tool credits](/agents/tools/overview#credit-tiers). On the [Neo Support Agent](/chat-agents/neo-support-agent) the sandbox is free entirely. Sandbox Write File writes the exact content the agent supplies. For a Python script it can also confirm the file compiles as it writes, so a broken script is caught at write time instead of failing later in the run. Typical uses: * Loop one API call across hundreds of records in a single script instead of hundreds of agent turns * Parse or reshape a CSV/JSON export the agent fetched from another tool * Run a one-off calculation or text transformation * Produce a file — a CSV, a chart, a PDF — for someone to download off the run If you want to steer the agent toward (or away from) the sandbox on a particular workflow, say so in custom instructions — e.g. "use the sandbox to parse the exported CSV before summarising it." ## Files Users Attach In Chat When someone attaches a CSV, Excel, PDF, Word or text file to a chat message, an internal Chat Agent (including the Neo Support Agent) reads it in the sandbox. It calls **Load Chat Files into Sandbox** with the files it needs, which copies them in and tells it how to read each one. A spreadsheet is read row by row with code, so the agent can act on every row. A file is copied only when the agent asks for it, so a message that carries a file but needs no sandbox starts none. The tool is always on for internal Chat Agents and hidden from the builder, because it only reads files the user already shared in that conversation. End-user Chat Agents have no sandbox and no tool: they put a shared file on the end user's ticket instead. Agents that run on a trigger or a schedule don't have it either. Two kinds of file can't be read: an old Word `.doc`, and a scanned PDF with no text in it. See [Attaching files](/chat-agents/using-chat#attaching-files). ## How Long One Command Can Run A single sandbox command runs for up to **30 minutes** on a scheduled or triggered agent. In a **Chat Agent** it is capped at **5 minutes**, because the whole reply has one budget and someone is waiting for it — a Chat Agent asked for something big splits the work into steps, saves each step's results as it goes, and carries on across the following commands rather than going quiet for half an hour. You may see that split in the chat: the agent fetches a first batch, tells you what it has, and continues. That is the intended shape. If a job genuinely needs one long uninterrupted run — a full-history export, a fleet-wide sweep — run it as a scheduled agent instead, where the longer budget applies. ## Files The Agent Leaves Behind Become Downloads When the run ends, the files the agent left in its `workspace/` directory are saved and attached to that run as artifacts, downloadable from the run's page in the dashboard (and via the public API). Files the agent tucked into a hidden directory are skipped, as are the oversized tool outputs described below. Saving is per file when the workspace holds fewer than 100 files. A workspace holding 100 files or more is normally saved as a single `workspace.tar.gz` download instead, because saving that many one at a time runs past the time Neo gives this step. The archive holds every file, but you unpack it on your own machine and the run's download list shows one entry rather than a browsable list. An agent writing one file per record is the shape that produces an archive, and one file per batch is the shape that keeps individual downloads — worth saying in the agent's custom instructions if you ask for a bulk export. If the archive cannot be built, or comes out over 50 MB, Neo falls back to saving file by file and can then run out of time or reach its 200 MB total. It keeps what it saved and leaves the rest behind, with nothing in the chat to mark the gap. So after a bulk export, check the run's download list against what you asked for. A single file over 50 MB is always skipped, archive or not. This is worth knowing for two reasons: * **It's how the agent hands you a file.** A CSV, spreadsheet, chart, or PDF the agent builds is a real deliverable you can open — it isn't stuck inside the run. * **It's a separate path from [Generate Artifact](/agents/tools/built-in/overview#analytics-category-tools).** That tool writes a markdown report that renders inline on the run. The sandbox produces actual files you download. Turning Generate Artifact off stops the written reports; it doesn't stop an agent that has been *instructed* to build a file from building one in the sandbox. If you don't want an agent producing files, say so in its custom instructions. ## Oversized Tool Outputs Land Here When any integration tool (PSA, RMM, Microsoft 365, documentation, …) returns a response too large for the agent to read in one go, Neo automatically saves the **complete** response to a file in the sandbox and shows the agent a map of it plus the file path. The map lists the parts of the response: the records in a list and the sections of a document, with their sizes, or the headings of a page, with where each one starts. The agent then reads only the parts it needs, so a big data pull never derails the run or forces the agent to re-fetch with narrower queries. Reading a part costs nothing in the common case. **Sandbox Read File** is free, and it can return one value of a JSON response, find text anywhere in the file, or return a range of characters. This works even when the response was saved on a single line, as most API responses are. When a part sits inside an item of a list, and that item has an `id` field of up to 64 characters, the read names that id, so the agent updates the right record. The agent uses the shell only when it has to filter or total the data. ## Safety | Control | Behavior | | - | - | | **Scoped network access** | The sandbox can only reach the integrations enabled on the agent, through an authenticated proxy that enforces the same permission groups as the agent's regular tools. That includes Neo's own [Neo API](/agents/tools/management/neo-api), so a script can audit or reconcile configuration across many agents at once. Code in the sandbox never sees credentials. | | **Isolated and ephemeral** | Beyond the proxy, the sandbox sees only what the agent puts in it. The machine is destroyed at the end of the run — only the files it left in `workspace/` are kept, as downloads on that run. In a chat conversation Neo reuses the same machine for the following turns where it can, so the agent can carry on from where it stopped. Once you have been quiet for a few minutes Neo copies the machine's files and shuts it down, and your next message starts a new machine from that copy, so the agent's working files survive a long gap between replies. A bulk job that must finish unattended still belongs in a scheduled agent, which runs the whole thing in one pass. | | **Test mode** | When test mode is on, sandbox commands still run and every read through the proxy returns real data, Microsoft Graph included. A write that would change your systems (PSA updates, emails, directory changes, …) is simulated at the proxy: nothing changes, and the script gets a success marked as a test so it carries on with the rest of the job, as the agent's tools do. The proxy first applies its own checks, so a write it refuses on a live run is refused in test mode too: a read-only command, an operation that always needs approval, a tool that is off, an email a script may not send without approval. The receiving system's own validation does not run, so a write it would reject, such as one to a record that does not exist or one missing a required field, is still simulated. A script's simulated writes are not in the end-of-run list of blocked tool writes; the agent is told to list them as simulated in its own run summary. Exchange PowerShell is blocked for every script, including one that only reads. | | **Technician approval** | When an enabled integration requires Technician-in-the-Loop, the sandbox defaults to read-only: reads, analysis, and reporting run with no approval, and any write is blocked at the proxy. To make changes, the agent switches to read-write and gets an approved request first. Neo first checks the script against your approvals as it always has; when one covers it, the script runs as before, and any calls a request lists also let through its writes that always need approval. When only a request that lists exact calls (a plan of calls) covers the script, each of its writes that needs approval passes only if it is one of the listed calls. A plan only ever adds to what a script may do. A listed call can be used again for the same call. A write that is not on the list is refused. When the agent's [External API](/agents/tools/management/external-api-request) tool requires approval, a script's write to your APIs is refused, and the agent makes that call with the tool, which asks for the approval. | | **Writes that need an exact plan** | A small set of high-blast-radius operations always needs approval for the specific call — deleting an agent, changing an agent's actions, tools, settings or integrations, changing tenant settings, disconnecting an integration, cancelling a run, starting or cancelling a backfill or rerunning its failed runs, bulk-updating or deleting an end company, and deleting a skill or one or more memories or replacing a memory's content. The agent makes these with the matching request tool in the conversation, where the approval attaches to the call — and for an agent edit in chat, your confirmation in the conversation is itself the approval, so nothing extra is asked of you. It plans them on the request tool from the start, even when a change covers many agents or memories, and uses a script to find them. A script can make one only when you approved a request that lists that exact call; an approval that describes the change only in words never unblocks it from a script, however it is worded, and the refusal says so. | | **Time limit on PSA calls** | A call to your **PSA** through the proxy stops starting new work after about two minutes. It is not a hard stop on the clock: an attempt already in progress is allowed to finish rather than being cut mid-write, and a call that your PSA's own rate limit keeps rejecting may be attempted again — so treat this as a bound on wasted waiting, not as a guaranteed maximum duration. Nearly all calls finish in under three seconds. When a call does stop this way the script gets a request-timeout error, and it says whether anything was sent: if nothing went out, a write did **not** reach your system and it is safe to send again as-is; if an attempt did go out, check whether the write landed first, because a timeout or a server error can arrive after your system already applied the change. Calls to other systems — Microsoft 365, Exchange, RMMs, documentation tools, your own APIs — have no such limit. If a script hits this often, have the agent split the work into smaller calls or run them further apart. | # Add Client-Facing Note Source: https://docs.neoagent.io/agents/tools/communication/add-client-facing-note Add notes to tickets that are visible to end users The Add Client-Facing Note tool allows Neo Agent to add notes to tickets that end users can see. Your PSA may deliver these notes as emails to the ticket contact. Enabled automatically when you grant your PSA's client-facing notes permission group on the PSA integration (the workflow's **Integrations** tab) — there's no separate toggle in the tool list. The group is **Ticket Notes (Client-Facing)** on Autotask and ConnectWise, **Actions (Client-Facing Notes)** on HaloPSA, and **Client-Facing Notes** on ServiceNow and Syncro. The settings below live on that permission group. ## What It Does When enabled, the agent can: * Add external notes visible to end users * Communicate resolution updates * Request additional information from users * Acknowledge ticket receipt **For Autotask users:** Follow the [ticket contact notifications guide](/integrations/psa/autotask/ticket-contact-notifications) to set up "Ticket Note" mode notifications. **For HaloPSA users:** Halo only emails the end user when the note carries an Outcome that sends email. Neo uses the Outcome you pick in the tool settings. If you pick none, it reads the permission group's **Allowed Outcomes**: * **One Outcome allowed** — Neo uses it, whether or not it sends email. A single entry is your choice, so Neo does not second-guess it. * **Several allowed** — Neo takes the first whose Halo **Send Email** setting is *Automatic*. If none of them is, Neo does not post the note; it tells the agent why, and the reason shows on the execution. Add an email-sending Outcome (usually **Email User**) to **Allowed Outcomes** to fix that. A **Respond Automatically** Outcome also logs the ticket's first response and marks the response SLA as met — see [End-User Communication](/integrations/psa/end-user-communication#by-psa) for how that works. ## Best Practices Use custom instructions to establish consistent messaging that matches your brand. # Add Internal Note Source: https://docs.neoagent.io/agents/tools/communication/add-internal-note Add notes to tickets that are visible only to MSP technicians The Add Internal Note tool lets Neo Agent add internal notes to a ticket. These notes are visible only to your MSP technicians — they are never delivered to the end user — so they're the right place to record troubleshooting steps, triage findings, internal context, and hand-off details. Enabled automatically when you grant your PSA's internal-notes permission group on the PSA integration (the workflow's **Integrations** tab) — there's no separate toggle in the tool list. The group is **Ticket Notes (Internal)** on Autotask and ConnectWise, **Actions (Internal Notes)** on HaloPSA, and **Work Notes** on ServiceNow and Syncro. The settings below live on that permission group. ## What It Does When enabled, the agent can: * Record investigation and troubleshooting steps for the next technician * Capture triage findings and recommended next steps * Keep a consistent, agent-attributed internal audit trail The note body is automatically prefixed with the agent's identity (`Agent: [id] name`) so your team can tell Neo's notes apart from technician and contact activity, and the tool returns the ID your PSA gave the new note. ServiceNow does not report one for a work note, so there the ID is empty. **In test mode this tool writes nothing.** Test mode disables every PSA write for the whole run, internal notes included — the call comes back marked `[TEST MODE]` and simulated, and nothing lands on the ticket. The agent still adds the notes its job calls for, and each one is simulated; it does not use an internal note to record what test mode blocked. Neo stages the writes it would have made and shows the whole set in the run's output when the run ends, together with the agent's run summary — so the agent's findings still reach the ticket when **Report test results via** is set to an internal note. Where else that report goes depends on the agent's **Report test results via** setting — see the [Configuration reference](/core/configuration-reference). ## Feedback link Turn on **Ask for Feedback** on your PSA's internal-notes permission group to add a feedback link to each internal note Neo writes. Technicians use it to rate the agent's work. An agent that still has **Add Internal Note** in its tool list from before uses that entry's settings instead of the permission group's. ## HaloPSA outcome On HaloPSA, **Outcome for Neo's Notes** on the **Actions (Internal Notes)** group sets the outcome Neo's own internal notes use. The list shows only outcomes that do not email the customer, and the choice must also be one of the group's **Allowed Outcomes**. If it is empty or not allowed, Halo's default is used. ## Autotask note type & publish On Autotask you can pin a dedicated **Note Type** and **Publish** value for Neo's internal notes, on the **Ticket Notes (Internal)** permission group. This lets your Autotask workflow rules recognise Neo's notes distinctly from real technician or contact activity. Publish is constrained to internal-only values, so these notes never become client-facing. ## Best Practices * Use internal notes to leave a durable record of what the agent found and did, especially when a follow-up action was blocked or deferred. * For anything the end user should see, use [Add Client-Facing Note](/agents/tools/communication/add-client-facing-note) instead — internal notes are never delivered to the customer. * If you need Neo's internal notes tagged with a specific Autotask note type for your workflow rules, configure the note type on the Ticket Notes permission group. * For how each PSA separates client-facing notes from internal ones, see [End-User Communication](/integrations/psa/end-user-communication#how-neo-reaches-the-end-user). # Read Teams Channel Messages Source: https://docs.neoagent.io/agents/tools/communication/read-teams-channel-messages Let an agent read recent posts from your team's own Teams channels while it works a ticket The Read Teams Channel Messages tool lets an agent read what your team has posted in a Teams channel. Use it when the answer to a ticket lives in a channel rather than in your PSA: a channel where staff post client travel, planned maintenance, or known issues. For example, a security agent that gets an impossible-travel sign-in alert can check your **Travel Notifications** channel for a trip by that user. If it finds one, it notes the post, with a link to it, on the ticket. ## What It Does When enabled, the agent can: * Read posts, with their replies, from the channels you pick, up to 14 days back * Narrow the read to posts that mention a name or other text * Link to each post it uses, so a technician can open the source in Teams The agent reads a channel only when it decides the channel is relevant to the ticket. It cannot post in the channel with this tool; posting is the [Send Teams Message](/agents/tools/communication/send-teams-message) tool. ## Setup A team owner adds the **Neo AI Agent** app to the team that holds the channel: in the team, open `···` → **Manage team** → **Apps** → **More apps** → find **Neo AI Agent** → **Add**. Teams asks the owner to allow the app to read the team's messages. Accept it. This is the same step as for [posting to a channel](/integrations/teams/intro#post-to-a-teams-channel-or-chat). If the app is already in the team, you do not add it again. In the agent's **Tools** tab, turn on **Read Teams Channel Messages** and pick the channels under **Channels Neo can read**. The agent can read only the channels you pick. There is no "any channel" option. Say in the agent's instructions which channel to check, and when. For example: > Before you escalate an impossible-travel or unusual sign-in alert, read the Travel Notifications channel for the last 14 days and look for a trip by that user. **Which channels appear in the picker.** The picker lists the channels of every team the **Neo AI Agent** app is in. A **private** channel appears after Neo first sees a post in it. A team that uses a branded (white-label) Neo app instead of **Neo AI Agent** cannot be read yet. ## If a channel cannot be read The agent reports why in its run, and it continues with the ticket: * **"Neo cannot read this channel yet"**: Neo has not seen activity in that team since channel reading was added. It can read the channel after the next post in any channel of that team. * **"Microsoft refused the read"**: the team owner did not accept the app's permission to read the team's messages. Remove the **Neo AI Agent** app from the team and add it again, and accept the permission prompt. ## Privacy Neo reads a channel only during a run of an agent that has the tool and has that channel on its list. Neo does not index your channels or read them outside a run. The posts an agent reads stay in that run's history, like the result of any other tool. ## Credits The tool is in the Standard tier: 2 credits. On a scheduled or chat agent, each call costs 2 credits. On a ticket-triggered agent, the tool makes the price of each run at least 2 credits. See [Credit Costs](/agents/tools/credit-costs). # Send Email Source: https://docs.neoagent.io/agents/tools/communication/send-email Email your own team, and when you allow it, any other address, from Neo's mailbox Use Send Email for a report, an alert or an approval request that must reach a person's inbox. The addresses you list in the tool's settings are always allowed, and the **Approval** switch covers only other addresses. Prefer **Add Client-Facing Note** or **Add Time Entry** for talking to the ticket contact when your PSA delivers those as email, because they keep the conversation on the ticket. Use Send Email when there's no PSA contact for the address, or your PSA doesn't email notes out. ## What It Does When enabled, the agent can: * Email the recipients it names: one recipient, and other addresses copied on the same email as visible CC recipients. To email your whole team, the agent names each address * Compose the subject and body from the ticket, the data it gathered and your custom instructions * Send with or without a ticket, so a scheduled agent can email its report * Send from Neo's address `notifications@notify.neoagent.io`; replies go to `neo.workflows@neoagent.io` An email is one-way: a reply never reaches the agent or resumes the run. ## Who the agent may email Three settings decide it: | Setting | What it does | | - | - | | **Your team's addresses** | Neo may always email these addresses, and the **Approval** switch does not apply to them. The agent is told who is on the list, so an instruction such as "email the daily brief to Lee" reaches Lee through it. | | **Email other addresses** | On by default. Lets the agent email addresses that are not in the list, for example a ticket's contact or the assigned technician. Turn it off to limit the agent to the list. | | **Approval** (the switch on the tool's row) | Applies only to addresses that are not in the list. The agent asks a technician before it emails one, and the approval covers that recipient. | An agent with **Email other addresses** off needs at least one address in the list, or the agent cannot be enabled. **If you used Send Email to Internal Team.** That tool is now part of Send Email. An agent that had only Send Email to Internal Team now has Send Email with the same addresses, **Email other addresses** off and no approval, so it emails the same people as before. An agent that had both tools keeps its Send Email settings, and its internal-team addresses become **Your team's addresses**, which the **Approval** switch does not cover. ## Subject Line and Ticket Link The agent can write a short subject for each email, for example "Approval needed: mailbox access for Alex Morgan". The subject can use these variables, which fill in per ticket: `{workflow_id}`, `{workflow_name}`, `{ticket_number}`, `{ticket_title}`, `{company}`. To control the wording, say what the subject must contain in your custom instructions. When the agent writes no subject, the subject depends on who receives the email: * **Your own team**: the standard workflow notification subject, `Notification from a workflow: [] `. When the email is about a ticket, the subject adds `| Ticket | Title: | Company: <company>` and the email opens with a link to the ticket in your PSA. An email goes to your own team when each recipient and CC is in **Your team's addresses** or on your company's email domain, which Neo learns from the dashboard users who can sign in. Neo ignores common free-mail domains such as Gmail and Outlook.com when it learns your domain. * **Anyone else**, such as an approver at your client, or an email that copies one: the ticket number and title, for example "Ticket T20260101.0001: New user account". Neo does not add your agent's name or id to the subject, and does not add a link to the ticket in your PSA, because the recipient cannot open it. An email to someone else with no ticket must have a subject from the agent. ## CC Recipients The agent can copy additional people on the email with a real CC header: all recipients receive one email and see who else was copied. CC recipients are shown in the technician approval preview when approval applies, so the reviewer sees exactly who is copied before the email goes out. ## Body Formatting & Attachments Email bodies are written in Markdown and rendered to HTML before sending, including Markdown tables, which arrive as real formatted tables. The tool itself does not take attachments. For reports that need an exact, fully-styled HTML body (for example a branded template) or file attachments, have the agent send from its code sandbox: * `neo.client.send_email(...)` emails one recipient and accepts `cc=[...]`, so the agent names each address it emails. It accepts `attachments=[...]` (sandbox file paths) and `content_type="html"`, which sends the body verbatim with no Markdown conversion. It follows the same rules as the tool: the listed addresses always, other addresses only when **Email other addresses** is on. A sandbox script cannot ask for approval, so an email that needs approval is refused there, and the agent sends it with the tool instead, which carries no attachments. ## Test reports by email When an agent in test mode reports **Email to internal team**, Neo sends the report to **Your team's addresses**, so the agent needs Send Email with at least one address in the list. When you turn on test mode with that option and the agent has no Send Email yet, the dashboard adds Send Email limited to the list. Add at least one address before you save. ## Safety | Control | Behavior | | - | - | | **Your team's addresses and Email other addresses** | Decide who the agent can reach at all | | **Approval** | Asks a technician before any email to an address that is not in the list | | **Test mode** | The agent drafts the email but doesn't send it | | **Custom instructions** | Define tone, signature, and when the agent should email versus add a ticket note | ## How to Use 1. Enable the tool on your agent. 2. List your own people in **Your team's addresses**. 3. Choose whether the agent may email other addresses, and use the **Approval** switch to decide whether those emails need a technician's approval. 4. Provide custom instructions on who to email, voice, signature, and when to use email instead of a ticket note. ### Example Instructions ``` Email the requester's manager when an offboarding completes — confirm the account is disabled, mailbox converted to shared, and licenses reclaimed. Keep it brief and professional, signed "IT Support". ``` <Tip> Follow the [Teams channel & chat notifications guide](/integrations/teams/intro#post-to-a-teams-channel-or-chat) to also notify via Teams channels and chats. </Tip> # Send Slack Message Source: https://docs.neoagent.io/agents/tools/communication/send-slack-message Notify your internal team in a Slack channel through the Neo Slack bot The Send Slack Message tool lets Neo Agent post a notification to one of your Slack channels, using the same Neo Slack app your workflows already use. Neo posts through the tenant's Slack bot token, so the message shows the standard notification header and a link to the related ticket. ## What It Does When enabled, the agent can: * Post to a Slack channel the Neo Slack bot has been added to * Notify your team about urgent issues or share ticket updates This is a one-way notification. Replies in Slack do not come back to the agent and do not resume the run. To ask the ticket contact something, use the client-facing ticket note; for a technician decision, use technician approval. <Tip> **Setup Required:** Follow the [Slack integration guide](/integrations/slack/intro) to create the Neo Slack app, add it to a channel, and share the bot token with your Neo administrator. </Tip> ## Choosing the channels the agent can post to List the Slack channel IDs Neo may post to. Neo can post only to the channels you list, and the list must hold at least one channel. If the agent asks for a channel that is not on the list, the tool returns an error and the agent can retry with an allowed channel. To find a channel ID: 1. Open the channel in Slack. 2. Choose **View channel details**. 3. Copy the **Channel ID** at the bottom of the **About** tab. It looks like `C1234567890`. Add the Neo Slack bot to every channel you list, or the post fails. # Send SMS Source: https://docs.neoagent.io/agents/tools/communication/send-sms Send text messages to end users The Send SMS tool allows Neo Agent to send text message updates directly to end users' mobile phones. ## What It Does When enabled, the agent can: * Send SMS notifications to end users * Follow up on tickets via text message * Notify users about urgent issues or status updates * Communicate with users who prefer or need SMS updates ## How to Use The agent will automatically use the phone number from the ticket contact or you can specify a different recipient. All phone numbers must be in E.164 format (e.g., +15551234567). ## Best Practices <AccordionGroup> <Accordion title="Keep messages concise"> SMS messages should be brief and professional. The agent will create appropriately short messages, but you can guide this with custom instructions. </Accordion> <Accordion title="Use for urgent communications"> SMS is best for time-sensitive updates where immediate notification is valuable, such as outage alerts or critical ticket updates. </Accordion> <Accordion title="Verify phone numbers"> Ensure phone numbers in your PSA are accurate and properly formatted. Invalid numbers will cause delivery failures. </Accordion> <Accordion title="Respect opt-out preferences"> Make sure you have user consent for SMS communications and respect any opt-out requests per your compliance requirements. </Accordion> </AccordionGroup> ## Settings * **Require Technician Approval**: When enabled, the agent must request approval before sending each SMS * **Phone Number Format**: All numbers must use E.164 international format with country code (e.g., +1 for US/Canada) <Note> SMS delivery depends on the recipient's mobile carrier. Check your SMS provider logs for delivery confirmation and troubleshooting. </Note> ## Use Cases * **Critical Outage Notifications**: Alert VIP users about service disruptions via text when email may not be checked quickly * **Appointment Reminders**: Send reminders about scheduled maintenance windows or on-site visits * **Urgent Ticket Updates**: Notify users of time-sensitive changes requiring immediate attention * **Out-of-Band Verification**: Contact users when their primary email may be compromised or unavailable # Send Teams Message Source: https://docs.neoagent.io/agents/tools/communication/send-teams-message Notify internal team members and Teams channels or chats via Microsoft Teams The Send Teams Message tool lets Neo Agent notify your internal team through Microsoft Teams — either as a **direct message** to individual technicians, or as a **post to a Teams channel or group chat** the Neo app is in. ## What It Does When enabled, the agent can: * Direct-message individual team members * Post to a Teams channel or group chat (see [Post to a Teams channel or chat](/integrations/teams/intro#post-to-a-teams-channel-or-chat)) * Notify technicians about urgent issues, request input, or share ticket updates <Tip> **Setup Required:** Follow the [Teams integration guide](/integrations/teams/intro#install-the-app) to allow Neo to send messages in Teams. </Tip> ## Controlling who the agent can notify The tool has two independent scopes so you decide exactly where the agent may send: * **Users** — *Any* (any user who installed the Neo app, the default), *Only specific* (a chosen list), or *Disabled* (never DM anyone). * **Channels & chats** — *Disabled* by default, so posting to a channel is opt-in; switch to *Any* (any channel/chat the app is in) or *Only specific* (a chosen list). Because the two are independent, you can model any combination — e.g. specific users but no channels, only a single `#alerts` channel and no DMs, or any mix. At least one of the two must be enabled. ## The agent picks the recipient per run The scopes above are a permission, not a fixed recipient list. The agent chooses which people and which channels or chats each individual message goes to, from everything the scopes allow, using what it knows about that ticket. So one agent can send each escalation to the chat that belongs to whoever the ticket is assigned to, without a separate agent per person. The agent can address a person by name, for example the technician named on the ticket. The name must match exactly one Teams user the scopes allow. Neo never guesses between similar names. When a name does not match, the agent looks up the allowed list and picks from it. When a scope is *Only specific* and you pick up to 50 entries in the dashboard, the agent is told your chosen list at the start of every run, so it needs no lookup. A longer list is looked up when needed. An instruction such as "send to the users set in the Teams tool" reaches every person on that list; an instruction that names one person still reaches only that person. If you use [Teams Technician Mapping & Availability](/integrations/teams/workforce-availability), that list also shows the PSA technician, or technicians, each mapped Teams user belongs to. The agent can then message the technician on the ticket through that link, which is what an instruction such as "notify the assigned technician through the technician-to-Teams mapping" needs. This is the difference from the [Notify Internal Team action](/building-automations/actions/notify/notify-internal-team) on a fixed-step workflow, where the recipients are chosen when you build the workflow and every run notifies the same set. If you need the destination to depend on the ticket, use an agent with this tool rather than a fixed-step workflow. # Send to Additional Contact Source: https://docs.neoagent.io/agents/tools/communication/send-to-additional-contact Send messages to additional contacts on tickets The Send to Additional Contact tool allows Neo Agent to message additional contacts associated with a ticket, such as IT managers or admins. <Info> Enabled automatically when you grant your PSA's client-facing notes permission group at Read / Write **and** turn on its **Allow Notify Additional Contacts** toggle — there's no separate toggle in the tool list. The group is **Ticket Notes (Client-Facing)** on Autotask and ConnectWise, and **Actions (Client-Facing Notes)** on HaloPSA. ServiceNow and Syncro do not carry that setting, so this tool is unavailable on them. </Info> ## What It Does When enabled, the agent can: * Identify additional contacts to notify * Send messages to contacts beyond the primary ticket contact * Automatically add contacts to tickets if needed <Tip> In custom instructions, tell Neo how to identify contacts to notify. Example: "Notify the IT Manager or admin for this company." </Tip> ## How to Use Use this tool when you need to notify someone other than the primary ticket contact: ``` Notify the IT administrator when security-related tickets are created. CC the department manager on high-priority tickets. ``` # Tool credit costs Source: https://docs.neoagent.io/agents/tools/credit-costs What each agent tool costs, and how ticket-triggered, scheduled, and chat agents spend credits differently A tool's tier sets its price. What changes is **when** you pay: once per run, or once per call. On a per-call agent, an integration API tool also prices by what the call did. | How the agent starts | What you pay | Typical use | | - | - | - | | **Ticket- or entity-triggered** | The highest tier among the tools *you chose*, **once per run**. The agent can call those tools as many times as it needs. Tools Neo adds for every agent (searches, sandbox, and similar) do **not** set this price. Nor does the Request Technician Approval tool when [Supervised mode](/core/supervised-mode) is what put it there, because a supervised agent cannot run without it. An agent that had that tool before Supervised mode keeps paying for it. A run never bills 0 — the floor is 1 credit. | A ticket arrives; the agent works that ticket. | | **Scheduled, with no ticket** | Each tool call at its per-call price. Ten 3-credit calls cost 30. A run whose tools are all free still bills **1 credit**. | A cron job: weekly report, M365 audit, account hygiene. | | **Internal chat** | Same as a ticketless scheduled agent: **per tool call**. A turn that calls no billable tool costs **0**. | A technician asks a question in the dashboard or Teams. | | **End-user Teams bot** | Not credits. Priced [per client company](/chat-agents/sessions-and-billing#end-user-teams-bot-pricing). | Your clients' employees message the branded bot. | Workflows that use smart actions (triage, dispatch, and similar) are separate: they bill **1 credit per ticket** they work, not by tool tier. See [Billing & credits](/product/billing-and-credits#how-credits-are-spent). <Warning> The **Built-in Capabilities** list on an agent (Skills and the always-on tools) does **not** show credit costs. Skills are free to load. The tools a skill tells the agent to call still bill at the rates below. **External API Request** is 3 credits per call on a scheduled or chat agent, even though **Neo API** is free and the API *skills* sit in that list with no price. </Warning> ## Worked example A scheduled agent builds a weekly open-ticket summary and posts it to Teams. One run calls: | Call | Tier | Credits | | - | - | - | | Find Tickets by Content × 3 | Standard | 6 | | Sandbox Bash × 2 | Standard | 4 | | Send Teams Message to Internal Team × 1 | Standard | 2 | | **This run** | | **12** | The same toolbox on a **ticket-triggered** agent would bill **2 credits for the whole run** (Standard is the highest chosen tier; the always-on searches do not set the per-run price). That is why a scheduled agent that looks cheap in the builder can spend hundreds of credits while you iterate. Building the procedure as a [custom skill](/agents/skills/custom-skills) with [Neo Support](/chat-agents/neo-support-agent) is free, unless Neo Support reads your own systems to do it. Running the scheduled agent — including test-mode runs — spends credits. ## Tiers | Tier | Credits per call (scheduled / chat) | Credits it can set on a triggered run | | - | - | - | | **Free** | 0 | Never raises the per-run price | | **Basic** | 1 | 1 | | **Standard** | 2 | 2 | | **Advanced** | 3 | 3 | Integration API tools price in two ways: * **On a triggered run**, the tier follows the access you grant: **Standard** when every enabled permission group is Read Only, **Advanced** when any group is Read / Write. * **Per call**, the price follows what the permission check decided the call is. A read costs at most **Standard (2)**. A write costs **Advanced (3)**, also when test mode blocks it or it waits for technician approval; the approved retry is a second call and bills again. A read is a GET, or a query-only call such as an Autotask `/query`. A call the permission check refuses is neither, and costs the tool's own tier. Microsoft Graph is the exception: every call costs **3**, read or write. PowerShell tools are always Advanced. [Neo API](/agents/tools/management/neo-api) stays Free at every permission level. ## Skills are not tools [Skills](/agents/skills/overview) are procedures the agent loads. **Load Skill** is Free. The Built-in Capabilities panel lists both: * **Skills** — Resolve Issue, MS Graph API, Autotask API, Neo API, and the rest. Loading any of these costs 0. * **Tools** — Find Documentation, Sandbox Bash, Generate Password, and the rest. Those have the tiers in the tables below. An "MS Graph API" *skill* teaches the agent how to use Graph. A Microsoft Graph *call* still costs 3 credits on a scheduled or chat agent. ## Test mode still bills Test mode blocks writes. It does not stop the agent calling tools, and those calls still spend credits — reads go through, and a simulated write still counts as a call. Check spend on [Billing](https://dashboard.neoagent.io/billing) or [Performance & Cost](/product/analytics) while you iterate. ## Integration API tools These turn on from the agent's **Integrations** tab. There is no separate toggle. The matching *skill* in Built-in Capabilities is free to load; each API call bills as below. | Tool | Per call: read | Per call: write | Triggered run | | - | - | - | - | | PSA API (ConnectWise, Autotask, Halo, ServiceNow, Syncro) | 2 | 3 | 2 Read Only / 3 Read / Write | | RMM API (NinjaOne, Datto, N-Sight, N-Central, ConnectWise Automate, ConnectWise Asio, ScreenConnect, Kaseya VSA X, Syncro, Addigy) | 2 | 3 | 2 Read Only / 3 Read / Write | | Microsoft Graph API | 3 | 3 | 2 Read Only / 3 Read / Write | | IT Glue, Hudu, Lexful, Confluence, SharePoint | 2 | 3 | 2 Read Only / 3 Read / Write | | Huntress, ThreatLocker, ScalePad, Ubiquiti UniFi, AutoElevate, Proofpoint Essentials, Hornetsecurity, Mimecast, SentinelOne, Wizer, Datto BCDR, BeyondTrust EPM, CIPP, Domotz, SaaS Alerts, Auvik, Cisco Meraki, ConnectWise CPQ, QuoteWerks, Datto EDR, WatchGuard, Duo, CyberQP, TP-Link Omada, OpenText Secure Cloud, Zabbix, CentralReach, Sophos | 2 | 3 | 2 Read Only / 3 Read / Write | | Uniview, Kaseya Quote Manager, RoboShadow, myITprocess (read-only) | 2 | — | 2 | | [External API Request](/agents/tools/management/external-api-request) | 3 | 3 | 3 | | [Neo API](/agents/tools/management/neo-api) | Free | Free | Free | ## Tools you enable | Tool | Credits | | - | - | | Trigger or Schedule Workflow | 1 | | Create TimeZest Scheduling Link | 2 | | Add Time Entry | 2 | | Add Internal Ticket Note | 2 | | Attach File to Ticket | 2 | | Get Technician Context | 2 | | Add Client-Facing Ticket Note | 3 | | Send Email | 2 | | Send Teams Message to Internal Team | 2 | | Send Slack Message to Internal Team | 2 | | [Read Teams Channel Messages](/agents/tools/communication/read-teams-channel-messages) | 2 | | Send Message to Ticket's Additional Contact | 3 | | Send SMS | 3 | | Execute RMM Script | 3 | | Find RMM Scripts | 3 | | Get RMM Script Result | 1 | | Wait for RMM Script | 1 | | Execute PowerShell (Exchange) | 3 | | Execute PowerShell (Active Directory) | 3 | | Trigger Azure AD Connect Sync | 3 | | Change License Seats / List License Subscriptions | 3 | | Web Search | 3 | | Web Fetch | 1 | | Request Technician-in-the-Loop Approval | 3 | | [External API Request](/agents/tools/management/external-api-request) | 3 | ## Always-on tools Neo adds these to every agent. On a **triggered** agent they never set the per-run price. On a **scheduled or chat** agent, each call bills at the tier below. | Tool | Credits | | - | - | | Find Documentation | 2 | | Find Tickets by Content | 2 | | Find Configurations / Devices | 2 | | Find PSA Contacts | 2 | | Sandbox Bash | 2 | | Get Ticket Summaries | 1 | | List End Client Companies | 1 | | Get Synced Devices | 1 | | Generate Password | 1 | | Generate Secure Link for given content | 1 | | Sandbox Read File | Free | | Sandbox Write File | Free | | Delay | Free | | Lookup Available | Free | | Recall Memory | Free | | Business Hours Elapsed & Chase Timing | Free | | Get Field Options | Free | | Load Skill | Free | Create Subagents is Standard (2) when the agent fans work out. See [Subagent fan-out](/agents/tools/built-in/dispatch-subagents). ## Free tools A Free tool costs 0 on every agent you own. The [Neo Support Agent](/chat-agents/neo-support-agent) is the same Chat Agent in the dashboard and in the Neo AI Agent Teams app. Its work on Neo itself is free: explaining, debugging or changing your agents, and building or editing skills. Its work on your own systems bills at the rates on this page, for example a PSA, RMM, Microsoft 365 or documentation call, or a search over your synced tickets. A few tools are tagged as support tools. They are Free **only** on Neo Support. On your own chat or scheduled agent they bill at the tier in the tables: Sandbox Bash is 2, Web Fetch is 1, Request Technician Approval is 3. See [Billing & credits](/product/billing-and-credits) for plans, top-up, and what happens when you hit the monthly limit. # Confluence API Source: https://docs.neoagent.io/agents/tools/documentation/confluence-api Read, create, update, and search Atlassian Confluence (Cloud) content during ticket resolution The Confluence API tool gives Neo agents direct access to the Atlassian Confluence Cloud REST API — list spaces, fetch and edit page content, manage attachments, search with CQL, and create new pages on behalf of customers. <Info> Automatically enabled when you configure Confluence permissions in your agent workflow. No manual toggle needed. See the [Confluence integration page](/integrations/documentation/confluence) for connection setup. </Info> ## What It Does * List spaces (knowledge bases, global, personal) * Fetch full page content in storage XHTML or Atlassian Document Format (ADF) * Create, update, and delete pages and blogposts * Manage attachments on pages and blogposts (upload, delete) * Add, update, or remove labels on pages and spaces * Create comments on pages * Look up users (resolve `@mentions` and author IDs to display names) * Run CQL (Confluence Query Language) searches across all content the agent can see ## Permission Groups Each group can be set to **Disabled**, **Read Only**, or **Read/Write**. When set to Read/Write, an additional **Allow Delete** toggle controls whether the agent can issue DELETE requests on that group. | Permission Group | What It Covers | Atlassian Scopes | | - | - | - | | **Pages** | Pages and blogposts — body content, version history, parent/child links, page labels and comments | `read:page:confluence`, `write:page:confluence`, `write:comment:confluence`, `write:label:confluence` | | **Spaces** | Space metadata and listing | `read:space:confluence`, `write:space:confluence` | | **Search** | CQL search across pages, blogposts, attachments, and spaces (read-only by API design) | `read:content-details:confluence` | | **Attachments** | Files attached to pages and blogposts (metadata, download, upload, delete) | `read:attachment:confluence`, `write:attachment:confluence` | | **Users** | User profiles referenced by content authors and mentions (read-only by API design) | `read:user:confluence` | ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All five groups Read Only. The agent can browse anything the connecting OAuth user has Confluence permission to see — but cannot make changes. The typical setting for documentation-aware ticket-resolution agents. </Accordion> <Accordion title="Documentation Manager"> Pages and Attachments **Read/Write**; Spaces, Search, and Users Read Only. The agent can create and update pages and upload attachments — ideal for agents that maintain runbooks and client documentation autonomously — but cannot restructure spaces or delete records. </Accordion> <Accordion title="Full Access"> All five groups Read/Write with **Allow Delete** enabled. The agent can create, update, and delete pages, blogposts, comments, labels, and attachments. Whole-space DELETE is still structurally blocked (see Safety Controls). </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Whole-space DELETE blocked** | Even with Full Access + Allow Delete, the agent cannot delete a Confluence space — orphans every page, blogpost, attachment, and comment inside. Rejected at the permission layer regardless of OAuth scope. | | **Allow Delete is per-group, opt-in** | Setting a group to Read/Write does not allow deletes by default. The agent can create and update but not delete unless you explicitly enable the per-group Allow Delete toggle. | | **Reads never trigger approval** | GET requests pass through without technician-in-the-loop checks. Each group has a separate `Require Approval` toggle if you want writes to go through a human first. | | **Rate-limit handling** | The Confluence client paces itself when Atlassian signals `NearLimit` (response header indicating under 20% of the hourly budget remaining) and retries 429s with the `Retry-After` window. | | **Response size guard** | Responses larger than 500 KB are rejected with a hint to narrow the query (smaller `limit`, tighter CQL filter, or `body-format=storage` instead of `atlas_doc_format`). | ## How to Configure <Steps> <Step title="Connect Confluence"> [Connect Confluence](/integrations/documentation/confluence) from the Neo dashboard. The flow is a single click + Atlassian consent — no developer app to register. </Step> <Step title="Configure permissions on the agent"> In your agent workflow's **Integrations** tab, choose an access profile (Read Only, Documentation Manager, Full Access) or customize each permission group individually. </Step> </Steps> <Tip> Start with **Read Only** when you just need an agent that surfaces documentation during ticket resolution. Move to **Documentation Manager** when you want the agent to maintain its own runbooks. Only enable **Full Access** + Allow Delete after validating the agent's write behavior on a test workflow first. </Tip> # Hudu API Source: https://docs.neoagent.io/agents/tools/documentation/hudu-api Read and write Hudu resources — articles, assets, asset layouts, companies, passwords, infrastructure, and more The Hudu API tool gives Neo agents direct access to the Hudu REST API — read, create, update, and delete Hudu resources during ticket resolution. <Info> Automatically enabled when you configure Hudu permissions in your agent workflow. No manual toggle needed. See the [Hudu integration page](/integrations/documentation/hudu) for the full permission model. </Info> ## What It Does * Look up companies, articles, assets, and procedures * Create and update knowledge base articles based on ticket resolutions * Flag new articles for technician review * Manage asset records and their structured fields * Browse asset layouts (schemas) and documentation folders * Read and manage network infrastructure documentation — networks, VLANs, IPAM, racks * Retrieve passwords (with technician approval) * Access any Hudu API endpoint with permission-group-based access control ## Permission Groups | Permission Group | What It Covers | | - | - | | **Companies** | Companies, relations, activity logs, matchers, integration cards, flags and flag types | | **Articles** | Knowledge base articles, procedures, uploads, public photos | | **Assets** | Asset records — structured data entries created from asset layouts | | **Asset Layouts** | Asset layout definitions — the schemas that define asset structure | | **Passwords** | Asset passwords and password folders | | **Folders** | Documentation folders for organizing articles | | **Infrastructure** | Networks, VLANs, VLAN zones, IP addresses (IPAM), rack storages | | **Websites** | Monitored website entries — uptime and SSL tracking | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. <Note> Hudu can ignore the draft setting on an article an agent creates, so the agent cannot confirm that the article is a draft. To have the agent mark new articles for review, create a flag type in Hudu (for example **Needs Review**), set **Companies** to **Read/Write**, because Hudu flags sit in that group, and tell the agent in its instructions to flag each new article for review. You find the flagged articles on Hudu's Flag Review page. </Note> ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. Agent can look up any resource but cannot modify. </Accordion> <Accordion title="Documentation Manager"> Articles, Assets, Folders, and Websites at Read/Write. Everything else Read Only. </Accordion> <Accordion title="Full Access"> All groups Read/Write with delete enabled. Password writes still require technician approval; company deletion is always blocked. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes — configurable per group | | **Password protection** | All password writes always require approval, regardless of settings | | **Company safety** | Agents can never delete companies | | **Delete control** | Delete permissions off by default, must be explicitly enabled per group | ## How to Configure <Steps> <Step title="Connect Hudu"> [Connect your Hudu instance](/integrations/documentation/hudu) with an API key in the Neo Dashboard. </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Decide which permission groups require technician approval for writes. </Step> </Steps> <Tip> Start with **Read Only** and gradually expand. Enable Technician-in-the-Loop for writes until you're confident in the agent's behavior. </Tip> # ITGlue API Source: https://docs.neoagent.io/agents/tools/documentation/itglue-api Read and write IT Glue resources — documents, configurations, flexible assets, contacts, passwords, and more The ITGlue API tool gives Neo agents direct access to the full IT Glue REST API — read, create, update, and delete any IT Glue resource during ticket resolution. <Info> Automatically enabled when you configure ITGlue permissions in your agent workflow. No manual toggle needed. </Info> <Tip> Neo resolves each IT Glue organization to its PSA company ahead of time, so agents read organizations by **ID** rather than an unreliable name search (IT Glue's `filter[name]` can't match punctuated names like "Tool Supply, Inc."). See [Company Mapping](/product/company-mapping) to view and correct those mappings. </Tip> ## What It Does * Look up organizations, contacts, configurations, and documentation * Read SSL certificate records — issuer, expiry date, host, and notes — for renewal reporting * Create and update documents based on ticket resolutions * Manage flexible assets and their custom fields * Retrieve passwords (with technician approval) * Update configuration items and interfaces * Copy a file attached to a PSA ticket into IT Glue, as a document image or an attachment (Autotask today) * Access any IT Glue API endpoint with permission-group-based access control ## Copying PSA Attachments Into IT Glue IT Glue accepts a file only as encoded text inside the request. The agent does not write that text itself. It names the PSA ticket and attachment, and Neo reads the file from the PSA and sends the exact bytes to IT Glue. Files over 10 MB are refused. This is how an agent puts a ticket screenshot into a knowledge-base article, or attaches a ticket's PDF to a configuration. * Works for Autotask ticket attachments, including files on notes and time entries. * The agent needs read access in its Autotask **Attachments** permission group, the same access it needs to read the file itself. * For other PSAs, the agent tells you to add the file in IT Glue by hand. ## Permission Groups | Permission Group | What It Covers | | - | - | | **Organizations** | Organizations, locations, domains, SSL certificates, related items | | **Contacts** | Contacts and contact types | | **Documents** | Documents, folders, sections, images, checklists, attachments | | **Flexible Assets** | Flexible asset records | | **Flexible Asset Types** | Asset type schemas and field definitions | | **Configurations** | Configuration items, types, statuses, interfaces | | **Passwords** | Passwords, folders, and categories | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. Agent can look up any resource but cannot modify. </Accordion> <Accordion title="Documentation Manager"> Documents, Flexible Assets, and Contacts at Read/Write. Everything else Read Only. </Accordion> <Accordion title="Full Access"> All groups Read/Write with delete enabled. Password writes still require technician approval. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes — configurable per group | | **Password protection** | All password writes always require approval, regardless of settings | | **Organization safety** | Agents can never delete organizations | | **SSL certificates read-only** | Agents can read SSL certificate records but never create, edit, or delete one, even at Read/Write | | **Delete control** | Delete permissions off by default, must be explicitly enabled | ## How to Configure <Steps> <Step title="Connect IT Glue"> [Connect your IT Glue API key](/integrations/documentation/itglue-api) in the Neo Dashboard. </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Decide which permission groups require technician approval for writes. </Step> </Steps> <Tip> Start with **Read Only** and gradually expand permissions. Enable Technician-in-the-Loop for writes until you're confident in the agent's behavior. </Tip> # Lexful API Source: https://docs.neoagent.io/agents/tools/documentation/lexful-api Read and write Lexful resources — organizations, asset types, documentation assets, file attachments, and tags The Lexful API tool gives Neo agents direct access to the Lexful REST API — read, create, update, and delete Lexful records during ticket resolution. <Info> Automatically enabled when you configure Lexful permissions in your agent. No manual toggle needed. </Info> ## What It Does * Look up customer organizations and the documentation stored against them * Read documentation pages, configurations, contacts, and locations — including custom asset types you've defined * Create and update documentation from ticket resolutions * Read asset type schemas to understand what each kind of record holds * Download file attachments when the answer lives in an attached diagram or export * Access any Lexful API endpoint with permission-group-based access control <Tip> For "what do we know about X", Neo's own **Find Documentation** tool is usually the better first stop — Neo syncs your Lexful documentation into its search index daily, and that search spans every documentation source you've connected. Reach for the Lexful API tool when you need something the sync doesn't carry: a live value, a non-document asset type, file attachments, or a write. </Tip> ## Permission Groups | Permission Group | What It Covers | | - | - | | **Organizations** | Customer organizations, their hierarchy and website domains, plus the account user directory | | **Asset Types** | Asset type definitions — which properties each kind of record carries | | **Assets** | The records themselves: documentation, configurations, contacts, locations, custom types | | **Asset Files** | File attachments on assets — metadata, download, upload | | **Tags** | Tags used to classify assets | | **Search** | Lexful's own cross-entity search | | **Secure Properties** | Retrieving a stored secret or TOTP code in plaintext | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. Secure Properties is read-only by design — storing a secret happens through **Assets** like any other property. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only, except Secure Properties which stays off. The agent can look up any record but cannot modify anything or read a stored secret. </Accordion> <Accordion title="Documentation Manager"> Assets, Asset Files, and Tags at Read/Write — the surfaces where documentation lives. Organizations, Asset Types, and Search stay Read Only. Secure Properties stays off. </Accordion> <Accordion title="Full Access"> Every group Read/Write with delete enabled, except organizations and asset types (which can never be deleted). Secure Properties still stays off — reading credentials in plaintext is always a separate, deliberate decision. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Secrets are masked** | Secret and TOTP values come back as `<secure>` on every ordinary read, so an agent reading documentation never sees a credential by accident | | **Reading a secret needs its own permission** | Plaintext comes only from two endpoints, both behind the Secure Properties group — the same way ITGlue and Hudu gate their Passwords group | | **Storing a secret always needs approval** | Lexful has no separate "save a password" endpoint, so Neo inspects the request itself and asks a technician to approve any write that sets a credential | | **Secrets are off by default** | Secure Properties is in no access profile; an admin has to enable it deliberately | | **Structural safety** | Agents can never delete an organization or an asset type — both would take every record beneath them | | **Recoverable deletes** | Asset deletes are soft and restorable, and are off unless you enable them per group | | **Technician-in-the-Loop** | Require human approval for writes — configurable per group | | **Historical secrets** | Past values of a rotated credential sit behind the same Secure Properties group, never behind ordinary record access | | **Authentication is Neo's** | Neo mints and caches the access token; auth endpoints are blocked to the agent | ## How to Configure <Steps> <Step title="Connect Lexful"> Connect your Lexful account in the Neo Dashboard's **Integrations** page with your API key ID, secret, and account ID. </Step> <Step title="Configure permissions"> In your agent's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Decide which permission groups require technician approval for writes. Writes that set a credential always require approval, whatever you choose here. </Step> </Steps> <Warning> Only enable **Secure Properties** if an agent genuinely needs to read stored credentials — including the historical values of rotated ones. It is in no access profile, so leaving it alone means the capability isn't there at all. </Warning> # SharePoint API Source: https://docs.neoagent.io/agents/tools/documentation/sharepoint-api Read SharePoint sites, files, and lists via Microsoft Graph — and write to exactly the sites you allow The SharePoint API tool gives Neo agents direct access to SharePoint through Microsoft Graph — browse sites and document libraries, read and search files, work with lists and site pages, and (where you allow it) create and update content. <Info> Automatically enabled when you configure SharePoint permissions in your agent workflow. No manual toggle needed. See the [SharePoint integration page](/integrations/documentation/sharepoint) for connection setup and write access. </Info> ## What It Does * List SharePoint sites and their document libraries * Browse folders, read file metadata, and download file content * Search files, folders, and pages with the Microsoft Search API * Read lists, list items, and site pages * Create folders, upload and update files, and update list items — on write-granted sites only ## Two write gates, by design Reading is limited to the document libraries you chose to sync. Writing has two further gates on top of that, and both must be open: 1. **Agent permission groups** — you set each group below to Disabled, Read Only, or Read/Write per agent. 2. **Per-site write grants** — a Microsoft 365 admin grants Neo write access site by site, on the [SharePoint integration page](/integrations/documentation/sharepoint). A write to any other site is refused, whatever the agent's permission groups say. An agent can list your sites and libraries by name wherever they are — that is how it finds the right one, and it returns names only. It can open **file content, folders, lists and pages only inside the libraries under Read access**. Microsoft Search runs across the tenant, and Neo filters the results down to those libraries before the agent sees them. An agent with Read/Write groups but no site grants can read everything and write nothing. DELETE is never supported, on any site, under any profile. ## Permission Groups | Permission Group | What It Covers | | - | - | | **Sites & Libraries** | Site listing and metadata, document library (drive) metadata | | **Files & Folders** | Files and folders in document libraries — metadata, content download, uploads and updates on write-granted sites | | **Lists & Pages** | SharePoint lists, list items, columns, and site pages | | **Search** | Microsoft Search across SharePoint content (read-only by API design) | ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All four groups Read Only. The agent can browse and search everything the connector can see, but cannot make changes. The typical setting for documentation-aware ticket-resolution agents. </Accordion> <Accordion title="Documentation Manager"> Files & Folders **Read/Write**; Sites & Libraries, Lists & Pages, and Search Read Only. The agent can create folders and upload or update files on write-granted sites — ideal for agents that maintain runbooks and client documentation — but cannot change site structure or lists. </Accordion> <Accordion title="Full Access"> All four groups Read/Write. Writes still land only on the sites an admin has granted, and DELETE stays blocked. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **DELETE blocked** | The agent can never delete files, folders, list items, or sites — deletions are done in SharePoint itself. | | **Per-site write scope** | Microsoft enforces the per-site grants (`Sites.Selected`) below Neo's own code: even a misbehaving request cannot write outside the granted sites. | | **Read scope** | Agents read only the libraries under **Read access**. Unlike the write scope, Microsoft does not enforce this one — the connector app can technically read the tenant, and Neo's own code holds the line. | | **Permission surface blocked** | The agent cannot read or change site permission entries — write grants are managed by your admin, never by an agent. | | **Technician approval** | Each group has a **Require approval** toggle; writes on that group then wait for a technician's sign-off. | | **Rate-limit pacing** | The tool reads Graph's rate-limit headers and paces itself before SharePoint starts refusing requests. | ## Relationship to other tools * **[Find Documentation](/agents/tools/search/find-documentation)** searches Neo's synced documentation index, SharePoint content included, one query across every connected source. Prefer it for "find the runbook about X"; use the SharePoint API tool to browse live structure, fetch a specific file, or write. * **Microsoft 365 (MS Graph API)** also exposes `/sites` and `/drives` under its SharePoint & OneDrive permission group, on the Microsoft 365 integration's own app. The SharePoint API tool works without that integration and is the only one with per-site write scoping. ## Setup <Steps> <Step title="Connect SharePoint"> [Connect SharePoint](/integrations/documentation/sharepoint) from the Neo dashboard — a one-time admin consent, then pick the libraries to sync. </Step> <Step title="Grant write access (optional)"> For write use, an admin opens **Integrations → SharePoint → Write access** and grants the specific sites the agent may write to. </Step> <Step title="Configure agent permissions"> In the agent builder's **Documentation** section, pick an access profile or set the four permission groups individually. </Step> </Steps> # End-user tools Source: https://docs.neoagent.io/agents/tools/end-user/overview The tools a white-label chat agent uses when it's talking to your clients' employees — scoped to that one person, by design These tools only ever run in **end-user conversations** — when one of your clients' employees messages your white-label bot in [Teams](/integrations/teams/end-user-bot) or [Slack](/integrations/slack/end-user-bot). They never appear for dashboard or technician chat. Every one of them takes its identity (which company, which contact) from the conversation itself — never from anything the user or the AI types. In Teams it is resolved from the user's Microsoft 365 account. In Slack, the company is the one the workspace was installed for, and the contact is matched by the user's Slack profile email — so a user can only ever act on **their own** company and **their own** tickets. They're switched on automatically, and you never pick them. One thing needs a one-time setup before the agent can be saved: where new tickets land, and the three statuses that make up a chat ticket's life — while the bot has it, once [a human takes over](#handing-a-ticket-to-a-technician), and once it's resolved. That's covered below. Whenever the bot mentions a ticket — in a list, a status update, or a "ticket filed" confirmation — it shows the ticket by its human ticket number (ConnectWise/Autotask/Halo/ServiceNow display number). Where your PSA has a **client-portal link the end user can actually open** (Autotask today, via its Client Portal), that number is rendered as a clickable link to the ticket. For Autotask this needs a one-time setup: paste your Client Portal address (found in Autotask under **Admin → Client Portal Global Settings → "Generic Client Portal Login"**, e.g. `https://yourcompany.itclientportal.com`) into **Integrations → Microsoft Teams — End-user Chat Bot → Ticket links in the chat**. Autotask's API doesn't expose that address, so Neo can't discover it on its own. Until it's set — and for PSAs without a client-facing ticket URL — the bot shows the ticket number on its own (never an internal link an end user can't open). Keep in mind the portal itself only admits contacts you've granted Client Portal access in Autotask; for everyone else the link stops at the portal's login page. ## Always available These need no setup — every end-user conversation has them. | Tool | What it does for the user | | - | - | | **Find Documentation (End User)** | Answers "how do I…" questions from **your** knowledge base, scoped to the user's company plus your general/shared docs. Internal-only material isn't searched. | | **Get My Tickets (End User)** | Lists the tickets that user has open with you — their own only. The bot also reads that list when a conversation starts, without calling the tool, so it recognises a follow-up on an open ticket even when the user never says "ticket"; the tool is for showing the list on request, for closed tickets, and for changes since the conversation started. | | **Get Ticket Details (End User)** | Shows the status and the **customer-visible** updates on one of the user's tickets. Internal technician notes are never shown. | | **Link to Existing Ticket (End User)** | Links the conversation to one of the user's own existing tickets. From then on the user's messages are recorded on it as genuine customer replies — word for word, never a summary — so your PSA notifies the technician (and your "customer replied" automations fire). | | **Attach File (End User)** | Attaches a screenshot or file the user shares in chat to one of their own tickets. See [Sharing screenshots and files](#sharing-screenshots-and-files). | | **Ask User Questions (End User)** | When the bot asks a question with a few likely answers (which device, whether others are affected, yes/no), it offers them as buttons in Teams or Slack. The user taps one or types their own answer. Where buttons can't show, the bot names the options in its message. It reads nothing. | If a user isn't matched to a contact record in your PSA, the read, reply, and attach tools politely decline and tell them to ask you to add them as a contact — they never fall back to a broader view. ## Added when intents apply The bot has this tool only in a conversation whose company has [intents](#intents). | Tool | What it does for the user | | - | - | | **Load Intent (End User)** | Pulls the intake for one of the [intents](#intents) you've set up — a form the employee fills in where the intent has one, otherwise the questions for the bot to ask — so the right details are captured before the ticket is filed. | ## What the bot won't promise The bot can't see your dispatch queue or anyone's calendar, so it never agrees a time on your team's behalf. When an employee asks to be called back at 1:30, or asks when someone will pick their ticket up, the bot treats it as a request: it passes the requested time through to the ticket and tells the employee your team will confirm. It won't book a slot, name a technician, or invent a response time. It will state a time your team set — a booked appointment or a scheduled date on the ticket, or one you've put in the agent's Custom Instructions. Those are your commitments, so the bot relays them as they stand. The employee's own request is not one of them: once it's written on the ticket, the bot still reads it back as awaiting your confirmation, so its own note never becomes a promise on a later message. ## What the bot knows about the person it's talking to Once the conversation is matched to a contact record, the bot is told who that person is — so it can greet them by name and answer "can you confirm the email you have for me?" without asking them to identify themselves first. It's given: | | | | - | - | | **Name, email, phone, job title** | From the matched contact record. The bot may share these back with the user — they're the user's own details. | | **Contact custom fields** | Every custom field on that contact **that has a value**: Autotask user-defined fields, ConnectWise custom fields, Halo custom fields. Treated as internal — see below. | No setup is needed and there's nothing to switch on. ServiceNow and Syncro contribute no custom fields (ServiceNow keeps them as columns on the user record rather than a custom-field list); name, email, phone, and title work on every PSA. ### Using a custom field to drive behaviour Because custom fields reach the agent, you can branch on them from the agent's instructions. A common one is client-portal access — if you keep a contact field for it, you can write: > Only include a clickable portal link for a ticket when the user's contact record says they have portal access. Otherwise give the ticket number on its own. Two things to know when you write instructions like that: * **Custom fields are internal.** The bot uses them to decide *how* to help, but won't read them out, list them, or tell the user what they say — including when asked directly. Fields like `Priority Contact: False` or `Unsupported User` aren't things you want quoted back to a client's employee. * **A field with no value doesn't reach the bot at all** — it isn't shown as empty or false, it's simply absent. So write the rule as "only do X when the field says yes" rather than "don't do X when the field says no": a field that's unset, or newly added and not yet synced, must not be read as a negative. Contact data comes from your PSA sync, so a value changed moments ago may lag until that contact next syncs. Fields whose **name** looks like it holds a credential — password, passcode, secret, token, API key, SSN — are never sent to the bot, on any PSA. That's a safety net, not a place to store secrets: a contact custom field isn't a secure vault, and anything in one is visible to staff in your PSA. ## Both sides of the conversation are documented on the ticket Once a conversation is linked to a ticket — the bot created one, or the user replied about an existing one — **every message from both sides is recorded on that ticket**, turn by turn, while the conversation stays active. That includes exchanges where the bot used no tool at all: a user saying "that fixed it" and the bot answering still reaches the ticket. If the conversation goes quiet for more than a day, that automatic carry lapses: the next message is treated as a fresh conversation, and nothing more is recorded until the bot links a ticket again or files a new one. The carry follows the *subject* as well as the clock. A message that raises a different problem is not filed on the ticket the chat happens to be on; once that problem has its own ticket, everything said from then on is recorded there. The check runs per message and needs your PSA to return the ticket it is comparing against; when it can't run, the message falls back to the older behaviour and is recorded on the ticket the chat was already on. See [What the ticket records](/integrations/teams/end-user-bot#what-the-ticket-records). * **The user's message**, word for word as they typed it, is recorded as a **customer reply** — authored by their own contact on Autotask, ConnectWise and Halo, the shape your customer-reply rules react to (on ConnectWise it also sets the ticket's customer-updated flag), and as a visible comment carrying their name on ServiceNow and Syncro. It reads on the ticket exactly like a reply that arrived by email. (If the person doesn't match an active contact in your PSA, nothing can be authored as them, so their message is kept as an internal note titled *Customer message* instead. The same happens on a ticket that is already closed — a customer reply there would re-open it.) * **The bot's message to the user** — the follow-up question it asked, the confirmation it gave — is recorded as an **internal note** titled *Assistant reply*. It stays internal deliberately: the user already has it in the chat, so publishing it would email them a second copy of something they've read and fire your customer-facing rules on every turn. The user's words come from the chat record itself, not from the bot's retelling, so the wording on the ticket is exact by construction. A technician opening the ticket sees the whole conversation in the customer's own words, not a summary of it. It's always on, and nothing in your agent's instructions is needed to make it happen — don't write rules like "add the whole conversation as a note at the end". If a message can't reach your PSA (an outage, a rejected write), Neo keeps it and retries on the next turn. In one rare case — the note landed but Neo could not record that it had — the retry posts the same message a second time; a duplicate note is preferred to a lost one. For how each PSA separates client-facing notes from internal ones, see [End-User Communication](/integrations/psa/end-user-communication#how-neo-reaches-the-end-user). ### Autotask: choose the Note Type these notes carry If your Autotask workflow rules key off **Note Type**, you can pick the type Neo stamps, so your rules can match its notes and tell them apart from technician activity. Two settings, on the **Link to Existing Ticket (End User)** card: | Setting | Applies to | | - | - | | **Note Type for customer replies** | Every note recording the user's own words, whichever form it takes — the replies they send once the conversation is linked to a ticket, and the internal *Customer message* note used instead when the speaker matches no contact or the ticket is already closed. One type, so a rule looking for the end user's words only has to match one. | | **Note Type for Neo's own notes** | The *Assistant reply* notes documented above, and the handover note left when a ticket is [passed to a technician](#handing-a-ticket-to-a-technician). | Leave either empty and it uses **Task Summary**, which is what these notes have always carried — so existing agents are unaffected until you choose otherwise. Only the Note Type is yours to set. Whether a note is customer-facing or internal is fixed by what the note *is*: a customer reply is published to the customer, Neo's own notes stay internal. That's what lets the internal ones be written on every exchange without ever reaching the end user. ### Halo: choose the outcome these actions carry Every Halo action carries an **outcome**, and the outcome decides what Halo does with it — which workflow rules fire, whether the user is emailed, and whether the ticket moves to another team, agent or status. Two settings, on the same card: | Setting | Applies to | | - | - | | **Outcome for customer replies** | The action recording the user's own words. Pick the outcome your workflows treat as a customer reply. Leave it empty and the action carries Halo's *Note Added*. | | **Outcome for Neo's own notes** | The *Assistant reply* actions, and the handover action left when a ticket is [passed to a technician](#handing-a-ticket-to-a-technician). Leave it empty and Neo picks a silent outcome — one that neither emails the user nor moves the ticket. A chosen outcome that would do either is ignored and a silent one is used instead, so Neo's own notes can never email your user. | The second picker hides outcomes known to email. Until your Halo outcomes have synced since this setting shipped, it can also list outcomes Neo hasn't verified yet — that's safe either way: a choice that would email the user or move the ticket is ignored at write time and a silent outcome is used instead. On the other PSAs there is nothing to pick: ConnectWise notes are marked by flags, and ServiceNow and Syncro simply by whether they're customer-visible. ## Sharing screenshots and files When a user shares a screenshot or a file in chat — an error screenshot, a log, an exported form — **Attach File (End User)** puts it on one of their own tickets so the technician has it in the PSA. The bot attaches the specific file(s) the user wants on the ticket, after checking the ticket is theirs. It works on **ConnectWise, Autotask, Halo, and ServiceNow**. A file stays attachable for the whole conversation, not just the message that carried it. That matters for the usual shape of a chat: the employee sends the screenshot *with* the problem, the bot asks a question or two, and the ticket only exists a few messages later. The bot puts the screenshot on that ticket when it files it — and it never asks the employee to send the file a second time. ### What the bot reads vs. attaches This is the important distinction: * **Screenshots** — the bot **reads** them. It can see the error in the image, describe it, and reason about it, *and* attach it to the ticket. * **Documents** (PDFs, logs, spreadsheets) — the bot **attaches** them for the technician but **does not read** their contents. It knows a file is there and can put it on the ticket; it can't open the document to troubleshoot from it, and it won't pretend to. ### Supported file types Only these types are accepted — anything else is politely declined. | Kind | Types | Bot reads it? | | - | - | - | | Images | PNG, JPEG, GIF, WebP | **Yes** — sees the screenshot | | Documents | PDF, plain text / logs (`.txt`, `.log`), CSV, Word (`.doc`, `.docx`), Excel (`.xls`, `.xlsx`) | No — attaches only | <Note> A screenshot works whether the user **pastes** it into the chat or sends it with the **paperclip** — the bot sees it either way. In Teams, anything sent via the paperclip (an image or a document) reaches the bot only if its Teams app allows file sharing (`supportsFiles`); pasted images don't depend on that. In Slack, up to six files per message reach the bot, each up to 20 MB. </Note> ## Configure where end-user tickets land **Create Ticket (End User)** lets the bot file a new ticket on the user's behalf. The bot normally collects the essentials first — what happened, since when, any error message — but if the employee asks it to just log the ticket without questions, it files straight away with what they've said. Any screenshot or file the employee shared for that issue goes onto the ticket as it is created, including one sent earlier in the chat. It's on for every end-user agent — but unlike the tools above it has a setup step: you must set where these tickets land. The destination fields are **mandatory** — you can't save the agent until they're filled (your PSA won't accept a ticket without them): | Setting | Notes | | - | - | | Board / Queue / Ticket Type | **Required** — the destination for end-user-filed tickets, per your PSA (board for ConnectWise, queue + ticket type for Autotask, ticket type for Halo). | | Initial status | **Required** — the status new tickets open in, i.e. while the bot is still working the issue. | | Statuses when Neo needs to escalate to a human | **Optional** — the status(es) the bot moves a ticket to when it can't finish the job itself ([Mark Escalated](#handing-a-ticket-to-a-technician), below). Leave it empty if your tickets already open somewhere your team triages. | | Resolved status | **Required** — the status the bot moves a ticket to when it resolves a brand-new issue outright in chat (Log Resolved Ticket, below). | | Source | Optional — the ticket source to tag these with. On ServiceNow this is the incident's **Contact type** (for example Chat). Not offered on Syncro, whose tickets have no source. | The statuses are one lifecycle — **initial** (the bot has it) → **escalation** (a human has it) → **resolved** (done) — and each is applied to tickets on the board you chose above. On ConnectWise that means any status you set must belong to that board, since ConnectWise statuses are board-specific; the dashboard scopes the dropdowns for you and the save is rejected if a status from another board slips through. Initial and resolved are required; the escalation status is the one you can leave empty, and doing so means Neo hands the ticket over with a note without moving it. The end user just describes their problem; the bot fills in the rest from these defaults and attaches the user as the contact. If the user isn't a known contact, the ticket is still created and their name/email is recorded in the description so a technician knows who reported it — a request is never dropped. On **Autotask**, the ticket is also recorded as having been *raised by* that contact, not by Neo's API user — matching how their replies are recorded, so the ticket reads as the employee's own. This needs **Contact Impersonation** on your Neo API user's security level ([how to set it](/integrations/psa/autotask/creating-security-level)); without it Autotask quietly ignores the attribution and the ticket lands under the API user instead. The bot also folds the part of the chat that led to the ticket into the ticket body, word-for-word, so the technician sees the exact context and tone — scoped to that one issue, so a chat that covered several topics doesn't carry unrelated ones into each ticket. If the conversation is longer than your PSA's description field allows (on Autotask, Neo fills the body up to 7,500 characters — just under Autotask's own 8,000 limit), the body is cut at the limit with a line saying where the rest is, and the **full transcript is written onto the ticket as an internal note** — so a long intake chat is never silently clipped mid-sentence. Like every note Neo writes about itself, it's internal on every PSA: it never emails the customer. On Autotask it carries the Note Type you set for [Neo's own notes](#autotask-choose-the-note-type-these-notes-carry). ## Resolving tickets When the bot gets a user sorted, it can close the loop in your PSA — so even issues it handles without a technician leave a clean record. **Mark Resolved (End User)** marks one of the user's existing tickets resolved once they confirm their problem is fixed: it writes a short Neo-attributed resolution summary, then moves the ticket to **its own** resolved status — whichever closed status applies to that ticket's board (ConnectWise) or type (ServiceNow). Nothing to configure, and it works on any of the user's tickets wherever they live. **Log Resolved Ticket (End User)** is for when the bot fully fixes a brand-new issue right in the chat, with no technician needed: it files a ticket and immediately resolves it in one step, so your team still has the record. It uses the Create Ticket destination above, and the **Resolved status** you set there. Both attribute the resolution to Neo and record the summary on the ticket (a resolution note in ConnectWise, a Neo action in Halo, a comment in ServiceNow) — never as a customer reply. ## Handing a ticket to a technician **Mark Escalated (End User)** is how the bot gets out of the way. When it can't finish the job — the issue needs an account change, the user asks for a person, or it's simply out of the bot's depth — it moves the ticket to one of the **statuses when Neo needs to escalate to a human** you set above, and records a handover note: what the user needs, what the bot already tried, and what it ruled out. **The note always happens; the status move is optional.** The two halves are independent, and which you need depends on where your chat tickets open: * **Your tickets open in a status nobody watches** — something like *Chat Active*, deliberately outside triage. Set an escalation status. It's the only thing that puts the ticket in front of a technician, and without one those tickets sit there. * **Your tickets already open in a status your queue triages** — leave the escalation status empty. There's nowhere useful to move the ticket to, a technician can already see it, and the handover note is the entire hand-off. Neo leaves the ticket exactly where it is. If you do set one, most MSPs set exactly one (their normal *New* / *Triage*) and the bot just uses it. Set several and the bot chooses the one that fits the request — so name them in a way that makes the choice obvious (*Escalated — Onsite*, *Escalated — Security*). The handover note is **internal on every PSA**: the end user has already read all of it in the chat, so it's written for the technician and never re-notifies the customer. If your PSA rejects the status change (a workflow rule, or a ticket that lives on another board), the note still lands — so the ticket is never silently stuck with the bot. There's nothing to configure on the tool itself, and it's on for every end-user bot. ## Intents You can teach a bot the common requests your clients raise — a new starter, a hardware request, a mailbox change — each with the exact details to collect. When an employee's request matches one, the bot loads its intake on demand with **Load Intent (End User)** (added automatically when the company has intents, no setup) — showing the employee a form to fill in where the intent has form fields, otherwise gathering only what it doesn't already know — then files the ticket to the Create Ticket destination above. Only the menu of names and descriptions sits in the bot's prompt, so you can add as many as you like, and intents are scoped **per client company**. See [Intents](/chat-agents/intents) for the full guide — what each intent contains, how the same intents also run on ticket-triggered agents, and how to set them up. <Note> These tools are deliberately narrow. End-user bots are an interface to you, not a way for end users to reach across your client base — anything beyond a user's own documentation and tickets is out of scope by design. See [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access). </Note> # Change License Seats Source: https://docs.neoagent.io/agents/tools/m365/change-license-seats Add or remove license seats via your marketplace provider Each call changes the seat count of one marketplace subscription, the one the agent picked with [List License Subscriptions](/agents/tools/m365/list-license-subscriptions), in one direction: it adds seats or it removes them. <Info> This tool changes the seat count of a subscription the client already holds. To buy the first seat of a product the client does not hold yet, an agent places an order through the [Vendor API](/agents/tools/vendor-api) tool on [Pax8](/integrations/marketplaces/pax8), [TD SYNNEX ION](/integrations/marketplaces/td-synnex) or [TD SYNNEX Stellr](/integrations/marketplaces/td-synnex-stellr). Assigning a license to a user, or unassigning it, is done by the [Microsoft 365 tools](/agents/tools/m365/overview) (Microsoft Graph API), gated by your M365 licensing permissions. An agent without those permissions is told to assign the new seat with the tool it uses for licensing, such as CIPP, or to hand that step to a technician. Unassign users **before** the agent removes seats. </Info> <Warning> **Removing seats never terminates a subscription.** If the agent removes the last seat, the subscription record stays on your marketplace and can keep billing until its term ends. The agent says so and hands the job to a technician. Cancelling the subscription itself is done by hand in the marketplace portal, or on Pax8 and TD SYNNEX Stellr by an agent with writable subscription permissions through the [Vendor API](/agents/tools/vendor-api) tool. This tool never ends a subscription. </Warning> ## What It Does When enabled, the agent can: * Add or remove seats for any license SKU * Target a **specific subscription** when your provider has multiple subscriptions for the same license (e.g., separate Monthly and Annual subscriptions) * Auto-detect which marketplace provider to use based on the company's configuration ## Settings | Setting | Description | | - | - | | **Require technician approval** | The agent sends a Teams approval request before it changes seats. Enabled by default. | | **Allow adding seats** | The agent may buy seats. Turn it off on an agent that should only remove seats, such as an offboarding agent. | | **Allow removing seats** | The agent may lower a seat count. Turn it off on an agent that should only buy seats, such as an onboarding agent. | At least one of the two directions must be on. When the agent asks for a change its settings do not allow, the tool changes nothing and the agent tells the technician. ## Subscription Targeting Many MSPs keep multiple subscriptions for the same license (e.g., an 80/20 yearly/monthly split, or separate month-to-month and annual-commitment subscriptions). The agent identifies the exact subscription by calling [List License Subscriptions](/agents/tools/m365/list-license-subscriptions) first, which returns the subscription ID, status, billing term, commitment term and seat count for each subscription. ## Marketplace Provider Auto-Detection The marketplace provider is determined from the company's configuration. Neo checks in this order: 1. A **Marketplace Company ID** typed on the company, in this order: Pax8, D\&H, Ingram Micro, Sherweb, TD SYNNEX ION, TD SYNNEX Stellr, OpenText Secure Cloud, Microsoft Partner Center 2. An **Ingram Micro** customer matched to the company under Organization Mapping 3. A **TD SYNNEX ION** customer, then a **TD SYNNEX Stellr** customer, then an **OpenText Secure Cloud** customer, matched to the company under Organization Mapping. When that customer holds no Microsoft 365 service in Secure Cloud and Partner Center credentials are saved, Neo uses Microsoft Partner Center instead 4. **Microsoft Partner Center**, as a fallback when Partner Center credentials are saved Only a confirmed or exact match in Organization Mapping selects a marketplace. A suggested match does not. ## Timing the Change The agent applies a change either **immediately** or **at the next renewal date**. Use custom instructions to direct it: * **Immediately** (default) — an addition applies now and bills for the prorated remainder of the current period. Microsoft NCE allows an immediate removal only within the first 7 days of a term, so an immediate removal can fail on an older subscription. If the marketplace rejects it on NCE policy grounds, the agent is told to retry at the next renewal. * **Next renewal** — the change is queued for the subscription's renewal date. It suits additions you want aligned with billing anniversaries, and removals after the 7-day window. Scheduled-at-renewal is supported via API on **Ingram Micro** and **Microsoft Partner Center**. For **Pax8**, **D\&H** and **Sherweb**, the API doesn't expose it. For **TD SYNNEX ION**, **TD SYNNEX Stellr** and **OpenText Secure Cloud**, Neo does not schedule a change at renewal yet. In both cases the agent suggests scheduling the workflow itself to run on the renewal day. The agent can also align the renewal date to the **end of the calendar month** or to the **subscription's existing anniversary** when the change applies (Ingram Micro only). ## Adding Seats: Waiting for the New Seat Marketplaces accept the order asynchronously. Microsoft Graph usually shows the new seat within \~60–90 seconds, but rare cases take longer. For an **immediate** order the tool waits for the new seat to become visible in Microsoft before it returns, so the agent can usually assign the license straight away. The wait is up to **5 minutes** in an automation and **20 seconds** in a chat conversation, where someone is waiting for the agent's reply. If the seat is still not visible when that wait ends, the tool returns successfully and tells the agent to wait a few more minutes and check again before assigning, or to hand off to a technician if the seat still doesn't appear. A **next-renewal** order returns immediately, and the seat appears on the renewal date. ## Confirming the Marketplace Applied the Change Whether Microsoft can assign a seat is a separate question from whether the marketplace record changed. One customer had the Microsoft side fulfil correctly while the Pax8 subscription disappeared from their portal. On **Pax8**, the agent reads the subscription back after the change and reports the seat count Pax8 holds. The read-back window is 90 seconds, and 30 seconds in a chat conversation. The read-back ends in one of two states: * **Confirmed** — Pax8 reports the seat count the agent asked for. * **Unconfirmed** — the read-back did not show that seat count in the time available. The agent is told not to claim the change applied, and to ask a technician to check the portal rather than send the change again, because a repeat that does apply would change the seats twice. For a removal, the state decides whether the tool reports success. A reduction **to zero seats** that stays unconfirmed reports failure, because Pax8 ends a subscription through cancellation and not through a seat change of zero; an offboarding agent then does not write a completed licence removal for seats that are still on the subscription. Every other unconfirmed reduction reports success with the unconfirmed wording, since Pax8 settles a quantity change over several minutes. On **TD SYNNEX ION**, the agent waits for the order to finish and reads the subscription back the same way. On **TD SYNNEX Stellr**, it waits for the provisioning operation to finish and reads the subscription back; a Stellr subscription keeps at least one seat, so removing the last one means cancelling it. On **OpenText Secure Cloud**, Secure Cloud accepts the change for processing, and the agent reads the subscription back until it shows the new seat count. Neo changes seats only on an active Microsoft 365 subscription, keeps at least one seat, and refuses a removal after the subscription's last day for a decrease (`CanCancelUntilDate`), when Microsoft bills the seat to the end of the term. When the read-back cannot confirm a change, Neo keeps other changes off that subscription for up to about 20 minutes, so a second change cannot start from the old count. D\&H, Ingram Micro, Sherweb and Microsoft Partner Center are not read back yet. There the agent reports the change as unconfirmed, never as failed, because nothing was checked either way. ## When the Marketplace Refuses a Removal * **Pax8 committed minimum** — Pax8 will not lower a subscription below the seat count committed for the current term. The agent is told how many seats, if any, can come off before the term ends, and not to retry. Often the answer is none until the renewal date. * **Sherweb at zero seats** — when Sherweb refuses to take a subscription to zero seats, the agent relays Sherweb's error and tells the technician to cancel the subscription in the Sherweb portal. ## Busy Subscriptions When Pax8 is still provisioning a prior change, it returns `HTTP 500 — Subscription being modified has executing provisioning actions`. In an automation, Neo retries this error with backoff (60 / 90 / 120 seconds, up to \~4.5 minutes) before it gives up. Concurrent calls against the same Pax8 subscription are serialized at the Neo layer, so parallel onboarding workflows do not race. A chat conversation does not wait any of that out. The two ways of giving up early read differently to the agent, because they leave the marketplace in different states: * **Another Neo run holds the subscription.** Nothing was sent, so the agent is told the subscription is unchanged and that it can run the change again later. An automation waits up to 6 minutes for the other run; a chat conversation waits 10 seconds. * **Pax8 reports the subscription as still provisioning.** The change did reach Pax8, and a provisioning rejection is not proof that Pax8 ignored it. The agent is told to read the seat count with [List License Subscriptions](/agents/tools/m365/list-license-subscriptions) before sending the change again. In the rare case where the whole marketplace call passes 50 seconds in a chat, the agent is told that Neo does not know whether the change was submitted, and to read the seat count before sending it again. ## Tool Dependencies When you enable this tool, the following are automatically enabled: * **List License Subscriptions** — so the agent can find the subscription ID before it changes seats * **Request Technician Approval** — when approval is enabled in settings ## How to Use Guide subscription selection with custom instructions: ``` When buying Microsoft 365 Business Basic seats: - Add 80% of seats on the Annual subscription - Add 20% of seats on the Monthly subscription ``` ``` After unassigning all licenses from the departing user, remove the freed Monthly seats to stop billing immediately. If this would take the subscription to zero seats, leave an internal note for the licensing team to cancel the subscription in the portal. ``` # CIPP API Source: https://docs.neoagent.io/agents/tools/m365/cipp-api Manage your customers' Microsoft 365 tenants through your CIPP instance: users, mailboxes, quarantine, devices, security alerts and SharePoint access It suits MSPs who manage their customers in [CIPP](https://cipp.app) and have not given Neo its own Microsoft access: the agent acts with the access your CIPP instance already has. <Info> Automatically enabled when you configure CIPP permissions in your agent workflow. </Info> ## What It Does * **Users and groups:** find a user, read their groups, devices, MFA registration and sign-ins; revoke sessions, block or allow sign-in, remove MFA methods, set a password, edit or create a user, change group membership, restore a deleted user, offboard or delete a user * **Mailboxes:** read mailbox details, permissions, rules, forwarding and out of office, and run a message trace; grant mailbox or calendar access, set out of office, set forwarding, convert to a shared mailbox, hide from the address list, turn on the archive, manage inbox rules, unblock a restricted sender * **Email security:** list quarantined mail and release, deny or delete it; read spam, phishing and malware policies and transport rules; add and remove Tenant Allow/Block List entries * **Devices:** read Intune and Autopilot devices, compliance, Defender state and apps; sync, restart, scan, lock, wipe or retire a device; disable or delete a device in Entra ID * **Security and sign-ins:** read Defender alerts and incidents, sign-ins and Conditional Access policies; run a business email compromise check and contain the account; set an alert's status; dismiss user risk; change per-user MFA * **SharePoint and Teams:** read sites, members, sharing and storage; add or remove site members and OneDrive access * **Tenants:** find the customer's tenant, and read its domains, licences, service health and Secure Score * **Passwords and keys** (a permission of its own): read a device's LAPS password or BitLocker / FileVault key, reset a password and read the new one, issue a Temporary Access Pass * **Raw Graph and Exchange** (a permission of its own, every call approved): any Microsoft Graph read or Exchange `Get-` / `Search-` cmdlet, for a record nothing above covers ## Passwords, keys and raw requests * **Passwords and keys reach an agent only through the Passwords & Keys group.** Turn it on for agents that hand credentials to your team, such as an internal chat agent a technician asks for a LAPS password. The agent delivers a secret the way your instructions say (an internal note, SMS), or by default through a one-time secure link; it never writes the secret into its answer or a customer-facing note. A password that another call reports, such as offboarding or account containment, is removed before the agent sees it. * **Raw Graph and Exchange requests always ask a technician**, reads included, because a request can name any record CIPP can read, secrets included. Use them as a last resort; the other groups, or Neo's own [Microsoft 365 integration](/integrations/m365/intro), have a permission for each kind of record. ## What Neo never does through CIPP * **Change every tenant at once.** Any POST sent to `AllTenants` is refused, a change or a message trace, so the agent acts in one customer's tenant at a time. A GET read may cover every tenant. * **Change CIPP or tenant-wide configuration.** CIPP settings, standards, Conditional Access policies, Intune policies and GDAP stay with your technicians in CIPP. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Tenants & Licences | Disabled, Read Only | Tenants, domains, licences, service health, Secure Score | | Users & Groups | Disabled, Read Only, Read/Write | Users, groups, MFA registration, roles, sign-in logs, and the account changes above | | Mailboxes | Disabled, Read Only, Read/Write | Mailboxes, permissions, rules, forwarding, out of office, message trace, shared mailboxes, contacts | | Email Security | Disabled, Read Only, Read/Write | Quarantine, Tenant Allow/Block List, spam and phishing policies, transport rules | | Devices | Disabled, Read Only, Read/Write | Intune and Autopilot devices, device actions, Entra ID devices | | Security & Sign-ins | Disabled, Read Only, Read/Write | Defender alerts and incidents, sign-ins, Conditional Access, business email compromise, user risk, per-user MFA | | SharePoint & Teams | Disabled, Read Only, Read/Write | Sites, members, OneDrive access, Teams | | Passwords & Keys | Disabled, Read Only, Read/Write | Read Only reads LAPS passwords and BitLocker / FileVault keys; Read/Write also resets passwords and issues Temporary Access Passes | | Raw Graph & Exchange | Disabled, Read/Write | Any Graph read or Exchange `Get-` / `Search-` cmdlet; every call asks a technician | A device wipe, retire, passcode reset, or any device action other than sync, restart, Defender scan or signature update, local admin password rotation, rename, lock, locate or primary user change always asks a technician first, whatever the group's setting. So does deleting a device from Entra ID; disabling or enabling one follows the group. ### Access profiles | Profile | What it does | | - | - | | Read Only | Reads everything except passwords and keys, changes nothing; raw requests off | | Helpdesk | Mailbox changes and LAPS / BitLocker key reads on its own; account and device changes and password resets ask a technician first; read-only elsewhere; raw requests off | | IT Admin | Users, mailboxes, devices, SharePoint and passwords on its own; email security and security changes (allow entries, MFA, user risk, alert status) and raw requests ask a technician first | | Full Automation | Every supported change with no approval, except the device actions and device deletion above and raw requests | ## Setup See [Connecting CIPP to Neo](/integrations/cipp/connecting-to-neo). # Execute PowerShell (Active Directory) Source: https://docs.neoagent.io/agents/tools/m365/execute-powershell-ad Run validated PowerShell against on-prem Active Directory through your RMM This tool lets a Neo Agent generate and run validated Active Directory PowerShell on a domain controller, executed through your connected RMM. It's how Neo manages on-prem and hybrid AD environments — user and computer accounts, organizational units, group membership, and infrastructure queries. <Info> Enabled automatically when you turn on **Active Directory** permissions on the workflow's **Integrations** tab — there's no separate toggle in the tool list. Requires an RMM connection that can run scripts on the domain controller. See [Microsoft 365 integration](/integrations/m365/intro) and [on-prem setup](/integrations/m365/on-prem). </Info> ## What It Does * Create, update, disable, enable, and delete AD user accounts * Reset passwords and unlock accounts * Manage group membership — security groups, distribution groups, OUs * Manage computer accounts and organizational units * Query directory and infrastructure state * Trigger an Azure AD Connect (Entra Connect) sync so on-prem changes propagate to the cloud ## Hybrid Environments In a hybrid setup, configure Microsoft 365 as on-prem. Neo makes the change on your domain controller and then triggers an Entra Connect sync, so a password reset or group change made on-prem shows up in the cloud automatically — no separate cloud action needed. If a company has both directories but **no AD Connect sync** (identity provider type "Hybrid (no AD Connect sync)"), there is no sync to trigger — Neo instead applies identity changes to both on-prem AD and Entra ID directly, keeping the two independent directories consistent. ## Safety | Control | Behavior | | - | - | | **Validated cmdlets** | Code is parsed before it runs — only AD cmdlets are allowed; dangerous operations are blocked | | **Allowed and blocked cmdlets** | Optionally limit the agent to a set of cmdlets, or block some. Set once for the whole Active Directory integration, above its permission groups | | **Technician-in-the-Loop** | Turn on approval on an Active Directory permission group, and its writes wait for a technician | | **Access level** | Set an AD permission group to Read Only to block its write cmdlets | | **Programs and .NET calls** | A program such as `nltest`, a .NET call such as `[System.IO.File]::WriteAllText`, or a script Neo cannot read runs only when every AD group other than Entra Connect Sync is Read / Write, and waits for a technician when any of them requires approval | | **Runs through your RMM** | Execution uses your existing RMM agent on the domain controller — the same credentials and audit trail you already trust | | **Test mode** | No script runs, including one that only reads. It is reported as a would-have-run script at the end of the run. For live data during a test run, the agent uses the built-in Active Directory user and group lookups, which do run | ## How to Configure <Steps> <Step title="Connect an RMM"> Connect a [supported RMM](/integrations/rmm/intro) that can run scripts on the domain controller. </Step> <Step title="Configure the on-prem environment"> Follow the [on-prem setup guide](/integrations/m365/on-prem) to point Neo at the domain controller. </Step> <Step title="Enable Active Directory permissions"> On the workflow's **Integrations** tab, set the Active Directory permission groups (users, groups, computers, OUs, infrastructure, Entra Connect sync) to Read Only or Read / Write. </Step> <Step title="Set approval and cmdlet limits"> Decide whether writes require technician approval on each permission group. To limit the cmdlets, use the two pickers above the Active Directory permission groups: * **Allowed cmdlets**: when you pick any, the agent can run only those. Also pick the helper cmdlets its scripts need, such as `Select-Object`. Leave it empty to allow every supported cmdlet. * **Blocked cmdlets**: the agent can never run these, even when a permission group or the allowed list includes them. The pickers show while at least one permission group is on. </Step> </Steps> <Tip> Start with Read Only and technician approval on. Most onboarding and offboarding workflows only need a handful of cmdlets — restrict to those once you've seen what the agent uses. </Tip> # Execute PowerShell (Exchange) Source: https://docs.neoagent.io/agents/tools/m365/execute-powershell-exchange Run validated PowerShell against Exchange Online and Exchange Server This tool lets a Neo Agent generate and run validated PowerShell against Exchange — Exchange Online for cloud tenants, or on-prem Exchange Server via your RMM. It covers the full range of mailbox, recipient, mail-flow, and compliance operations. <Info> Enabled automatically when you turn on **Exchange** permissions on the workflow's **Integrations** tab — there's no separate toggle in the tool list. See [Microsoft 365 integration](/integrations/m365/intro). </Info> ## What It Does * Manage mailboxes — properties, statistics, shared mailboxes, archive settings * Configure mailbox permissions — full access, send-as, send-on-behalf, delegation * Set up and remove email forwarding * Manage recipients, contacts, and distribution groups * Configure mail flow — transport rules, connectors, address lists, retention policies * Run compliance and auditing operations * Handle bulk operations across many mailboxes or recipients ## Safety | Control | Behavior | | - | - | | **Validated cmdlets** | Code is parsed before it runs — only Exchange cmdlets are allowed; dangerous operations are blocked | | **Allowed and blocked cmdlets** | Optionally limit the agent to a set of cmdlets, or block some. Set once for the whole Exchange integration, above its permission groups | | **Technician-in-the-Loop** | Turn on approval on an Exchange permission group, and its writes wait for a technician | | **Access level** | Set an Exchange permission group to Read Only to block its write cmdlets | | **Cmdlets outside the groups** | An admin write cmdlet no permission group covers, such as `Add-RoleGroupMember`, a program, a .NET call, or a script Neo cannot read runs only when every Exchange group is Read / Write, and waits for a technician when any group requires approval | | **Test mode** | No script runs, including one that only reads. It is reported as a would-have-run script at the end of the run. For live data during a test run, the agent reads through Microsoft Graph instead | ## How to Configure <Steps> <Step title="Connect Microsoft 365"> [Connect your tenant](/integrations/m365/cloud) (cloud) or [on-prem environment](/integrations/m365/on-prem). Exchange Server runs through your RMM. </Step> <Step title="Enable Exchange permissions"> On the workflow's **Integrations** tab, set the Exchange permission groups (mailboxes, permissions, recipients, distribution groups, mail flow, address lists, compliance) to Read Only or Read / Write. </Step> <Step title="Set approval and cmdlet limits"> Decide whether writes require technician approval on each permission group. To limit the cmdlets, use the two pickers above the Exchange permission groups: * **Allowed cmdlets**: when you pick any, the agent can run only those. Also pick the helper cmdlets its scripts need, such as `Select-Object`. Leave it empty to allow every supported cmdlet. * **Blocked cmdlets**: the agent can never run these, even when a permission group or the allowed list includes them. The pickers show while at least one permission group is on. </Step> </Steps> <Tip> Use this for Exchange operations the higher-level Microsoft 365 tools don't cover — detailed mailbox statistics, transport rules, retention policies, or bulk recipient changes. </Tip> # List License Subscriptions Source: https://docs.neoagent.io/agents/tools/m365/list-license-subscriptions Discover subscriptions, commitment terms, and seat counts for a specific Microsoft license The List License Subscriptions tool allows Neo Agent to query your marketplace provider for the subscriptions behind a specific license, showing subscription IDs, billing terms, commitment terms, and current seat counts. ## What It Does When enabled, the agent can: * List all provider subscriptions for a given license SKU * Show the **marketplace subscription ID** for each subscription * Show the **billing term** (payment frequency — e.g., Monthly, Annual) for each subscription * Show the **commitment term** (contract duration — e.g., Monthly, 1-Year) for each subscription * Show the **marketplace seat quantity** per subscription — the number of seats purchased/billed on that subscription record * Show the **marketplace seat total** — the sum of seats across all of the provider's subscriptions for the SKU * Show the **renewal date** — the date the subscription's current term ends — and whether it **auto-renews** * Return the **SKU ID** and **SKU part number** so the agent can line the marketplace records up with the tenant's Microsoft 365 licenses * Identify which marketplace provider was queried (Pax8, D\&H, Ingram Micro, Sherweb, TD SYNNEX ION, TD SYNNEX Stellr, OpenText Secure Cloud, or Microsoft Partner Center) ## Finding the Marketplace Product A Microsoft license and a marketplace product rarely share a name. Microsoft calls its CSP variant of Power BI Pro **"Power BI Pro Dept"** (`POWER_BI_PRO_DEPT`); Pax8 sells the same thing as **"Power BI Pro"**. Neo resolves the two in this order: 1. **By Microsoft SKU ID**, where the marketplace publishes it. Pax8 records the Microsoft SKU on a product only where that field is set, and some Pax8 products leave it empty; Microsoft Partner Center returns it directly. Where the ID is there, Neo matches on it exactly. This is the reliable path: it does not depend on the two catalogs agreeing on a name. 2. **By product name**, as a fallback. It runs only when *no* subscribed product publishes the requested SKU ID. A match on step 1 skips it. Sherweb, Ingram Micro, TD SYNNEX ION, TD SYNNEX Stellr and OpenText Secure Cloud always take this path; Pax8 takes it when none of the company's products carry the ID. Step 1 returns every subscribed product that carries the ID, so an annual and a monthly offer of the same license are both reported. A product with an empty mapping is a different case: if the company holds one offer with the SKU and a second offer without it, only the first is reported, and the **marketplace seat total** omits the second offer's seats. Set the missing mapping in the Pax8 portal to bring it back into the count. <Tip> If a Pax8 product repeatedly fails to resolve, check its Microsoft SKU mapping in the Pax8 portal. A product with the correct Microsoft SKU is matched exactly and never depends on the name. </Tip> ### When nothing matches Some Microsoft licenses have no marketplace product at all — free and promotional SKUs such as **Power BI (free)**, **Microsoft Power Automate Free**, **Windows Store for Business** and **Teams Exploratory** are assigned by Microsoft and are not sold by any marketplace. When no product matches on Pax8, Sherweb, Ingram Micro, TD SYNNEX ION, TD SYNNEX Stellr, OpenText Secure Cloud or Microsoft Partner Center, the tool returns no subscriptions and a `no_matching_product` note, and does not fail. A reconciliation agent that goes through every license a tenant holds therefore continues past the free ones. On **Pax8, Sherweb, Ingram Micro, TD SYNNEX ION and TD SYNNEX Stellr**, the note says which Microsoft license was requested (name, SKU part number and SKU ID) and lists the marketplace products the company subscribes to. The list is capped at 30 names so it stays short enough for a technician note; above that, the message says how many products it left out and asks the technician to read the full catalog in the marketplace portal. The agent passes that on to a technician instead of ordering seats against a product it guessed at. On **OpenText Secure Cloud**, the note names the requested license and lists the customer's Microsoft 365 products only; a customer with no current Microsoft 365 subscription gets a note that says so, with no product list. Read the list to decide which applies: * The right product is in the list under a different name → on Pax8, correct the product's Microsoft SKU mapping. Sherweb, Ingram Micro, TD SYNNEX ION and TD SYNNEX Stellr publish no Microsoft SKU, so there is no mapping to correct — buy against the product you identified. * The message says products were left out → check the full catalog in the marketplace portal before you conclude the product is missing. An omitted name is not an absent product, and buying one you already own gives you a duplicate subscription. * The right product is missing → buy it in the marketplace portal, then re-run. * The license is a free Microsoft SKU → nothing to buy; assign it in Microsoft 365. **Microsoft Partner Center and D\&H report a no-match differently.** Partner Center's note says only which SKU it could not find (`No subscriptions with SKU <id> (<name>) found in Microsoft Partner Center`) — no product list, so open the Partner Center catalogue yourself to see what the company holds. D\&H does not yet have a technician-facing message for this case at all: the call fails and the agent reports the failure. On either provider, read the company's subscriptions in the provider portal rather than expecting the capped list above. ## Seat Counts and Reconciliation The **marketplace seat quantity** on each subscription is an explicit **seat count** for that one subscription record — it is *not* a count of subscription records, and *not* the number of seats currently assigned to or used by end users. A single license SKU can have seats spread across several subscription records (or even several marketplace providers), so the marketplace seat total for a SKU can legitimately differ from the seat total Microsoft 365 reports for the same SKU. The agent reconciles the two using the returned SKU ID / SKU part number and treats each subscription record independently when purchasing or cancelling seats, rather than assuming the marketplace and Microsoft totals are identical. ## Renewal Dates The **renewal date** is the date the subscription's *current* term ends, exactly as the marketplace reports it. If the subscription auto-renews, that is the date it renews; if it does not, that is the date it lapses. This is what lets an agent act only on subscriptions renewing inside a window — "reduce unused seats, but only within 7 days of renewal", for example. Not every provider exposes it: | Provider | Renewal date | Auto-renew flag | | - | - | - | | Pax8 | Yes — commitment end date, or the subscription end date for month-to-month | Yes | | Sherweb | Yes | No | | Ingram Micro | Yes | No | | TD SYNNEX ION | Yes | Yes | | TD SYNNEX Stellr | Yes — the billing end date | Yes | | OpenText Secure Cloud | Yes — the subscription's expiration date | Yes | | D\&H | No | No | | Microsoft Partner Center | No | Yes | Where a provider does not return a value, the field is empty and the agent treats it as **unknown** — not as "this subscription is not renewing". An agent whose rules depend on the renewal date should say what to do when the date is unavailable (usually: leave the subscription alone and tell a technician). This tool reports what the **marketplace** knows. Microsoft publishes its own renewal date per subscription, which the [Microsoft 365 tools](/agents/tools/m365/overview) read under Licensing — use that for SKUs bought outside your marketplace, or where the table above shows no renewal date. Ask for both when you want full coverage. ## When It's Used This tool is called by the agent before it adds or removes license seats, so it can get the marketplace subscription ID for the target subscription. It's auto-enabled as a dependency of [Change License Seats](/agents/tools/m365/change-license-seats). <Info> You don't need to enable this tool manually — it's automatically enabled when you enable Change License Seats. </Info> In a chat conversation the tool waits up to 60 seconds for the marketplace. When the marketplace is slower, the agent says so and tries again later, and nothing changes. ## Billing Term vs Commitment Term Microsoft's New Commerce Experience (NCE) has multiple subscription types for each license. Two subscriptions can share the same billing term but differ in commitment: | NCE Type | Billing Term | Commitment Term | Price | | - | - | - | - | | Monthly-Monthly | Monthly | Monthly | Highest | | Monthly-Annual | Monthly | 1-Year | \~20% cheaper | | Annual-Annual | Annual | 1-Year | Cheapest | The **commitment term** is the key differentiator — it tells you whether a subscription is month-to-month (cancel anytime) or locked into an annual contract. ## Example Output For a company with both month-to-month and annual-commitment subscriptions for Microsoft 365 Business Basic: | Subscription ID | Billing Term | Commitment Term | Marketplace Seat Quantity | Renewal Date | Auto-Renew | | - | - | - | - | - | - | | abc-123-def | Monthly | 1-Year | 80 | 2026-08-14 | Yes | | ghi-456-jkl | Monthly | Monthly | 20 | 2026-08-31 | Yes | Here the marketplace seat total is 100 (80 + 20). The agent uses the subscription ID to target the correct subscription when purchasing or cancelling seats, and reconciles the marketplace seat total against the tenant's Microsoft 365 seat count via the SKU part number. # Microsoft 365 Tools Source: https://docs.neoagent.io/agents/tools/m365/overview How Neo Agents manage Entra ID, Active Directory, Exchange, and Intune Neo Agents manage the full Microsoft estate — cloud and on-prem — through a small set of API-backed tools. You don't enable individual operations like "Create User" or "Reset Password" one at a time. Instead, you connect the Microsoft 365 integration, choose which **permission groups** the agent can use, and the matching tools turn on automatically. <Info> These tools appear in your agent automatically once you configure Microsoft 365, Active Directory, or Exchange permissions on the workflow's **Integrations** tab — there's no separate toggle in the tool list. See [Microsoft 365 integration](/integrations/m365/intro) for the permission model. </Info> ## The Tools | Tool | What It Covers | Environment | | - | - | - | | **Microsoft Graph API** | Users, groups, licenses, directory roles, devices, conditional access, domains, app registrations | Entra ID (cloud) | | **Execute PowerShell (Exchange)** | Mailboxes, permissions, recipients, distribution groups, mail flow, transport rules, compliance | Exchange Online and Exchange Server | | **Execute PowerShell (Active Directory)** | On-prem users, computers, OUs, groups, infrastructure queries, Entra Connect sync | On-prem Active Directory (via RMM) | In hybrid environments Neo routes each operation to the right place — for example, it makes the password change on-prem and triggers an Azure AD Connect sync so it propagates to the cloud. For hybrid tenants without AD Connect sync ("Hybrid (no AD Connect sync)" in Company Settings), Neo writes to both directories directly instead — same change, same values, applied to on-prem AD and Entra ID independently. ## What Agents Can Do <AccordionGroup> <Accordion title="User lifecycle" icon="user-plus"> Create, update, disable, enable, and delete users in Entra ID or on-prem Active Directory. Assign managers, set job titles and departments, and update user properties. </Accordion> <Accordion title="Passwords & security" icon="lock"> Reset passwords, unlock accounts, revoke sign-in sessions, reset MFA, and block or unblock sign-in. In hybrid environments, Neo makes the change on-prem and syncs it to the cloud automatically. </Accordion> <Accordion title="Licensing" icon="id-card"> Assign and remove Microsoft 365 licenses, and look up friendly license names from SKU IDs. Read each subscription's **renewal or expiration date**, status, trial flag, and seat total straight from Microsoft — including SKUs you did not buy through a marketplace. To **add or remove** license seats through a marketplace (Pax8, TD SYNNEX, Partner Center, and others), see the dedicated [Change License Seats](/agents/tools/m365/change-license-seats) and [List License Subscriptions](/agents/tools/m365/list-license-subscriptions) tools. Free and self-service SKUs publish no renewal date, and a subscription bought outside the tenant's own purchase channel may not appear. Ask the agent to check the Microsoft 365 admin center for those. </Accordion> <Accordion title="Groups" icon="users"> Add and remove users from security groups, Microsoft 365 groups, distribution lists, and mail-enabled security groups. Search and list groups across Entra ID and on-prem AD. </Accordion> <Accordion title="Directory roles" icon="shield-halved"> Assign and remove Entra ID directory roles (Global Admin, Exchange Admin, User Admin, and so on) and view a user's current role assignments. </Accordion> <Accordion title="Mailboxes" icon="envelope"> Convert mailboxes to shared, create and delete shared mailboxes, configure delegation (full access, send-as, send-on-behalf), and set up or remove email forwarding. Works with Exchange Online and on-prem Exchange Server. </Accordion> <Accordion title="Conditional Access" icon="filter"> List, view, create, update, and delete Conditional Access policies. Destructive changes always require technician approval, regardless of workflow settings. </Accordion> <Accordion title="Devices" icon="mobile"> View user devices in Intune; remote wipe and retire mobile devices. Device deletion is always blocked for safety. </Accordion> <Accordion title="App registrations & OAuth governance" icon="key"> Review app registrations, service principals, and OAuth consent grants — app inventory, third-party app audits, client secret expiry checks. Create dedicated app registrations (for example, a send-only Mail.Send app for a notifications mailbox), and rotate client secrets on existing app registrations after the customer re-grants Neo access. Every write requires technician approval. Admin consent always stays with your technician — Neo prepares the consent link, a Global Admin clicks it. **Client secret values are never exposed to the agent or written to ticket notes** — when Neo creates a secret, the value is pushed to a one-time secure link (the same self-destructing link used for password resets) that the agent shares for retrieval. </Accordion> <Accordion title="On-prem Active Directory & Exchange Server" icon="server"> Full AD and Exchange Server management via your RMM: user and computer accounts, organizational units, group operations, infrastructure queries, mailbox and recipient management, mail flow, and Entra Connect sync triggers. </Accordion> </AccordionGroup> ## Permissions & Safety Each Microsoft integration is split into permission groups, and every group has an access level: | Level | What the agent can do | | - | - | | **Disabled** | No access to this category | | **Read Only** | Query and list operations only | | **Read / Write** | Full access including create, update, and delete | You can require **technician approval** on any permission group, and some destructive operations (deleting a user, wiping a device) always require approval even when the group doesn't. A few operations (deleting a domain, deleting a device) are blocked entirely. Quick-start profiles — **Read Only**, **Helpdesk**, **IT Admin**, **Full Automation** — configure every permission group at once. **Service Health** is read only — Microsoft exposes no write for it — and a client company connected before 3 September 2026 needs one Microsoft permission step before its first call succeeds, which differs for direct-consent and GDAP companies. See [Service Health](/integrations/m365/intro#service-health). A group badged **Coming Soon** is not released: the Microsoft access behind it has not been granted to Neo, so it stays **Disabled** and cannot be switched on. No group is in that state today. See [Coming Soon permission groups](/integrations/m365/intro#coming-soon-permission-groups). ## Test Mode With [test mode](/core/configuration-reference#test-mode-and-re-running) on, an agent reads Microsoft 365 and Active Directory exactly as it would on a real run. Looking up a user, listing groups, checking which licences you have left — all of it reaches your live tenant and returns real data, so the agent reasons from the same facts either way. PowerShell is the one exception. An Exchange or Active Directory script the agent writes itself does not run in test mode, even one that only reads. A script can change things in more ways than Neo can rule out from its text, so during a rehearsal Neo holds every script back rather than guess. The agent still reads through Microsoft Graph and the built-in Active Directory lookups, which is where most of what it needs comes from. What test mode holds back is every change: creating or updating a user, assigning a licence, editing group or role membership, mailbox and device changes, and every PowerShell script. A blocked Microsoft Graph change is recorded by its operation only, such as creating a user, never its values, because these requests can carry passwords and other secrets. Where Neo sends that record, and when it doesn't, is set by [Report test results via](/core/configuration-reference#test-mode-and-re-running). <Card title="Configure Microsoft 365 permissions" icon="microsoft" href="/integrations/m365/intro"> Full details on Graph, Active Directory, and Exchange permission groups, access levels, and quick-start profiles. </Card> <Tip> Start with **Read Only** or **Helpdesk** and keep technician approval on for writes. Expand the permissions as you build confidence in the agent's behavior. </Tip> # Add Time Entry Source: https://docs.neoagent.io/agents/tools/management/add-time-entry Add time entries to tickets for work performed The Add Time Entry tool allows Neo Agent to log a **customer-visible** time entry on the ticket in your PSA — duration, billable flag, work type, and a note describing what was done. <Info> Enabled when you grant the **Time Entries** write permission on your PSA integration (the workflow's **Integrations** tab) — the settings below live on that permission group. Agents only call this tool when there's customer-relevant work to report. Saved-time analytics are separate: on every Agent run that takes a substantive action, the agent gives its estimate of the technician time saved in its final answer, and a run that takes no action gives none. Chat Agent conversations record no saved-time estimate. The estimate feeds **Time Saved** in [Analytics](/product/analytics). </Info> ## What It Does When enabled, the agent can: * Add time entries to tickets * Set duration and billable status * Include detailed notes about work performed * Communicate resolution to end clients (time entries are often client-visible) <Tip> Use custom instructions to specify how much time to add and what message format to use. Example: "Add 15 minutes for simple tickets, 30 minutes for complex tickets, focusing the message on resolution steps." </Tip> <Note> **Work type.** To put every entry the agent logs on one work type, pick it on the **Time Entries** permission group. The setting is **Work Type** on Autotask and ConnectWise, **Charge Rate** on HaloPSA and **Labor Product** on Syncro. The list shows the values from your own PSA. Leave it on **PSA default** and your PSA applies its own default, as it did before the setting existed. The setting covers the entries this tool logs; a time entry Neo creates another way, such as a Notify Ticket Contact action set to **Time Entry**, keeps your PSA's default. ServiceNow time entries have no work type, so ServiceNow has no such setting. The agent is told which work type the tool uses, by the name your PSA listed when you picked it, so an instruction such as "log customer messages under the Communication work type" is met by the tool itself. If you rename the work type in your PSA later, pick it again so the agent sees the new name. The agent then has no reason to write the entry through the PSA API tool to set a work type, a route that skips the checks on this page, such as the contact check and the per-run entry limit. </Note> <Note> **The entry's text and the customer message.** Every entry the agent logs has one description of the work, written so the end user could read it, and an optional internal note for technicians. When the entry is also the agent's message to the ticket contact, the agent marks it so, and Neo delivers it the way your PSA is set up. Neo never changes where your PSA files the entry, and the run result says when the message did not reach the contact: * **ConnectWise:** Neo asks ConnectWise to email the contact only for a message entry; every other entry goes out with all email flags off. Your board's time-entry default decides whether the entry lands in Discussion or Internal, and a ticket whose automatic email setting is on still emails the contact for a Discussion entry. Neo reads the saved entry back: the run result says when the board filed a message as Internal, so the contact received nothing, and when the ticket's setting emailed an entry that was not a message. * **Autotask:** a message entry sets your workflow UDF, when you turned that on (see below). Other entries leave the UDF alone. * **HaloPSA, ServiceNow and Syncro:** a time entry is not Neo's route to the contact, so the run result says Neo did not send the message, and the agent sends it with [Add Client-Facing Ticket Note](/agents/tools/communication/add-client-facing-note) if it must reach them. The internal note is written as its own internal note beside the entry. When your internal-notes permission group requires technician approval, the agent adds that note with Add Internal Ticket Note, which asks for it. </Note> <Note> **Whose time entry is it?** An entry an automation creates is recorded against Neo's own PSA resource, so it doesn't touch anyone's timesheet. An entry a technician asks a [chat agent](/chat-agents/building-a-chat-agent#psa-records-carry-the-technicians-name) for is recorded against **that technician** — so "log 20 minutes on this ticket" from Teams counts toward their utilization. Automatic on every PSA, as long as the technician is mapped to their Microsoft account. </Note> <Note> **Autotask resource/role handling.** Autotask only accepts a time entry when the resource is actually associated with the role in its ResourceRoles — and a resource's default service-desk role (used for ticket assignment) is sometimes *not* one of them. When that happens, Add Time Entry automatically looks up the resource's valid roles and records the time entry under one of them (preferring the ticket's assigned role, then the resource's default role) instead of failing the run. If the resource has no usable role at all, the agent leaves an internal note so a technician can fix the role mapping in Autotask. Some tickets accept time under one role only, usually the role assigned on the ticket, and Autotask names that role when it rejects the entry. Add Time Entry then records the entry under that role, as long as Neo's resource holds it in ResourceRoles. If the resource does not hold it, the agent leaves an internal note that names the role, so a technician can add the role to the resource or change the ticket's role. </Note> <Note> **Autotask: entries wait in Approve & Post.** Autotask never auto-posts time entries created through its API — Neo's entries (like any integration's) sit in **Approve & Post → Labor** until posted there, even on a contract set to post immediately. A bulk select-all in that view clears the queue in one click. Details: [Time entries stay Not Posted](/integrations/psa/autotask/overview#time-entries-stay-not-posted). </Note> <Note> **Sending more than one customer message in a run.** Some MSPs deliver every customer message as a time entry (one time entry per communication — common on Autotask, where a workflow rule emails the contact when a UDF flips). When a single run genuinely needs to send two customer messages — for example an intake or clarification message, then a dispatch acknowledgement after a short idle wait — the agent can create a second customer-facing entry for the second message. What stays blocked is stacking *log-only* entries (no customer message) to "correct" or annotate a prior one, and an unusually high number of customer messages in one run — both are noise the guard exists to stop. </Note> <Note> **Autotask: who emails the end user.** On Autotask, the end-user message goes into the time entry's Summary Notes. Neo does not send an Autotask Quick Notification and does not email the contact itself, and Summary Notes alone send no email. Only an Autotask notification or workflow rule that your team has set up emails the contact. Turn on **Use UDF field to trigger Autotask workflow** in the tool settings and Neo sets that UDF to true on an entry that carries a customer message, which starts a workflow rule built on that UDF. An entry without a customer message leaves the UDF alone. Neo cannot see whether Autotask sent the email, and the run result says so. If your instructions tell the agent to confirm a Quick Notification, the agent records that the entry was created and that Neo has not confirmed the notification. It does not send the message a second time. </Note> <Note> **A ticket with no contact gets no customer message.** The customer message on a time entry needs somebody to deliver it to. When the ticket has no contact, Neo does not send the entry as a message, and the run result says the end user received nothing — the same answer [Add Client-Facing Ticket Note](/agents/tools/communication/add-client-facing-note) already gives, so the agent cannot route around it by switching between the two. The time entry is still logged, and its description still records the work. A ticket one of your own engineers raised usually has no contact on it. Those runs now record their outcome on an internal note and in the dashboard summary instead of writing to a customer-visible field nobody is attached to. </Note> <Note> **The internal note on an entry follows your internal-notes permission group.** Set **Ticket Notes (Internal)** (**Actions (Internal Notes)** on HaloPSA, **Work Notes** on ServiceNow and Syncro) to Read-only or Disabled, and the agent leaves the internal note off the entry. The time entry is still logged, and the run result says the note was not written. Only those two values suppress it. The group that counts is the one on the PSA the ticket came from. ConnectWise and Autotask keep the internal note on the entry itself. On HaloPSA, ServiceNow and Syncro a time entry has one note field, so Neo writes the internal note as its own internal note beside the entry, under the same permission. </Note> <Note> **HaloPSA Outcomes.** A Halo time entry is posted under an Outcome. If you allow more than one on the **Time Entries** permission group and pick no specific one, Neo takes the first in your list — but it skips Halo's built-in **Journey** steps (Start Journey, Arrive On Site, Leave Site, End Journey). Halo rejects those on any ticket with no site visit open, so they can never carry a time entry. If your allowed list holds nothing else, Neo sends the generic **Time Entry** Outcome instead, which is what it already sends when no Outcome is configured at all. </Note> <Note> **Start and end clock times.** On PSAs that store a real start and end (Autotask, ConnectWise, Syncro), the entry starts when the agent began working the ticket, and ends at that start plus the logged duration. The start is never earlier than the ticket's own creation time, so an entry created moments after a ticket opens cannot begin before the ticket existed. Halo and ServiceNow record only the duration, so start and end do not apply to them. The start is not rounded to a clock boundary. To bill in fixed increments, tell the agent the increment you want in your custom instructions — for example "always log time in multiples of 15 minutes" — and it will choose the duration accordingly. Custom instructions control the **duration**, not the start time. </Note> <Note> **Closed tickets.** A PSA won't accept a time entry on a completed/closed ticket, so the agent always logs time *before* it closes a ticket. If a ticket does end up closed before the entry lands, Neo does not silently drop it: it reports that no time entry was recorded and does not count the failed attempt against the run's entry budget, so the agent can reopen the ticket and add the required entry — or, if the ticket can't be reopened, leave an internal note so a technician can add the entry manually. </Note> ## How to Use 1. Enable the tool in your workflow 2. Configure approval requirements 3. Provide custom instructions on time amounts and message format ### Example Instructions ``` Add 15 minutes for password resets. Add 30 minutes for software installations. In the time entry notes, summarize what was done to resolve the issue. ``` # Attach File to Ticket Source: https://docs.neoagent.io/agents/tools/management/attach-file-to-ticket Attach a file to a PSA ticket: an export, log or report the agent produced, a file it downloaded such as an email or PDF, or a screenshot your team pasted into a chat The Attach File to Ticket tool puts a file onto a PSA ticket as a **real attachment**, instead of pasting the contents into a note or asking a technician to upload it by hand. The file can come from three places: * **A file the agent produced** during a run — a CSV or XLSX export, a diagnostic log, a generated report. * **A file the agent downloaded** during a run — for example a reported phishing email (`.eml`) fetched from a shared mailbox, or a PDF from another system. * **A screenshot or file your team shared in a chat** with an internal Chat Agent — for example an error screenshot pasted into Teams with "create a ticket for this and attach the screenshot". A file the agent downloaded or wrote with a script is saved in its [sandbox](/agents/tools/built-in/sandbox) first. The agent names that file, and Neo sends its exact bytes, so an email or PDF arrives on the ticket unchanged, at any size up to 10 MB. A short file the agent wrote itself can also go in directly as text (CSV, TXT) or base64 (a small XLSX or image). For a file from the chat, Neo takes the file exactly as it was shared, with its original name and type. Each way, Neo attaches it to the ticket using your PSA's attachments API. Neo reads an attached email (`.eml`) or PDF back on the next ticket load (see [Reading Email and PDF Attachments](/core/reading-email-attachments)). <Info> Works on **ConnectWise, Autotask, Halo, and ServiceNow**. Enable it on the tools list of an agent. </Info> ## What It Does When enabled, the agent can: * Attach an exported file (for example a leaver/offboarding export) to the originating ticket * Attach a diagnostic log or generated report it created while resolving the ticket * Attach an email or document it downloaded, for example a reported phishing email kept as evidence on the security ticket * Attach screenshots and files a technician shared in the chat, including ones sent a few messages before the ticket existed * Choose a descriptive file name and the correct file type so the attachment opens cleanly in your PSA ## Screenshots and Files From a Chat When a technician pastes a screenshot into a chat with an internal Chat Agent, the agent can already see it. With this tool enabled, the agent can also put that same file on a ticket. The technician does not need to upload it to the PSA by hand. * The agent attaches only the files the technician asks for. It does not attach every image in the conversation. * A file stays available after the message that carried it. The usual order is: the technician sends the screenshot, the agent asks a question or two, and then it creates the ticket. The screenshot still attaches at that point, with no need to send it again. * The agent can only attach files that were shared in the same conversation. If this tool is not enabled on the agent, the agent says so when asked to attach a shared file. Your end users' Chat Agent does this with its own locked-on tool; see [Sharing screenshots and files](/agents/tools/end-user/overview#sharing-screenshots-and-files). ### Screenshots Inside a Halo Note On Halo, the agent can also show a screenshot **inside an internal note**, the way it looks when a technician pastes an image into a note. Ask for it in plain words, for example "put this screenshot in a note on ticket 5589". The agent writes one internal note with a short line about the image and the image below it, and it still attaches the file to the ticket. * The note follows the same rules as the agent's other internal notes: the outcome you set for Neo's notes, the limit on notes per ticket, and technician approval if you require it for notes. * The agent needs write access to Halo notes (the **Actions** permission group). Without it, a request for the note is refused and nothing is written; the agent tells you why and can attach the file without the note. * Only images show inside a note. Other files, such as a PDF, are attached as usual. ## When It's Used Neo reaches for this tool when a task calls for an artifact to live on the ticket — for example an offboarding run that exports a user's mailbox/permission summary, or an audit that produces a CSV the technician needs to keep with the ticket. Without it, the agent could only describe the export in a note and leave the upload to a human. ## When the Attachment Fails If your PSA is temporarily unavailable or returns a server error while storing the file, Neo automatically retries the upload a few times. If the attachment still can't be saved, the tool reports a clear failure back to the agent instead of stopping the run — so the agent can fall back to posting the file's content in an internal note (or asking a technician to attach it) and finish the work rather than leaving it half-done. Genuine setup problems (for example the PSA API user lacking permission to add attachments) are surfaced as an action item so you can fix them. <Tip> Use custom instructions to steer the file format and naming — for example: "When you export a leaver summary, attach it to the ticket as a CSV named `<user>_leaver_<date>.csv`." </Tip> # CentralReach API Source: https://docs.neoagent.io/agents/tools/management/centralreach-api Create, update and deactivate employee accounts in your clients' CentralReach practices, set their labels and custom fields, and assign tasks; schedules, files, patient records, billing and payroll when you turn them on The common use is staff onboarding and offboarding at an ABA practice: after the agent creates the new hire's Microsoft 365 account, it creates their CentralReach employee account; when someone leaves, it deactivates them with a termination date. <Info> Automatically enabled when you configure CentralReach permissions in your agent workflow. CentralReach is connected per client, so the agent calls the CentralReach organization of the ticket's company. </Info> ## What it does * Find an employee by name, email or the id from the practice's HR or payroll system * Create an employee, update their record, and deactivate them with a termination date * Convert a generic contact to an employee * Read and set an employee's claim settings and identifiers, such as an NPI number * Read and set a contact's labels and custom field values * Read, create and assign tasks, one at a time or for many employees at once * Read a provider's or client's appointments, cancel an appointment, and set employee and client availability * Read, create, label and delete files on a contact's record * Read and update client (patient) records and payors, and read their authorizations * Read billing entries, balances and payments, record or void a payment, and read service codes * Read payroll settings, an employee's pay settings and timesheets Neo replaces the value of the social security number field (`ssn`) in every CentralReach answer, so the agent never reads a stored SSN, and it refuses a request that sets that field: a person enters an SSN in CentralReach. Neo also refuses an employee or client update that does not say whether the person stays active, because CentralReach deactivates a contact when it does not recognize that value. ## How the agent changes or deactivates an employee The agent sends only the fields that change. Before the update, Neo reads the employee's stored record and fills in each field the agent left out, the stored SSN included. Neo does not fill the provider drive time rate, or the language when the record lists several, because the stored record names them differently: CentralReach may clear those two on an update, and the agent says so when the employee has them. To offboard someone, the agent sends two fields: inactive, and the termination date. With an access profile that asks first, the technician approves exactly those changes. ## How the agent handles a new hire The agent reads the ticket for the new hire's name, work email, date of birth, hire date and the id the practice's HR or payroll system gives them. It looks the person up first, then creates the employee with the employee contact form your instructions name. When the ticket is missing a value CentralReach requires, the agent asks for it. It then adds the labels and custom field values your instructions give for the role. ## Writes that always ask a technician Three writes wait for a technician's approval under every access profile, Full Automation included, whatever the group's own approval setting: * Recording a payment against a billing entry * Voiding a payment * Deleting a file A payment moves the practice's money, and a deleted file can be a patient's medical record, so no setting lets an agent make these on its own. ## Permission groups | Group | Access levels | Covers | | - | - | - | | Employees | Disabled, Read Only, Read / Write | Staff records: create, update, deactivate, convert to employee; addresses, claim settings, appointment types | | Contact Labels & Custom Fields | Disabled, Read Only, Read / Write | Contact labels and custom fields of any contact, employee or client | | Tasks | Disabled, Read Only, Read / Write | Tasks, task templates and task labels | | Schedules & Availability | Disabled, Read Only, Read / Write | Appointments by provider or client, cancelling one, unconverted services, employee and client availability | | Files | Disabled, Read Only, Read / Write | A contact's files and file labels; deleting a file always asks a technician | | Clients (Patients) | Disabled, Read Only, Read / Write | Client records, addresses, payors, accepted insurances, authorizations | | Billing & Payments | Disabled, Read Only, Read / Write | Billing entries and balances, payments, billing labels, service codes; recording or voiding a payment always asks a technician | | Payroll | Disabled, Read Only | Payroll settings, an employee's pay settings, timesheets | ## Access profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Reads of employees | No write is allowed | | **Helpdesk** | Reads of employees | Creating, changing or deactivating an employee | | **IT Admin** | Every read and write in Employees | Nothing | | **Full Automation** | Every other supported call, in every group | Recording or voiding a payment, and deleting a file | Read Only, Helpdesk and IT Admin turn on Employees alone. Every other group can reach patient health information or staff pay: labels, custom fields and tasks take any contact, a client's included. Turn a group on by hand for an agent that needs it, such as Contact Labels & Custom Fields for an onboarding agent that sets a new hire's labels. # Create TimeZest Scheduling Link Source: https://docs.neoagent.io/agents/tools/management/create-timezest-link Generate a TimeZest booking link so the end user can self-schedule with a technician The Create TimeZest Scheduling Link tool lets a Neo Agent generate a TimeZest booking URL for a ticket. Instead of the agent (or a technician) playing email tag to find a time, it sends the end user a link to pick a slot themselves; TimeZest handles the calendaring and writes the appointment back to your PSA. <Info> Requires the [TimeZest integration](/integrations/timezest/overview). </Info> ## What It Does When enabled, the agent can: * Pick the appropriate TimeZest appointment type for the ticket * Generate a scheduling link for the ticket's contact * Share the link via a ticket note or email so the end user can book a time Use it whenever a ticket needs a scheduled call or on-site visit and you'd rather the customer choose the time. ## Naming Appointment Types and Technicians Write appointment types, technicians and teams in your instructions by the names they have in TimeZest. The agent passes those names, and Neo reads your TimeZest lists and finds the match itself. A difference in capital letters, spacing or punctuation still matches: "Level 1" finds a team named "\*Level 1". TimeZest IDs work too. When a name matches nothing, or matches more than one option, Neo creates no link and gives the agent the list of valid names, and the agent tries again with one of them. When you add or rename an option in TimeZest, Neo reads the lists again before it reports a name as unknown. TimeZest lets two options share a name, such as two appointment types both called "Phone Call". Neo then gives the agent each option's ID, and the length of each appointment type, and the agent picks one by its ID. To make sure the agent picks the right one, say which one in your instructions, for example "the 15-minute Phone Call", or give each option a different name in TimeZest. ## Two Delivery Modes The agent chooses how the booking link reaches the end user: | Mode | What happens | When to use | | - | - | - | | **Generate a link** (default) | TimeZest returns a scheduling URL; **Neo** delivers it via a note or email. TimeZest sends nothing itself and does **not** run any workflows attached to the appointment type. | The default. Use it when Neo should control delivery, or when the appointment type has no TimeZest workflows. | | **Send via TimeZest** | **TimeZest** emails the link to the end user and runs any TimeZest workflows/automations (reminders, follow-up sequences) configured on that appointment type. | Use it when you rely on TimeZest's own reminders/follow-ups, i.e. workflows that only fire when TimeZest itself creates and sends the scheduling request. | <Warning> In **Send via TimeZest** mode, TimeZest already emailed the link — so tell the agent **not** to also paste it into a note or email, or the customer receives it twice. The tool's own response says the same, so the agent knows the link is already delivered. </Warning> Behind the scenes these map to TimeZest's `generate_url` and `pod` trigger modes respectively. The default (`generate_url`) is unchanged from previous behavior, so existing workflows keep working exactly as before. <Note> TimeZest needs a real end-user **name and email** to build a booking link. Before calling TimeZest, Neo checks the ticket's contact and — if it's missing a name or email — falls back to the company's primary contact. If neither resolves, Neo **skips the TimeZest call** and returns an actionable message asking you to add a contact name and email (or set a primary company contact) and re-run, rather than failing with an opaque error. </Note> ## Safety | Control | Behavior | | - | - | | **Test mode** | When test mode is on, the agent decides it would send a link but doesn't actually create one | | **Appointment types are yours** | The agent can only use TimeZest appointment types you've already configured | ## How to Use <Steps> <Step title="Connect TimeZest"> Set up the [TimeZest integration](/integrations/timezest/overview) and configure your appointment types in TimeZest. </Step> <Step title="Enable the tool"> Add **Create TimeZest Scheduling Link** to the workflow's tool list. </Step> <Step title="Tell the agent when to use it"> In custom instructions: "When a ticket requires an on-site visit, send the contact a TimeZest link for the 'On-site visit' appointment type and add a note explaining what was booked." To rely on TimeZest's own reminders and follow-up sequences, tell the agent to **send the link via TimeZest** for that appointment type — TimeZest then emails the link and runs those workflows, and the agent won't add its own copy. </Step> </Steps> <Tip> Combine with [Add Client-Facing Note](/agents/tools/communication/add-client-facing-note) or [Send Email](/agents/tools/communication/send-email) so the link reaches the customer the way you prefer. </Tip> # External API Request Source: https://docs.neoagent.io/agents/tools/management/external-api-request Let agents call external APIs and webhooks through your Custom API connections The External API Request tool lets an agent call external APIs, webhooks, or internal services as part of ticket processing. The APIs themselves are configured once as [Custom API connections](/integrations/custom-api/overview) on the Integrations page; this tool gives one agent access to the connections you pick. This tool is **Advanced — 3 credits**. On a ticket-triggered agent that is the per-run price (if no other chosen tool is higher). On a [scheduled](/core/scheduled-agents) or [chat](/chat-agents/sessions-and-billing) agent it is **3 credits per call**. It is not the [Neo API](/agents/tools/management/neo-api) tool (that one is Free), and it is not the API *skills* listed under Built-in Capabilities (those are free to load). See [Tool credit costs](/agents/tools/credit-costs). ## What It Does When enabled, the agent can: * Call any connected API by its connection name (GET, POST, PUT, PATCH, or DELETE) * Authenticate with the connection's stored credential — API keys (in a header or in the web address), Bearer tokens, Basic Auth, or OAuth 2.0 * Fill in the path placeholders, query parameters, and body fields the connection defines * Process and act on API responses <Info> This tool is ideal for integrating with systems Neo doesn't natively support. </Info> ## How to Use <Steps> <Step title="Connect the API"> On [**Integrations**](https://dashboard.neoagent.io/integrations), open **Custom API** and add a connection — endpoint, authentication, and the fields the agent can fill. The wizard walkthrough is on the [Custom API page](/integrations/custom-api/overview). </Step> <Step title="Pick it in the agent"> Enable **External API Request** in the agent's toolbox and choose the connection under **Connected APIs**. One agent can use several connections. </Step> <Step title="Add Custom Instructions"> Guide the agent on when and how to use each API. Include: * Conditions for calling the API * How to map ticket data to request fields * What to do with the response Refer to each API by its connection name — that's the name the agent sees. </Step> </Steps> <Note> Agents configured before Custom API connections existed carried per-agent inline API configurations. Those were migrated to connections and the inline editor is gone; anything still writing inline configurations through the [API](/developers/introduction) keeps working during the deprecation window, but new setups should create connections. </Note> ## Example: Kick-off a Rewst Workflow <Frame> <img alt="Rewst user onboarding" /> </Frame> If you have a Rewst workflow that you want Neo to decide when to kick off, connect the webhook URL as a Custom API connection and give it to the agent. **Connection (on the Integrations page):** * **Name**: `rewst_user_onboarding` * **Web address**: `https://engine.rewst.io/webhooks/custom/trigger/<your-trigger-id>/<your-org-id>` * **What Neo does there**: POST * **Authentication**: your preferred method (webhook URLs are often pre-authenticated — **No key needed**) **Information Neo sends (body fields on the connection):** | Name | Type | Description | Required | | - | - | - | - | | `user_email` | String | The email of the user to onboard | Yes | | `user_name` | String | The name of the user to onboard | Yes | | `user_phone` | String | The phone number of the user to onboard | Yes | | `microsoft_licenses` | String | The Microsoft licenses to assign to the user | Yes | A field's type can also be **List**, for an API that wants a JSON array — an SMS gateway whose `to` field takes `["3546618111"]`. The agent sends a List body field as an array, and a List query parameter as repeated `?name=value` pairs. <Note> The trigger and org IDs are the same on every call, so paste the real values into the address. Use `{placeholder}` braces only for values that change per ticket — each one becomes a required input the agent fills. </Note> ## Example: Slack Webhook Alert Send alerts to a Slack channel when high-priority tickets arrive: **Connection:** * **Name**: `slack_high_priority_alert` * **Web address**: `https://hooks.slack.com/services/YOUR/WEBHOOK/URL` * **What Neo does there**: POST * **Authentication**: No key needed (the webhook URL is pre-authenticated) * **Information Neo sends**: one field, `text` (String, required) — the message to post **Custom Instructions on the agent:** ``` When a ticket has priority "Critical" or "Emergency", use the slack_high_priority_alert API to notify the team. Include the ticket number, company name, and a brief summary of the issue. ``` ## Best Practices <AccordionGroup> <Accordion title="Use descriptive connection names"> Choose names that clearly indicate purpose: `jira_create_issue`, `pagerduty_alert`, `custom_crm_update`. The agent uses these names to decide which API to call, and your instructions reference them. </Accordion> <Accordion title="Write detailed field descriptions"> The agent relies on the connection's field descriptions to map ticket data correctly. Instead of "The message", write "A summary of the ticket issue including the error message and affected user". </Accordion> <Accordion title="Test with approval enabled first"> Enable technician approval when an agent first gets a new connection. Review the requests the agent wants to make before allowing autonomous operation. The setting covers the agent's sandbox scripts too: while it is on, a script can read from your APIs but not write to them, so each write goes through the tool and its approval. </Accordion> <Accordion title="Handle errors gracefully"> Add custom instructions for what the agent should do if the API returns an error — retry, escalate, or add a note to the ticket. </Accordion> <Accordion title="Test the connection before going live"> Use the **Test** button (▶) on the connection to verify connectivity and authentication before enabling the agent. This catches credential issues early. </Accordion> </AccordionGroup> # Generate Password Source: https://docs.neoagent.io/agents/tools/management/generate-password Generate secure passwords for user accounts The Generate Password tool allows Neo Agent to create secure, random passwords that meet complexity requirements. ## What It Does When enabled, the agent can: * Generate cryptographically secure passwords * Meet standard complexity requirements * Provide passwords for use in other operations ## How to Use This tool is typically used in conjunction with: * **Microsoft Graph API** — to set the password on a new or existing M365 account * **Execute PowerShell (Active Directory)** — to set it on an on-premises AD account * **Generate Secure Link** — to securely share the password ## Password Redaction in the Run History A password generated by this tool is redacted from the run history — the steps Neo Agent records for that run, and the run's own closing message on Event History. The agent still works with the real value — a password reset cannot happen without it — but the stored copy shows `***MASKED***` in its place. This covers the places a password used to become readable after the fact: * The password field in the tool's own result. * A password written into a script the agent runs, such as the `Set-ADAccountPassword` command in an on-premises Active Directory reset. * A password a script prints in its own output. * A password the agent mentions in its own reasoning step, both while the step streams and in the final saved version of it. * A password the agent quotes in the message it reports back at the end of the run. This redaction matches the exact value Neo Agent generated, so it is complete for a password this tool produced. A password the agent writes itself, which Neo Agent never held as a value, is covered instead by the script-literal redaction in the [audit log](/product/audit-log), and that one reads the script rather than a known value. So keep passwords out of script output — the **Writing PowerShell** skill instructs the agent to return a status instead of printing one. Redaction covers the run history, not the ticket. Deliver the password to the person with **Generate Secure Link** and put only the link in a ticket note — a password typed into a note is stored by your PSA, where Neo Agent cannot redact it. ## Do Not Ask the Agent To Make the Password Inside a Script Agent instructions sometimes tell the agent to skip this tool and let the reset script invent the temporary password itself. That cannot work alongside delivering the password: the value then exists only on the machine that ran the script, so either nobody can tell the user their new password, or the script has to print it and the secret lands unredacted in the run history. Value masking covers only a password Neo Agent generated, and the script-literal redaction reads the script's text rather than what the script printed. From there anyone can copy it into a ticket note. Let the agent call **Generate Password** first and pass that value into the script. The value is then masked by value in the run history, and **Generate Secure Link** has something to deliver. Your instructions still decide *how* the password reaches the person — which channel, which note, whether a secure link is allowed at all. # Generate Secure Link Source: https://docs.neoagent.io/agents/tools/management/generate-secure-link Create secure, time-limited links for sharing secrets like passwords The Generate Secure Link tool lets a Neo Agent create a secure, expiring link for sharing a **secret** — a password, an API key, a client secret, or a one-time credential. ## Secrets only The link is intentionally expiring and view-limited (PushPwd), which is correct for a secret and wrong for anything the recipient needs to keep. Use this tool **only** for a genuine secret. Do **not** put a report, an export, or general/tabular data (a CSV, a table of results, an analysis) through this tool. That data is not a secret, and a self-destructing link is the wrong way to deliver it — the recipient loses it when the link expires. For non-secret results: * Small result → the agent shows it inline in the chat or on the ticket. * Large result → the agent builds the file and emails it to the recipient as a durable attachment, so they keep a copy after the chat. ## What It Does When enabled, the agent can: * Generate a secure link for a secret using PushPwd * Share the secret behind an expiring, view-limited link — it stays usable until it expires or the view limit is reached, so it is not spent after the first open ## How to Use 1. Agent generates or receives a secret (like a password) 2. Agent creates a secure link for that secret 3. Link is shared with the user 4. Link stops working once it expires or the view limit is reached ### Example Use Case ``` 1. Generate a new password for a user 2. Create a secure link for the password 3. Send the link to the user 4. User clicks the link to view the password, before the link expires ``` # Merge Tickets Source: https://docs.neoagent.io/agents/tools/management/merge-tickets Merge a duplicate ticket into another ticket in your PSA Before it merges, Neo checks both tickets: a ticket that is already merged is not merged again, and a target that was itself merged is followed to the ticket it went into. ## What It Does When enabled, the agent can merge one ticket into another. If the source ticket is already merged, Neo reports that and makes no change. If the target was already merged into the source ticket, the two tickets are already combined and Neo makes no change. If the target's merges form a loop, Neo does not merge into any ticket in that loop. The agent tries one other open duplicate of the source; if there is none, it leaves an internal note on the source with the merge chain, so a technician can find the right ticket. The source ticket's status and queue stay as they were. ConnectWise only merges tickets of the same company. If the two tickets belong to different companies there, Neo makes no change and names both companies in the run. To merge them, move one ticket to the other's company in your PSA first. ## Which PSAs * **ConnectWise and Halo**: the PSA's own merge. * **ServiceNow**: the source incident gets the target as its parent and is closed as a duplicate. * **Autotask**: Autotask has no merge. Neo adds the source contact to the target ticket, adds a note to both tickets, and closes the source ticket. It also copies the source description and notes to the target, unless the agent turns note copying off for that merge. Syncro is not supported. ## How to Use Enable a ticket search tool as well, such as **Find Tickets by Content**, so the agent can find the duplicate. ### Example Instructions ``` If a new ticket is from the same contact about the same issue as an open ticket from the last 24 hours, merge the new ticket into the older one. ``` # Neo API Source: https://docs.neoagent.io/agents/tools/management/neo-api Let the agent read and configure Neo itself through Neo's public API The Neo API tool gives a Neo Agent access to Neo's own public API (`/public-api/*`). Use it for "meta" automations — agents that report on other agents, reconcile configuration, kick off other workflows, manage technician-in-the-loop requests, or escalate to the Neo team. This tool is **Free** at every permission level. It is not [External API Request](/agents/tools/management/external-api-request) (3 credits per call on scheduled and chat agents). See [Tool credit costs](/agents/tools/credit-costs). <Info> Automatically enabled when you set **Neo API** permissions in your agent's **Integrations** tab — there is no separate toggle in the tool list, the same way the PSA, RMM, and documentation API tools work. Access is scoped by permission groups. Want to call the API from your own code rather than from an agent? See the [public API documentation](/developers/introduction). The full OpenAPI spec is also served at `/public-api/openapi.json`. </Info> <Note> **Also reachable from a sandbox script.** An agent with the [Code Execution sandbox](/agents/tools/built-in/sandbox) can call the same routes in Python (`from neo.client import api_request`), under the same permission groups and approval rules — nothing extra to enable. That is worth using when the job spans **many** things: comparing a setting across a fleet of agents, auditing which workflows carry a configuration, or pulling executions and summarising them. For a single read or change, the tool is the better route — one call does not justify a sandbox. </Note> ## What It Does * Read and configure **agents** (workflows) — list, inspect, enable/disable, update settings, and set an agent's [daily credit alert](/product/billing-and-credits#a-daily-credit-alert-for-one-agent) * Browse Neo's curated **templates** library — starting points for new agents * Query **executions** and **event history** — what ran, when, and what it did * Fetch **artifacts** produced by an execution — markdown notes inline, sandbox-file downloads via short-lived URLs * Inspect **callbacks / triggers** — see why a workflow did or didn't match an event * Manage **technician-in-the-loop** requests — list pending approvals, see decisions * Look up **RMM script runs** the agent has launched * Read **settings**, **end companies**, and **integrations** configuration * Pull **observability**, **performance** rollups, and **billing/credits** data — including end-user (white-label) Teams bot **active-user (MAU)** usage and its monthly charge * Trigger and read **Insights** ROI analyses * View **Phone Agent** numbers and call history * Read **chat sessions** * Build, read, refresh and delete **dashboards** (Beta): see [Dashboards](/product/dashboards) * Escalate an issue to the **Neo team** ## Permission Groups Like the other API-backed tools, Neo API access is split into permission groups, each set to **Disabled**, **Read Only**, or **Read / Write** — so you can give an agent read access to executions and analytics without letting it reconfigure other agents, for example. ## Safety Controls | Control | Behavior | | - | - | | **Opt-in** | Off unless you set at least one Neo API permission group above **Disabled** | | **Permission groups** | Scope exactly which parts of the API the agent can touch, and at what access level | | **Technician-in-the-Loop** | Require approval before configuration writes | | **Test mode** | When test mode is on, the agent plans writes but doesn't execute them | | **Same auth & rate limits as any API client** | Calls go through Neo's public API auth and per-tenant rate limiting | ## How to Configure <Steps> <Step title="Open the agent's Integrations tab"> Find **Neo API**. It needs no connection step — it's Neo's own API, so it's available on every tenant. </Step> <Step title="Set permission groups"> Choose an access profile, or set each permission group individually to decide which parts of the API the agent can read or write. Setting any group above **Disabled** gives the agent the Neo API tool. </Step> <Step title="Set approval requirements"> Decide whether configuration writes require technician approval. </Step> </Steps> <Tip> Start with **Read Only** — most "meta" agents (status digests, drift checks, "did workflow X run today?") never need to write anything. </Tip> # Trigger or Schedule Workflow Source: https://docs.neoagent.io/agents/tools/management/trigger-or-schedule-workflow Allow Neo to trigger workflows immediately or schedule them to run at a future time The Trigger or Schedule Workflow tool allows Neo Agent to trigger other configured workflows immediately or schedule them to run at a specific future date and time. It can also schedule the current workflow to re-run itself later. ## What It Does When enabled, the agent can: * Analyze the ticket and determine if another workflow should be triggered * Trigger any of the configured workflows immediately * Schedule a workflow (including itself) to run at a future date and time * Chain workflows together for complex, time-sensitive automation <Tip> Use custom instructions to specify WHEN and WHICH workflow(s) to trigger or schedule. Example: "If the ticket mentions employee termination, immediately trigger the Access Removal workflow and schedule the Account Deletion workflow for 30 days after the last day." </Tip> ## How to Use 1. Enable the tool and select which workflows can be triggered or scheduled 2. Provide custom instructions on when to trigger or schedule each workflow 3. Keep the allowlist focused on workflows you're comfortable being triggered automatically ### Example Instructions ``` Trigger the "User Onboarding" workflow when tickets mention: - New employee setup - New hire - Account creation needed When processing an employee termination: 1. Trigger the "Access Removal" workflow immediately 2. Schedule the "Account Cleanup" workflow to run on the employee's last day 3. Schedule the "Mailbox Archive" workflow to run 30 days after the last day ``` ## Triggering Immediately vs. Scheduling The tool supports two modes based on the situation: ### Immediate Trigger When the agent determines a workflow should run right now, it triggers it immediately for the current ticket. You can configure whether the agent should wait for the triggered workflow to complete before continuing. <Note> **Run only once per ticket** behaves differently on the two immediate-trigger paths, depending on whether the agent waits for the target to finish: * **Fire and forget** (the agent does not wait): if the target has **Run only once per ticket** enabled and has already succeeded on this ticket, the trigger is skipped and shows as **SKIPPED** in [Executions](/product/executions). The target's own guarantee holds. * **Wait for completion** (the agent waits for the target to finish before it continues): **Run only once per ticket is not enforced.** This path starts the target directly and does not go through the same check, so the target can run again on a ticket it has already processed. This difference is a known behaviour, not a setting you control. If you need the once-per-ticket guarantee to hold in both cases, add your own guard — for example, a filter or an internal note that the agent checks before it triggers the target. </Note> <Note> **In a chat agent, the agent never waits — "wait for completion" is ignored.** Someone is waiting for a reply, and these workflows commonly take six to eleven minutes, so a chat agent always uses the fire-and-forget path. Instead of waiting it tells you what it started and roughly how long that takes, and reads the result afterwards through **Get Workflow Run Status** (added automatically alongside this tool) so it can report what the run actually did. Ask it to check and it will. The setting still applies as written on ticket-triggered and scheduled agents, which have hours to work in and nobody waiting on them. A chat agent can only read runs of the workflows it is allowed to trigger — the list you set above. If it needs to report on another workflow, add that workflow to the list. </Note> ### Scheduled Execution When an action needs to happen in the future, the agent schedules the workflow to run at a specific date and time. This creates a **Scheduled Work** entry that you can view and manage from your dashboard. <Info> When scheduling for the future, the agent can schedule any workflow in the allowlist **or the current workflow itself**. Self-scheduling is useful when the agent needs to re-process the same ticket later (e.g., check back in a week to verify a fix). </Info> ## What Gets Scheduled When the agent schedules work for the future, it creates an entry with: | Field | Description | | - | - | | **Workflow** | The workflow to execute | | **Scheduled For** | When to run (must be in the future) | | **Ticket** | The current ticket for context | | **Instructions** | Additional guidance for the scheduled run | All scheduled work appears in the **Scheduled Work** section of your dashboard where you can view, reschedule, or cancel pending entries. <Card title="Scheduled Work Dashboard" icon="calendar" href="/product/scheduled-work"> Learn more about managing scheduled work from the dashboard </Card> ## Example Scenarios ### Offboarding with Delayed Actions An agent processing a termination ticket on March 1st for an employee whose last day is March 15th: ``` Agent actions: 1. Immediately: Trigger "Remove Sensitive Access" workflow 2. Immediately: Add internal note documenting the offboarding plan 3. Schedule for March 15th: Run "Disable Account" workflow 4. Schedule for April 15th: Run "Delete Account" workflow ``` ### Follow-Up Verification After resolving a recurring issue: ``` Agent actions: 1. Immediately: Apply the fix and close the ticket 2. Schedule for 7 days later: Re-run the current workflow to check if the issue recurred ``` ### Conditional Workflow Chaining An agent determines the ticket needs specialized handling: ``` Agent actions: 1. Analyze the ticket content 2. If it mentions mailbox permissions → Trigger "Mailbox Access Review" 3. If it mentions new hire starting next month → Schedule "User Onboarding" for the start date ``` ## Requirements The tool can only trigger or schedule workflows that are: * **Enabled** — Disabled workflows cannot be triggered or scheduled * **Triggered type** — Only event-triggered workflows support this ### When a workflow your instructions name is not available If your instructions tell the agent to run a workflow first when it is available, and that workflow is not in its allowlist, the agent skips that step and carries on with the rest of the job. It notes the skipped step in its run summary, unless your instructions set an exact format for that summary. To make the agent stop instead, say so in the instructions, for example: "If the Bundling workflow is not available, do not assign the ticket; add a note for the dispatcher." <Warning> When scheduling, the time must be in the future. The agent cannot schedule work for a time that has already passed. </Warning> ## Which target settings apply to a direct invocation A direct hand-off from one agent to another is **not** the same as a PSA event reaching the target. When an agent triggers a target with this tool, most of the target's own trigger settings are deliberately skipped, so the source agent is in control of the hand-off. This is different from how the target behaves when a PSA event arrives on its own. There are three separate gates, and they are easy to confuse: | Gate | When it applies | What it checks | | - | - | - | | **Run Now** (dashboard) | You click Run Now on a workflow | The **source** workflow's own **Filter Ticket** conditions (see [Filter tickets](/core/filter-tickets)). A mismatch shows as SKIPPED. The "Bypass 'Filter Ticket' conditions" switch turns this off. | | **PSA event matching** | Your PSA emits an event (ticket created, status changed, note added, …) | The target's full callback filter: entity type, run-once, the configured trigger event, then the Filter Ticket conditions. | | **Direct Agent-to-Agent invocation** | An agent triggers a target with this tool | Only two of the target's settings, listed below. | For a **direct invocation**, the target's settings apply as follows: | Target setting | Applies? | | - | - | | **Enabled** | Yes — a disabled target cannot be triggered | | **Triggered type** | Yes — only Triggered workflows can be a target | | **Entity type** | Yes — a ticket agent cannot invoke a target set to a different entity type | | **Filter Ticket conditions** | No — skipped for the hand-off | | **Execution window** (weekends, hours) | No — skipped for the hand-off | | **Configured trigger event** | No — not consulted. A target set to **Manual only**, or to a trigger event that did not occur, can still be invoked this way | <Note> Because the target's **Filter Ticket** conditions and its **configured trigger event** are skipped, those settings are a gate on **PSA events**, not a guard against a direct invocation from another agent. If you only want a target to run for certain tickets, control that on the **source** agent — through its instructions and its own filter — because the source agent decides which tickets to hand off. Set the allowlist on this tool to the exact targets you are comfortable being invoked directly. </Note> ### Instructions the source agent passes on When the source agent triggers a target immediately and that call starts a new run, the instructions it writes reach the target as **handoff notes**: what the source agent found, and what it asks the target to do. If the target is already running for that ticket, no new run starts and the notes do not reach it. The target is told to rank these notes below its own custom instructions. This lowers their weight, but it does not guarantee the target ignores a note that conflicts with its instructions. The guard you can rely on is the **source** agent: its ticket filter and its instructions decide which tickets it hands off and what it asks for. Still write a rule the target must keep on every run into the target's own custom instructions. For example, on a dispatch agent: "Only assign tickets in the Ready for Dispatch status. If the ticket is in any other status, stop." Instructions you give yourself through **Run Now** keep their full weight for that run. ## Related <CardGroup> <Card title="Scheduled Work" icon="calendar" href="/product/scheduled-work"> View and manage all scheduled work from the dashboard </Card> <Card title="PSA API" icon="ticket" href="/agents/tools/psa/psa-api"> Add internal notes to document trigger or scheduling decisions in the ticket </Card> </CardGroup> # Update Ticket Fields Source: https://docs.neoagent.io/agents/tools/management/update-ticket-fields Change ticket fields such as status, priority, board or queue, within the fields your PSA's Tickets permission allows The agent changes one ticket field per call, and Neo applies each PSA's rules for that field, such as the status that belongs to a ticket's board. This tool is not in the agent builder's tool list: Neo adds it to the agent from the PSA's **Tickets** permission group. ## How the agent gets it Neo adds Update Ticket Fields to an agent when your PSA's **Tickets** permission group is at **Read / Write**. You set the group on the agent's **Tools & Settings** tab, under your PSA's permissions. Neo removes the tool when Tickets is **Read Only** or **Disabled**, or when the group's **Fields** list allows no field this tool writes (for example, only Tags or Due Date on Syncro, or only Budget Hours on ConnectWise). Read / Write on Tickets also lets the agent create tickets and make other ticket writes through the [PSA API tool](/agents/tools/psa/psa-api). Set Tickets to Read / Write only for an agent that may write tickets. ## Which fields it can change The **Fields** selector on the Tickets permission group is the one field list for ticket updates. It limits this tool and the PSA API tool's ticket updates in the same way: * **All fields** (the default) sets no limit. * A selection allows only those fields. When the agent asks for any other field, Neo changes nothing and tells the agent which fields it may change. The selector shows your PSA's own field names, such as Status, Priority and Board on ConnectWise, or State, Assignment Group and Caller on ServiceNow. ## Approval When **Require technician approval** is on for the Tickets group, each field change from this tool waits for a technician's approval, as other ticket writes in that group do. See [where approval can be required](/core/technician-in-the-loop#where-approval-can-be-required). ## What it adds over a direct PSA write The PSA API tool can write the same fields. Update Ticket Fields adds the PSA rules a direct write misses: * **Status by name**: the agent gives a status name, and Neo finds the right status for the ticket's board or queue. * **ConnectWise board moves**: when a ticket moves to another board, Neo keeps its Type, Subtype and Item where the new board has them. * **Halo**: a team change does not remove the assigned technician. * **Autotask**: Neo adds the role that Autotask requires when the agent changes the assigned resource. * **Autotask tags by name**: the agent gives the label of an existing, active tag, and Neo finds the tag and adds it to the ticket. The ticket keeps its other tags. A label that matches no tag changes nothing. When a call changes nothing, the tool tells the agent why, so the agent does not report the change as done. For example, a field with options, such as the company, needs one of those options, and a Halo team change that would remove the assigned technician is not made. Each call appears in the [Audit Log](/product/audit-log). Neo also records each field the agent changes, with its new value, and the public API returns these records for a run (`GET /public-api/executions/{execution_id}/field-update-audit`). ## How to Use 1. On the agent's **Tools & Settings** tab, set your PSA's **Tickets** permission group to **Read / Write**. 2. In the group's **Fields** selector, keep **All fields** or pick the fields the agent may change. 3. Turn on **Require technician approval** on the group if a person should approve each ticket write. 4. In your instructions, say when to change each field. ### Example instructions ``` Set the status to "In Progress" when you start work. Set the priority to "High" if the user says the whole office is affected. Move the ticket to the "Level 2" board if you escalate it. ``` <Note> Workflows have a separate [Update Ticket Fields action](/building-automations/actions/write-to-psa/update-ticket-fields) with its own settings. This page covers the agent tool. </Note> # OpenText Secure Cloud API Source: https://docs.neoagent.io/agents/tools/marketplace/opentext-api Set up users with Microsoft 365 licences, remove licences, answer billing questions, and act on Webroot endpoints, with approvals you set per agent One connection reaches two OpenText products through the Webroot Unity API: OpenText Secure Cloud (formerly AppRiver), for customers, users, licences and charges, and the Webroot (OpenText Core) console, for sites and endpoints. Each area is a permission group you turn on per agent, and the agent reaches only the groups you enable. <Info> Automatically enabled when you configure OpenText Secure Cloud permissions in your agent workflow. No manual toggle needed. Calls go through the [Vendor API](/agents/tools/vendor-api) tool with the vendor id `opentext`. </Info> <Tip> Agents load the OpenText Secure Cloud API skill first. It carries the onboarding and offboarding steps, the user and service body shapes, and the charge search. A sub-skill covers the Webroot console, agent status and usage reports. </Tip> ## What It Does * Find the Secure Cloud customer behind a PSA company, or take it from the company mapping * Read a customer's users with their services and Microsoft 365 licences * Read which services, licences and domains a customer can assign * Create a user with services and licences, change a user's details, and add, change or remove a user's services (giving a user a role uses Admins & Roles) * Read subscriptions with seat counts, terms and renewal dates, and search charges and charge events * Read Webroot licences and order status, place an order and start a trial * Read Webroot sites, endpoints, groups, policies, commands and threat history * Scan, clean up, restart or isolate named endpoints, move them between groups and apply a policy * Read DNS Protection policies and traffic, and change a site's policy mappings * Read agent status, statistics and usage reports, and fetch event notifications ## Permission Groups | Permission Group | What It Covers | | - | - | | **Customers & Users** | Secure Cloud customers, their users, and each user's services and Microsoft 365 licences | | **Subscriptions & Charges** | Subscriptions, seat counts, charges and charge events: **read-only** | | **Orders & Trials** | Carts, orders, trials and product licences | | **Webroot Sites** | The Webroot GSM console and its sites | | **Webroot Endpoints & Groups** | Endpoints, groups, policies, agent commands, threat history and blocked URLs | | **DNS Protection** | DNS Protection policies, site mappings and traffic | | **Status & Reports** | Agent status, statistics, security awareness activity and usage reports: **read-only** | | **Admins & Roles** | Webroot console and site administrators, and Secure Cloud users created or updated with a role | | **Event Notifications** | Event notification subscriptions and their webhooks | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. Subscriptions & Charges and Status & Reports offer only Disabled and Read Only. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. The agent looks up customers, users, licences, charges and Webroot endpoints, and never changes anything. </Accordion> <Accordion title="Helpdesk"> Customers & Users and Webroot Endpoints & Groups at Read/Write, everything else Read Only. Every write in those two groups requires technician approval. </Accordion> <Accordion title="IT Admin"> Every writable group at Read/Write. The agent manages users, licences, orders, sites and endpoints autonomously. Admins & Roles, DNS Protection and Event Notifications writes require technician approval, as do the changes listed under Full Automation. </Accordion> <Accordion title="Full Automation"> Every supported write runs autonomously. Only Admins & Roles changes, changing an endpoint's keycode, uninstalling or deactivating Webroot on endpoints, suspending or deactivating a site, and cancelling a product require technician approval. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes, configurable per group | | **Admin access** | Every Admins & Roles write always requires technician approval: adding, changing or removing a Webroot console or site admin, requesting admin access to a console, a Secure Cloud user create or update that sets a role, and making a user a Microsoft 365 administrator or removing it. Each changes who holds admin access | | **Keycode changes** | A `changekeycode` agent command always requires technician approval, because it moves endpoints to the site whose keycode it names | | **Protection removal** | An `uninstall` or `deactivate` agent command, deactivating endpoints, suspending or deactivating a site, and cancelling a product always require technician approval, because each removes the client's protection or service | | **Seat quantities** | Changing a subscription's seat quantity is refused on this tool. The agent changes it with [Change License Seats](/agents/tools/m365/change-license-seats) | | **Named targets only** | A site-level command, move, policy change, reactivation or deactivation must list its endpoints in `EndpointsList` (a move may name a source group instead). Webroot applies an empty list to the whole site, so Neo refuses it | | **Documented operations only** | Every call must match an operation in the Unity API reference with its own method, and any other is refused | | **Secrets** | The two `webconsoleurl` operations, which return a link that signs its holder in to the Webroot console, are refused | ## How to Configure <Steps> <Step title="Connect OpenText Secure Cloud"> Save your Client ID, Client secret and refresh token in the Neo Dashboard under the **Cloud Marketplace** integrations category, with your GSM keycode if you use Webroot. See [Connecting OpenText Secure Cloud to Neo](/integrations/opentext/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Decide per permission group whether writes need a technician. Admins & Roles changes, keycode changes, removing endpoint protection, suspending or deactivating a site, and cancelling a product always do. </Step> </Steps> <Tip> Start with **Read Only** to see how an agent finds the client, its users and its subscriptions. **Helpdesk** then lets it set up and remove licences, with a technician approving each change. </Tip> # Auvik API Source: https://docs.neoagent.io/agents/tools/networking/auvik-api Read Auvik devices, online status, uplinks, alerts, statistics, tenants and billing usage, and dismiss an alert — dismissal follows the approval setting you give it An agent with this tool answers a network ticket from the client's Auvik data: is the device really down, when Auvik last saw it, which switch ports it connects to, and which Auvik alerts are open on it. <Info> Automatically enabled when you configure Auvik permissions in your agent workflow. No manual toggle needed. </Info> ## What It Does * Find the client's Auvik tenant (a site in the Auvik UI) * Find a device by name, IP address, serial number or MAC address, and read its online status and when Auvik last saw it * Read the device's outage history, the devices and switch ports it connects to, and the state of each likely uplink. Auvik does not mark which neighbour is the uplink, so with more than one the agent lists each * Read the open Auvik alerts on the device or its uplink, and dismiss an alert once the condition has cleared and the ticket is resolved * Read device details, warranty and end of life, networks, interfaces, components and configuration backup times * Read bandwidth, CPU, memory and interface statistics, and SNMP poller settings and history * Read billable device days per client for a month, and the average billable devices per site * Match Auvik devices to ConnectWise configurations by the Auvik device id field, serial number, MAC address or name, and list the devices with no match on each side. The agent changes a configuration only when your instructions ask and the agent has ConnectWise **Configurations** write access * Find the Auvik alert behind a ticket that Auvik opened in your PSA * Read Auvik SaaS Management apps, users and licenses The agent calls Auvik through the [Vendor API](/agents/tools/vendor-api) tool, with `auvik` as the vendor id. [Sandbox](/agents/tools/built-in/sandbox) scripts can call Auvik too, under the same permissions. ## Permission Groups | Group | Access levels | What it covers | | - | - | - | | **Inventory** | Disabled, Read Only | Devices, interfaces, networks and components: online status, last seen, connected devices, details, warranty, lifecycle and configuration backup times | | **Alerts** | Disabled, Read Only, Read/Write | Alert history. Write dismisses an alert | | **Statistics** | Disabled, Read Only | Device, interface, component, service and OID statistics, outage history, and SNMP poller settings and history | | **Tenants and Billing** | Disabled, Read Only | Your Auvik tenants and billing usage per client | | **Notes and Audit** | Disabled, Read Only | Notes your technicians typed on devices and networks in Auvik, and the audit log. Off in every profile, because notes are free text and can hold passwords | | **SaaS Management** | Disabled, Read Only | Auvik SaaS Management apps, users, licenses, tags and security log per client | Neo sends Auvik reads and one write, dismissing an alert. Nothing Neo sends to Auvik changes a network device. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> Every group Read Only except Notes and Audit, which stays off. The agent reads, and never dismisses an alert. </Accordion> <Accordion title="Helpdesk"> Reads the same groups. Dismissing an alert waits on a technician. </Accordion> <Accordion title="IT Admin"> Reads the same groups. Dismissing an alert waits on a technician. </Accordion> <Accordion title="Full Automation"> Reads the same groups and dismisses alerts without approval. </Accordion> </AccordionGroup> To let an agent read Auvik notes, turn **Notes and Audit** to Read Only by hand. Do it only if your Auvik notes hold no passwords or keys. ## Not available through Neo Auvik's published API has no operation that runs a command on a device, pushes a configuration, or exports a configuration backup, so Neo cannot do these. The agent reads only when a backup was taken. ## Setup See [Connecting Auvik to Neo](/integrations/auvik/connecting-to-neo). # Domotz API Source: https://docs.neoagent.io/agents/tools/networking/domotz-api Read Domotz collectors, devices, history and alerts, edit devices, resolve alerts, manage monitoring, Organizations and users, and power cycle a device through its switch port or PDU — each area follows the approval setting you give it An agent with this tool answers a network ticket from the client's Domotz data: is the whole site down or one device, when the device dropped off, and whether a power cycle brought it back. <Info> Automatically enabled when you configure Domotz permissions in your agent workflow. No manual toggle needed. </Info> ## What It Does * Find the client's collectors from the [Organization Mapping](/integrations/domotz/overview#your-clients-are-mapped-automatically). A client with several sites has one collector per site * Read a collector's devices with their status, uptime, latency and history, and the site's speed tests, IP conflicts and network topology * Read device metrics, sensors, activity logs and the account audit log * Edit a device's details (name, type, model, vendor, importance, room, zone, serial, notes) and its inventory values; tag it, add a sensor or an external host, and start a configuration backup * Read alert events with the rules, profiles and contact channels behind them, and resolve an alert once the device is back * Change what Domotz watches: alert rules and their bindings, excluded and hidden devices, monitoring state * Power a device on, off or through a cycle on its PoE switch port or PDU outlet, reboot it, or run a custom driver action * Change a collector's scan policies and routed networks, close a VPN session, and manage Organizations, their contacts and the account's users The agent calls Domotz through the [Vendor API](/agents/tools/vendor-api) tool, with `domotz` as the vendor id. [Sandbox](/agents/tools/built-in/sandbox) scripts can call Domotz too, under the same permissions. ## Permission Groups | Group | Access levels | What it covers | | - | - | - | | **Collectors & Devices** | Disabled, Read Only, Read/Write | Collectors and their devices: status, uptime, latency, speed tests, IP conflicts, topology, history, metrics, sensors, activity and audit logs, device profiles. Write edits a device's details (name, type, model, vendor, importance, room, zone, serial, notes) and inventory values, tags a device, adds sensors, triggers and external hosts, starts or uploads a configuration backup, names an outlet and attaches a device to it, sets device credentials and SNMP settings, and applies a device profile | | **Collector Settings** | Disabled, Read Only, Read/Write | How a collector discovers and reaches the network: scan and interface policies, DHCP discovery, routed networks, service ports, the collector's default SNMP credentials, VPN sessions (list and close), moving a collector to another team, and deleting a collector | | **Monitoring Coverage** | Disabled, Read Only, Read/Write | Alert rules (create and change) and their bindings to collectors, devices and contact channels, alert profile bindings, excluded and hidden devices, monitoring state (managed or unmanaged), and deleting a device, sensor or trigger | | **Alerts** | Disabled, Read Only, Read/Write | Alert events, alert rules and profiles, contact channels. Write resolves an alert | | **Device Actions** | Disabled, Read Only, Read/Write | Power on, off or cycle through a PoE switch port or PDU outlet, software reboot, PDU outlet actions, running and binding custom drivers | | **Organizations** | Disabled, Read Only, Read/Write | The Domotz Organizations, which collectors belong to each, and their contacts. Write creates, changes and deletes them | | **Users & Account** | Disabled, Read Only, Read/Write | Domotz users, user groups and roles, areas and teams, and the account's tag and inventory field definitions | A write in **Monitoring Coverage** can stop an alert without anyone noticing: a hidden or unmanaged device, or an unbound alert rule, raises nothing. A write in **Collector Settings** or **Users & Account** can change what a collector finds or who reaches the account. Each is a separate group so you can ask for approval on those writes alone. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> Every group Read Only. The agent can look up any collector, device, history or alert, but never changes anything. </Accordion> <Accordion title="Helpdesk"> Resolves alerts on its own. Every other change waits on a technician. </Accordion> <Accordion title="IT Admin"> Changes devices, runs power actions, resolves alerts and manages Organizations on its own. Monitoring Coverage, Collector Settings and Users & Account changes wait on a technician. </Accordion> <Accordion title="Full Automation"> Nothing waits on a technician, except the two operations below. </Accordion> </AccordionGroup> Two operations always wait on a technician, whatever the settings: deleting a collector, which removes the site and its whole history, and deleting an Organization. ## Not available through Neo Neo refuses these before it calls Domotz: * Opening a remote connection to a device or a collector VPN session, because the response is a working access link or VPN configuration * The text of a stored device configuration, which can contain passwords. The agent reads the backup list and its checksums, to see when a configuration changed * Camera snapshots, because the response is an image the agent cannot read * Bulk deleting a collector's offline devices, because the call names no device. The agent can delete devices one at a time * Wiping the account's whole inventory, which deletes every field and value on every device Neo also removes SNMP community strings and keys from every Domotz response before an agent or a script sees it. ## Setup See [Connecting Domotz to Neo](/integrations/domotz/connecting-to-neo). # TP-Link Omada API Source: https://docs.neoagent.io/agents/tools/networking/omada-api Check a client's Omada access points, switches, gateways and clients, reboot devices, block clients, issue hotspot vouchers and change WiFi, network and firewall settings, on an Omada Cloud-Based Controller or a controller you run The common use is a connectivity ticket: "WiFi is slow" or "the internet is down" at a client's site. The agent finds the client's site in Omada, checks the gateway's WAN state, the access point the user's device is on and its signal, and writes what it found. <Info> Automatically enabled when you configure TP-Link Omada permissions in your agent workflow. </Info> ## What It Does * Find the Omada customer (in the MSP view) or the site that belongs to the ticket's company * Read access points, switches, gateways, OLTs and stacks: status, uplink, ports, PoE, CPU and memory, firmware, online history * Read a gateway's WAN ports: internet state, latency, packet loss and ISP * Reboot a device, power-cycle a PoE port, adopt or forget a device, change port and device settings, plan firmware upgrades * Find a client by name, MAC or IP, with its access point, SSID, signal, VLAN and connection history; reconnect, block, unblock or rename it, set a fixed IP or a rate limit * Read and change WiFi (WLAN groups and SSIDs), LAN and WAN networks, DHCP reservations, routing, QoS and VoIP settings * Read and change ACLs, firewall, NAT and port forwarding, IPS, URL and application filters, VPN, 802.1X and MAC authentication * Create and read hotspot vouchers, and change portal settings * Read and resolve alerts, events, audit logs, insights, incidents and health * Read and change site templates, controller admins, roles, licenses and controller settings ## How the Agent Troubleshoots * **Connectivity complaint:** the agent finds the user's device by IP, MAC or name, then reads the access point or switch port it is on, its signal and health score, and when it last disconnected. * **Internet outage:** the agent reads the gateway's WAN state now, then looks for a time that dates the WAN link: an alert or event about the WAN, or a drop in WAN health. It reports the time it found and where it came from, or says the outage is unverified and which checks it ran. * **Access point offline or not answering:** the agent reboots it when it is connected. When it is disconnected or has missed its heartbeat, and it is powered from a PoE port on an Omada switch, the agent power-cycles that port once and then reads its status again; otherwise it reports the access point's status to the technician. Each of these follows the Devices group's approval setting. Neo reaches an Omada Cloud-Based Controller (Omada Central), or a Software or hardware controller at version 6.2.0 or later through Omada cloud access; the agent's calls are the same for both. Passwords, WiFi keys, shared secrets and private keys in a response are replaced before the agent sees them. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Customers & Sites | Disabled, Read Only, Read / Write | MSP customers, sites, site tags and scenarios | | Devices | Disabled, Read Only, Read / Write | Access points, switches, gateways, OLTs and stacks: status, ports, PoE, reboots, adoption, firmware | | Clients | Disabled, Read Only, Read / Write | Wired and wireless clients: history, reconnect, block, names, fixed IPs, rate limits | | Networks & WiFi | Disabled, Read Only, Read / Write | WiFi, LAN and WAN networks, DHCP, DNS, routing, QoS, VoIP, RF planning | | Firewall, VPN & Security | Disabled, Read Only, Read / Write | ACLs, firewall, NAT and port forwarding, IPS, URL and application filters, VPN, 802.1X, MAC authentication | | Hotspot & Portal | Disabled, Read Only, Read / Write | Guest portals, vouchers and voucher groups, authorized guests | | Monitoring, Logs & Reports | Disabled, Read Only, Read / Write | Dashboards, alerts, events, audit logs, insights, incidents, health, reports | | Site Templates | Disabled, Read Only, Read / Write | Site templates and the settings they push to every bound site | | Admins & Controller Settings | Disabled, Read Only, Read / Write | Admins, roles, SSO, two-factor authentication, licenses, webhooks, mail, backups, controller settings | ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every supported read | No write is allowed | | **Helpdesk** | Device, client, hotspot and monitoring changes: reboots, client blocks, vouchers, resolving alerts | Network, security, site, template and controller changes, and the Safety Controls below | | **IT Admin** | Every supported change except those on the right | Every change in the Firewall, VPN & Security and the Admins & Controller Settings groups, and the Safety Controls below | | **Full Automation** | Every supported change except the Safety Controls below | Only the Safety Controls below | ## Safety Controls | Control | Behavior | | - | - | | **Deletes and restores** | Deleting a customer or a site, and restoring the controller or sites from a backup, always ask a technician | | **Forgetting devices** | Forgetting a device or a switch stack, which removes it from the controller and resets it, always asks a technician | | **Admins and sign-in** | Adding, changing or removing a controller or MSP admin (a re-invite included), a role or a customer role, a SAML identity provider or an SSO user group, and turning two-factor authentication on or off, always ask a technician | | **Secrets** | A change that sets a secret (a password, key, PIN, token or SNMP community), a WiFi key or a shared secret included, always asks a technician. Secrets in a response are replaced with `[redacted by Neo]`, and a change that sends that text back is refused | | **Bulk changes** | A bulk change (resolving or deleting logs, bulk ACL, OSPF or IP-MAC changes) must name its records: a change that selects "all" or "exclude", or leaves out the selection, is refused | | **Not supported** | Transferring the controller's owner and binding or unbinding its cloud account, the batch processing calls that carry other operations in one call (`openapi/v1/<omadacId>/batch`), file uploads and downloads, generating WireGuard keys, and any change that is not an operation in the Omada Open API reference Neo was built from (versions 6.2.0 to 6.3.0) | # UniFi API Source: https://docs.neoagent.io/agents/tools/networking/unifi-api Read UniFi consoles, sites, devices and clients, and change networks, WiFi and firewall rules — device restarts and any network or firewall change always require technician approval The UniFi API tool gives Neo agents direct access to your UniFi network — pull a site's gateway, switch and AP status into the ticket, find the client behind a connectivity complaint, issue a guest voucher, and, with your approval, restart the access point that stopped responding. Which API it calls follows the connection type you chose when you connected UniFi: | Connection type | What the tool calls | | - | - | | **UniFi Site Manager** | Ubiquiti's Site Manager cloud API, and each console's Network API through Ubiquiti's cloud Connector | | **UniFi OS Server or console by URL** | That controller's Network Integration API | | **Self-hosted Network Server** | That controller's classic API, over a username and password session | The permission groups, the approval rules and the agent setup below are the same for all three. A path that belongs to another connection type is refused with a message naming the one that applies, so an agent corrects itself instead of retrying. <Info> Automatically enabled when you configure UniFi permissions in your agent workflow. No manual toggle needed. </Info> <Tip> Agents load the UniFi API skill first, which carries the endpoint tables for each connection type, pagination and filter syntax, and the pacing rule that matters most on Site Manager: **the Connector allows 100 requests per minute per console**. </Tip> ## What It Does * List the consoles and sites the connected account manages, and every device across the fleet with its online state * Read ISP latency, packet-loss, throughput and uptime per site * Read a site's adopted devices with live statistics, and the clients connected to them * Restart a device or power-cycle a PoE port (always behind technician approval) * Generate hotspot vouchers; authorize or revoke guest access for a client and delete vouchers (always behind technician approval) * Read and change networks/VLANs, SSIDs, WANs, VPNs, DNS policies, firewall policies and ACL rules (writes always behind technician approval) ## Permission Groups | Permission Group | What It Covers | | - | - | | **Consoles & Sites** | Consoles, sites, fleet-wide device inventory, ISP health, SD-WAN — **read-only by API design** | | **Devices** | Adopted and pending devices, statistics, restart, PoE power-cycle, adopt/unadopt | | **Clients** | Connected wired and wireless clients, guest authorization | | **Networks & WiFi** | Networks/VLANs, SSIDs, WANs, VPNs, RADIUS, switching, DNS policies | | **Firewall & ACLs** | Firewall policies and zones, ACL rules, traffic matching lists | | **Hotspot Vouchers** | Guest hotspot vouchers | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write** (Consoles & Sites only ever offers Read Only). ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. The agent can look up any resource but never changes anything. </Accordion> <Accordion title="Helpdesk"> Hotspot Vouchers and Clients at Read/Write — issuing a voucher runs autonomously; authorizing a guest still requires technician approval on every call. Everything else Read Only. </Accordion> <Accordion title="IT Admin"> Every writable group at Read/Write, but every write requires technician approval — not just the mandatorily-forced ones. </Accordion> <Accordion title="Full Automation"> Issuing vouchers runs autonomously. Device actions, network/firewall changes, guest authorization and voucher deletion still always require technician approval — that override is never optional. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes — configurable per group | | **Device protection** | Restart, PoE power-cycle, adopt and unadopt always require technician approval, regardless of settings | | **Network protection** | Creating, editing or deleting networks, SSIDs, WANs, VPNs and DNS policies always requires technician approval | | **Firewall protection** | Any firewall policy, zone, ACL rule or traffic-matching-list change always requires technician approval | | **Guest access protection** | Authorizing or revoking a client's guest access always requires technician approval | | **Voucher deletion** | Deleting vouchers always requires technician approval; issuing them does not. On a self-hosted controller both share one endpoint, so Neo reads the command being sent and approves on that | | **Read-only areas** | Consoles & Sites has no write endpoint — nothing to approve or restrict there | | **Application scope** | Only the Network application is reachable; Protect and other UniFi applications are rejected | | **Controller administration** | On a self-hosted controller, settings, admin and hotspot-operator accounts, backups, site creation and controller reboot are not exposed to agents at all | | **Rate limiting** | Calls are paced to Ubiquiti's 100 requests/minute per console | ## How to Configure <Steps> <Step title="Connect UniFi"> In the Neo Dashboard, open the **Networking** integrations category, pick your **Connection type** and enter its credentials — a Site Manager API key, a console API key with its URL, or a controller URL with a local admin's username and password. See [Connecting UniFi to Neo](/integrations/unifi/connecting-to-neo) for which one your controller needs. </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Every write except issuing a hotspot voucher already requires technician approval; decide whether voucher issue should too. </Step> </Steps> <Tip> Start with **Read Only** — most network tickets are answered by reading the gateway's WAN status, the AP's client count and the client's signal, with no write at all. </Tip> # WatchGuard API Source: https://docs.neoagent.io/agents/tools/networking/watchguard-api Check a Firebox or access point after an offline alert, read and change Firebox exceptions and policies, and read and act on WatchGuard Endpoint Security and ThreatSync for each client you manage in WatchGuard Cloud The common use is a WatchGuard Cloud alert that a Firebox's cloud connection went offline or came back online: the agent checks the Firebox and writes whether it is back and since when it was down. <Info> Automatically enabled when you configure WatchGuard permissions in your agent workflow. </Info> ## What It Does * Pick the client's WatchGuard Cloud account by name from the accounts you manage * Read a Firebox's or access point's state, offline since, uptime, public IP, model, serial and firmware * Read the Firebox Executive and Security dashboard reports * Read BOVPN tunnels, firewall policies, networks, SD-WAN, users and schedules of a cloud-managed Firebox * Read, add and remove Firebox and FireCloud exceptions: blocked sites, WebBlocker, botnet, file, IPS, geolocation and HTTPS * Deploy saved exceptions or configuration to named Fireboxes, and read the deployment's result * Find a computer in WatchGuard Endpoint Security (EPDR, EDR, EPP, Panda Aether) and read its protection, security events, risks and missing patches * Isolate a computer, stop the isolation, reboot it or scan it * Read ThreatSync incidents and act on them: isolate, end a process, quarantine a file, block an address, set the status, add comments * Read accounts, licences, allocations and contracts * Send an AuthPoint test push and read its result For AuthPoint, Neo reaches only the Authentication API: a token unlock, resync or reassignment, or a user change, stays in the AuthPoint console. Locally managed Fireboxes show their status, reports and exceptions; their policies and VPN stay on the device. ## How the agent handles a Firebox offline alert The agent finds the account for the ticket's company and lists its devices. It matches the Firebox name or serial number in the alert to a device and reads its state. When the Firebox is online and its uptime started after the alert, it writes when the Firebox came back. When it is still offline, it writes since when and the last public IP. What happens to the ticket next follows your instructions. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Firebox Devices and Reports | Disabled, Read Only | Fireboxes, FireClusters and access points: status, offline since, uptime; the dashboard reports | | Firebox Exceptions | Disabled, Read Only, Read / Write | Firebox and FireCloud exceptions | | Firebox Configuration | Disabled, Read Only, Read / Write | Firewall policies, BOVPN tunnels, certificates, networks, users, templates, deployments | | Endpoint Security | Disabled, Read Only, Read / Write | Devices, protection, security events, risks, patches, tasks; isolate, reboot, scan | | ThreatSync and NDR | Disabled, Read Only, Read / Write | ThreatSync incidents, actions and comments; NDR assets and Smart Alerts | | Accounts and Licensing | Disabled, Read Only, Read / Write | Accounts and managed accounts, operators, activations, allocations, contracts, invoices | | AuthPoint Authentication | Disabled, Read Only, Read / Write | Push and its status, OTP and QR code checks, the authentication policy for a user | ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Every write | | **IT Admin** | Isolating, scanning and rebooting endpoints, ThreatSync containment and incident updates, AuthPoint push | Exceptions, Firebox configuration and account changes, and every write under Safety Controls | | **Full Automation** | Every write except those below | Only the writes below | ## Safety Controls | Control | Behavior | | - | - | | **Exceptions** | A Firebox exception follows the access profile, and reaches the Firebox only through a deployment, which always asks. A FireCloud exception that lets traffic through or skips a scan always asks a technician, and so does removing a FireCloud blocked-site entry | | **Firebox configuration** | Firewall policy, BOVPN, certificate and template changes, and disabling global exceptions, always ask a technician | | **Deployments** | Every deployment always asks a technician, and it must name its Fireboxes | | **Endpoints** | Every endpoint action must name its devices. Uninstalling protection and moving devices to another security configuration always ask a technician | | **ThreatSync** | Undoing an isolation or a block always asks a technician | | **Accounts** | Operator changes, deallocations, purchase orders and contract suspend or cancel always ask a technician | | **Right account** | A call to a client's devices, configuration, endpoints or incidents names that client's account id; a call for an account your credential does not manage is refused. Operator calls name the client's account in the body or the query; order and activation calls name no account and run in your own WatchGuard Cloud account | | **Refused** | Neo does not delete a WatchGuard Cloud account, create a partner account, read Azure access credentials, check a user's password, or send a ThreatSync batch | ## How to Configure <Steps> <Step title="Connect WatchGuard"> Save your WatchGuard Cloud API credential in the Neo Dashboard under the **Networking** integrations category. See [Connecting WatchGuard to Neo](/integrations/watchguard/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> Start with **Read Only**. Checking a Firebox after an offline alert needs only reads in WatchGuard; the note on the ticket is written with the PSA tools. </Tip> # Zabbix API Source: https://docs.neoagent.io/agents/tools/networking/zabbix-api Read Zabbix hosts, problems, latest values and history; acknowledge and close problems, set maintenance, run scripts and change monitoring — each change follows the approval settings you give it An agent with this tool answers a monitoring ticket from your Zabbix data: which host it is about, whether Zabbix can still reach it, which problems are open on it, and what its values looked like when the problem started. <Info> Automatically enabled when you configure Zabbix permissions in your agent workflow. No manual toggle needed. </Info> ## What It Does * Find the host by visible or technical name, IP address or DNS name, or among a client's host groups or tags * Read the host's availability per interface, its open problems with their severity and acknowledgements, and the trigger behind each problem * Tell a host that is down from a stopped Zabbix agent or an offline proxy * Read any item's latest value, history and hourly trend, such as CPU, memory, disk and ping * Match a ticket a Zabbix alert email opened to its problem, by event id, trigger id, or host, problem name and start time, and route recovery emails, and update emails that carry the Zabbix event id, to the original ticket * Acknowledge, comment on, close, suppress or change the severity of a problem, with the ticket number in the message * Put a host or host group in maintenance for planned work * Run a script you defined in Zabbix on a host, such as a ping or a service restart * Change hosts, host groups, templates, items, triggers, macros, users and other Zabbix settings, with the access and approvals you choose The agent calls Zabbix through the [Vendor API](/agents/tools/vendor-api) tool, with `zabbix` as the vendor id. [Sandbox](/agents/tools/built-in/sandbox) scripts can call Zabbix too, under the same permissions. ## Permission Groups | Group | What it covers | | - | - | | **Problems and Events** | Current problems, events and the alerts Zabbix sent. Write acknowledges, comments on, closes, suppresses or changes the severity of a problem | | **Hosts** | Hosts, host groups and host interfaces. Deleting a host always requires technician approval | | **History and Trends** | Collected values and hourly trends. Write sends values to trapper items | | **Maintenance** | Maintenance periods | | **Scripts** | Global scripts: read, run on a host or for an event, create, change and delete | | **Items, Triggers and Discovery** | Items, triggers, graphs, web scenarios, low-level discovery and their prototypes, host macros, value maps and "check now" | | **Templates** | Templates, template groups and template dashboards | | **Actions and Media Types** | Actions, media types and event correlation | | **Dashboards, Maps and Reports** | Dashboards, maps, images, icon maps and scheduled reports | | **Services and SLAs** | Business services and SLAs | | **Network Discovery and Proxies** | Network discovery rules and results, proxies, proxy groups and autoregistration | | **Users and Access** | Users, user groups, roles, API tokens, user directories, MFA and authentication. The changes listed under "Changes that always ask a technician" below always require technician approval | | **Administration** | Global settings, housekeeping, modules, regular expressions, connectors, global macros, the audit log and HA nodes | Every group can be Disabled, Read Only or Read/Write. Neo never sends these methods: `user.login`, `user.logout` and `user.checkAuthentication` (Neo uses the API token), `token.create` and `token.generate` (a new token works only once its secret is generated, and Neo never reads a secret), `history.clear` (it destroys data), and `configuration.export`, `configuration.import` and `configuration.importcompare` (an export can carry passwords, and an import makes many changes at once). Neo removes the fields Zabbix keeps credentials in (passwords, SNMP communities and passphrases, pre-shared keys, credential headers, HTTP request bodies, and the user name and password in a URL) from every answer; text typed elsewhere, such as a script's command or a text macro, reaches the agent as written. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> Every group Read Only. The agent reads, and never changes anything. </Accordion> <Accordion title="Helpdesk"> Problems and Events is Read/Write without approval. Maintenance and Scripts are Read/Write with technician approval. Everything else is Read Only. </Accordion> <Accordion title="IT Admin"> Every group Read/Write. Scripts, Actions and Media Types, Users and Access, and Administration require technician approval, and so does deleting a host. </Accordion> <Accordion title="Full Automation"> Every group Read/Write without approval, except the changes below, which still require technician approval. </Accordion> </AccordionGroup> ## Changes that always ask a technician These require technician approval under every access profile, whatever the group's own approval setting: * Changing authentication settings (HTTP, LDAP and SAML sign-in, the default sign-in method, the password policy). * Creating, changing, testing or deleting an LDAP or SAML user directory. * Creating, changing or deleting an MFA method. * Creating, changing or deleting a user role or a user group. * Creating, deleting or provisioning a user from LDAP, or changing a user's role, user groups or user directory. Disabling a user means moving them to a disabled user group, so it asks too. * Resetting a user's MFA. * Changing or deleting an API token. * Deleting a host, which removes its collected history. * Any change that stores a credential: a password, a secret macro, a credential header or parameter, the user name and password in a URL, or an HTTP agent's request body. # Tools Overview Source: https://docs.neoagent.io/agents/tools/overview Tools are the capabilities you enable for Neo Agents to accomplish tasks Tools define what actions Neo Agents can perform. When you configure a workflow, you select which tools are available and customize their settings to match your processes. <Info> Some tools turn on **automatically** once you configure an integration's permissions on the workflow's **Integrations** tab — the PSA, RMM, Microsoft 365, and documentation API tools (IT Glue, Hudu, Lexful, Confluence, SharePoint) all work this way. You pick which permission groups the agent can use; the matching tool appears without a separate toggle. </Info> ## Tool Categories <CardGroup> <Card title="Tool credit costs" icon="coins" href="/agents/tools/credit-costs"> What each tool costs, and why a scheduled or chat agent is billed per call — not once per run </Card> <Card title="PSA" icon="ticket" href="/agents/tools/psa/psa-api"> Read and write your PSA — tickets, notes, time entries, contacts, configurations, and more </Card> <Card title="RMM" icon="server" href="/agents/tools/rmm/run-rmm-script"> Read device and monitoring data, and run scripts on target devices to fix problems </Card> <Card title="Microsoft 365" icon="microsoft" href="/agents/tools/m365/overview"> Manage Entra ID, Active Directory, Exchange, and Intune — users, groups, licenses, mailboxes </Card> <Card title="Communication" icon="comments" href="/agents/tools/communication/add-client-facing-note"> Send messages to end users and internal teams — ticket notes, email, Teams, SMS </Card> <Card title="Search" icon="magnifying-glass" href="/agents/tools/search/find-documentation"> Find documentation, similar tickets, configurations, and web resources </Card> <Card title="Documentation" icon="book" href="/agents/tools/documentation/itglue-api"> Read and write documentation in IT Glue, Hudu, Lexful, Confluence, and SharePoint </Card> <Card title="Management" icon="list-check" href="/agents/tools/management/external-api-request"> Log time, generate passwords and secure links, trigger workflows, call external APIs and Neo's own API </Card> <Card title="Built-in & Internal" icon="gear" href="/agents/tools/built-in/overview"> Tools the agent always has or gets automatically — search helpers, the sandbox, plumbing </Card> <Card title="Approvals" icon="user-check" href="/agents/tools/approvals/request-technician-approval"> Request human approval before sensitive actions </Card> </CardGroup> ## Credit Tiers Each tool has a tier. What you pay depends on **how the agent runs**, not only on which tools are enabled. | How the agent runs | What the tier means | | - | - | | **Ticket- or entity-triggered** | You pay the highest tier among the tools *you chose*, **once per run**. The agent can use those tools as many times as it needs. | | **Scheduled (no ticket) or internal chat** | You pay **each time a tool is called**, at that call's [per-call price](/agents/tools/credit-costs). Ten 3-credit calls cost 30 credits. | | Tier | Credits | Typical tools | | - | - | - | | <Icon icon="circle" /> **Basic** | 1 | Generate a password, trigger another workflow | | <Icon icon="circle" /> **Standard** | 2 | Documentation and ticket search, the sandbox shell, email or Teams, a read-only PSA or RMM integration | | <Icon icon="circle" /> **Advanced** | 3 | PSA or Graph writes, RMM script execution, PowerShell, [External API Request](/agents/tools/management/external-api-request) | <Note> For the API-backed integration tools (PSA, RMM, Microsoft 365, the documentation platforms and the vendor APIs), a triggered agent's tier reflects the access you grant — Standard when every enabled permission group is Read Only, Advanced when any group allows writes. On a scheduled or chat agent, each call prices by what it did: see [Tool credit costs](/agents/tools/credit-costs). </Note> <Note> **Tools Neo adds for you never set a triggered agent's per-run price.** Searches, the sandbox, and similar always-on tools are listed under **Built-in Capabilities** with no price tag. On a scheduled or chat agent they still bill when called — Find Documentation is 2 credits per search, Sandbox Bash is 2 per call. Skills in that same list are free to *load*; the tools they use are not. The full table is on [Tool credit costs](/agents/tools/credit-costs). </Note> ## Tool Dependencies Some tools automatically enable other tools they depend on. For example: * **Execute RMM Script** automatically enables the device-lookup and script-search capabilities it needs * Update and create operations automatically enable the field-options lookups they need <Info> Dependency tools are shown in each tool's documentation. They're automatically enabled when you select the parent tool. </Info> ## Technician-in-the-Loop Many tools support **Technician-in-the-Loop** approval, which requires human approval before the agent takes action. When enabled: 1. The agent prepares the action and explains what it wants to do 2. A Teams message is sent to configured technicians 3. A technician approves or rejects the action 4. The agent proceeds based on the decision <Tip> Start with approval enabled for sensitive operations. As you gain confidence in the agent's decisions, you can disable approval for routine tasks. </Tip> # Get Technician Context Source: https://docs.neoagent.io/agents/tools/psa/get-technician-context Canonical source for technician working hours, today's calendar, workload, and expertise — the data a dispatch agent needs to assign tickets The Get Technician Context tool feeds a dispatch agent a structured, pre-computed snapshot of your technicians — who's working today, when, how loaded they are, and who has the right expertise — so it can make a good assignment decision quickly without re-deriving any of it from raw PSA endpoints. It works for ticket-triggered runs and for scheduled (ticketless) sweeps; specifying the technician pool via the ticket's company or board team requires a ticket, while passing an explicit list of technicians works in either mode. <Info> **Turn it on in the agent's toolbox**, like any other tool. Give it to the agents that assign tickets; leave it off the ones that do not, and their runs stay smaller and faster. It pairs with the agent's **Dispatch Decision Framework** skill, which the agent loads to interpret the context — and it loads it on every run, because the tool asks for it before returning a result. Switching it on also gives the agent [Verify Dispatch Decision](/agents/tools/built-in/overview#verify-dispatch-decision), which reserves a booked slot against Neo's other runs and counts every assignment toward a short-term cap per technician. That one needs no setting and costs no credits. </Info> ## What It Does It returns, per technician: * **Calendar** — weekday working hours (days flagged "Not working" when off), timezone, holidays, today's existing appointments, and a wrap- and timezone-resolved "on shift / off shift right now" summary so the agent doesn't have to re-derive overnight-shift or timezone math itself (it still overlays time-off and holidays before deciding) * **Workload** — the open tickets in the workload window you set (the last N days of activity, not the whole backlog): the count and one row per ticket with the fields the agent asks for (the ticket id and status by default; queue, title and priority on request when your instructions read them), plus, when the incoming ticket has a company, the tickets the technician already has for that company. Closed tickets and tickets whose status name contains Complete are not counted * **Expertise** — the technician's [profile](/product/technician-profiles) plus PSA-configured skills (ConnectWise and Autotask; plus ConnectWise certifications), prior work on similar tickets, the relevant configuration items or technologies * **Recent Neo assignments** — which tickets the agent recently dispatched to each technician, with timestamps, so it can round-robin fairly across the team and avoid handing consecutive tickets to the same person * **Teams availability** *(optional)* — from your own M365 tenant: each technician's **live presence** (Available / Away / Busy / In a call / Offline / out-of-office), so the agent won't hand work starting now to someone who's away or on a break; plus their **shift rota** (upcoming Microsoft Teams Shifts, with each shift's label — an on-site client name or an absence marker like *Annual Leave*), so the agent can prefer whoever is actually rostered on — now or for a future slot; plus their Shifts **time off**, with the reason you gave it — an absence reason (*Annual Leave*, *Sickness Absence*, *Bank Holiday*) is a hard block for work overlapping it, while a reason that just records where someone is working (*London Office*, *Working from Home*, *On Call*) is read as context, not as absence The agent uses this to choose an assignee (or to decide the ticket should be escalated or left unassigned), then acts via the [PSA API](/agents/tools/psa/psa-api) — for example setting the ticket's owner or adding a schedule entry. On Autotask and ConnectWise, the agent can also ask for calendar entries marked complete (Autotask service calls, ConnectWise schedule entries marked done) within the requested window; by default they are left out. If your team marks shift markers or proactive-time blocks complete before they end, say so in the agent's custom instructions, together with what those entries mean, and the agent asks for them. On Halo and ServiceNow, completed entries are always included. Each entry marked complete is flagged as such, separately from whether its scheduled end time has passed. <Note> **Picking the pool from a ticket's team is PSA-aware, with a graceful fallback.** The agent can source candidates from the ticket's **company team** or **board/queue team**, or pass an explicit list. Board/queue teams are a ConnectWise concept; on Halo, Autotask, and ServiceNow — or whenever the ticket has no board/company team, or the team is empty — the tool doesn't error. It returns the PSA's active technicians as fallback candidates and flags that it did so, so the agent knows to confirm each candidate's team/skill/availability suitability rather than treating the list as a curated team match. Any pool taken from a ticket's team or from that fallback contains only technicians with a ready [profile](/product/technician-profiles) in Neo: a technician without one has no calendar and cannot be scheduled, and the tool tells the agent how many technicians it left out for that reason. If nobody in the pool has a ready profile yet, the tool returns the whole pool and says so, so the run can still tell you what to fix. Under **Technicians**, add the people who are missing and complete the profiles that are not ready yet. </Note> <Note> **Teams availability** is fetched only when the agent asks for it. **Presence** is a current-moment signal (who can take this *now*); **shifts** are the rota (who is scheduled on, now and for future slots). Both require the **Microsoft Teams — Technician Mapping & Availability** integration connected and technicians mapped to their Microsoft user; shifts also read the Teams you selected when mapping (your service-desk Teams). When a piece isn't available, the agent falls back to PSA calendar availability. It's the same signal as the Dispatch Ticket action's "Teams availability" setting, surfaced for agentic dispatch. </Note> ## Why It Matters Each PSA exposes "is this engineer working today" through a different chain of endpoints with non-obvious field names (e.g. ConnectWise's `mondayStartTime` / `sundayEndTime` on `schedule/calendars/{id}`, Autotask's `InternalLocationWithBusinessHours` + per-resource overrides, Halo's `api/Workday`). Asking the agent to reconstruct that on the fly is brittle: a misspelled field name or a missing day attribute leads to silent guesses ("probably Mon–Fri 09:00–17:00") and engineers scheduled outside working hours. **Get Technician Context is the canonical answer to working-hours / availability questions.** Custom instructions that reference "engineer's working hours" or "calendar working days" should let the agent reach for this tool, not derive it from primitives. <Tip> **If a calendar entry sets someone's shift, say so in custom instructions.** The calendar normally starts at the current moment, so a short morning marker — an "Early Shift 07:00 - 08:30" booking that means the day ends at 15:30 — has passed by the afternoon and the agent no longer sees it. Write the rule the way you already read it ("an *Early Shift* entry means that engineer works 07:00-15:30") and the agent fetches the earlier part of the day too. Entries that have already finished are marked as such, so they inform the shift without blocking new work. </Tip> <Tip> **A technician on a Neo schedule gets that schedule's hours.** A schedule set on the Technicians page replaces the PSA working hours for that technician, a day with a break returns one `working_hours` row per part, and `working_hours_source` names the schedule. See [Technician working hours](/product/technician-working-hours). **Set your technicians' timezones so appointments schedule in local time.** Working hours are reported in each technician's own timezone. On HaloPSA, Neo resolves that timezone in order — the technician's **agent-level Timezone**, then their assigned **Workday's** timezone, then your tenant's default timezone. Setting a Timezone on the technician's agent record (or their Workday) keeps dispatched appointments inside their real working hours; a technician with no timezone anywhere falls back to your tenant default rather than UTC. </Tip> <Tip> **Name a group to scope the pool.** When your instructions say "choose from Tier 1 Helpdesk", the agent looks up your [technician groups](/product/technician-groups), picks the one your instructions mean even when the wording differs, and reads only its current members, never the whole roster. Each technician's groups also come back next to their name, and each group's instructions come back once. </Tip> <Tip> **Company rules come back next to each technician's name.** Only the rules for the ticket's company come back: whether it is a preferred company, a company they never take, or outside the preferred companies of a technician limited to them, with the note. Verify Dispatch Decision warns when the agent picks a technician who never takes the ticket's company, or who is limited to other companies. </Tip> ## How to Use 1. Build a dispatch workflow (or start from a dispatch [recipe](/recipes/assign-technician-basic)) 2. Switch **Get Technician Context** on in the agent's toolbox. Verify Dispatch Decision comes with it 3. In custom instructions, describe your routing rules — preferred boards, escalation thresholds, who handles what. Reference "engineer's working hours" / "calendar working days" naturally; the agent will fetch them via this tool 4. Review assignments in [Executions](/product/executions) before turning off technician approval <Tip> The richer your PSA data — skills on technician records, accurate schedules, configuration items on tickets — the better the agent's dispatch decisions. This tool only surfaces what your PSA (and connected calendars) already know. </Tip> # PSA API Source: https://docs.neoagent.io/agents/tools/psa/psa-api How Neo Agents read and write your PSA — tickets, notes, time entries, contacts, and more Neo Agents act on your PSA through a single API-backed tool — **ConnectWise PSA API**, **Autotask PSA API**, **Halo PSA API**, **ServiceNow PSA API**, or **Syncro PSA API**, depending on which PSA you've connected. Rather than enabling separate tools for "update ticket fields", "add a note", "merge tickets", and so on, you pick which **permission groups** the agent can use and the matching capabilities turn on at once. <Info> The PSA API tool appears in your agent automatically once you connect a PSA — there's no separate toggle in the tool list. You control what it can do on the workflow's **Integrations** tab. </Info> ## What It Does * Read and update tickets — status, priority, type, board/queue, assignee, custom fields * Add internal notes, detail descriptions, and resolution notes * Add client-facing notes (which your PSA may deliver as an email to the contact) * Log time entries, set billable options and work types * Merge and bundle duplicate or related tickets * Look up and manage companies, sites, contacts, and configuration items * Search the product catalog and add line items to tickets * Manage schedule entries, appointments, and service calls * Query agreements, SLAs, projects, opportunities, knowledge base articles, and other PSA records * Reach any endpoint your PSA's API exposes, gated by the permission groups you enable ## Permission Groups Each PSA integration is split into permission groups — for example **Tickets**, **Ticket Notes (Internal)**, **Ticket Notes (Client-Facing)**, **Time Entries**, **Contacts**, **Companies**, **Configurations**, **Products**, **Schedule Entries**, **Agreements**, **SLAs**, **Projects**, **Knowledge Base**, **Audit Trail**, and more (the exact set varies by PSA). Every group has an access level: | Level | What the agent can do | | - | - | | **Disabled** | No access to this category | | **Read Only** | Query and list operations only | | **Read / Write** | Create and update operations | A few groups have extra switches — for example, **Tickets** lets you enable **merge** and **bundle** separately, and lets you whitelist exactly which ticket fields the agent may change. **Delete** is off by default everywhere and must be turned on explicitly per group. <Tip> **Letting the agent change ticket fields:** set the **Tickets** permission group to Read / Write and pick the allowed fields in its **Fields** selector. Read / Write also lets the agent create tickets and make other ticket writes. Neo then adds the [Update Ticket Fields](/agents/tools/management/update-ticket-fields) tool to the agent, which applies each PSA's field rules. The one field list limits both tools, and the group's technician approval covers both. Notes (**Ticket Notes (Internal)** and **Ticket Notes (Client-Facing)**), time entries (**Time Entries**) and contacts (**Contacts**) have their own groups. </Tip> ### Autotask: pinning a Note Type on internal notes On Autotask, the **Ticket Notes (Internal)** permission group at Read / Write has a **Use Custom Note Type** switch. Turn it on to pin a fixed **Note Type** and **Note Publish** on every internal note Neo writes, instead of letting the agent choose. This is useful when you have Autotask workflow rules that fire on notes — a dedicated note type lets those rules recognise Neo's notes and treat them differently from a technician's or a contact's reply. The **Note Publish** options are scoped by audience: the **Ticket Notes (Internal)** group offers only internal values (*Internal Project Team*, *Internal & Co-Managed*), while the **Ticket Notes (Client-Facing)** group offers the customer-facing value (*All Autotask Users*). When set, the configured Note Type/Publish is applied to internal notes regardless of what the agent would otherwise pick. <Note> One deliberate exception: a note [attributed to the technician who asked for it](/chat-agents/building-a-chat-agent#psa-records-carry-the-technicians-name) keeps its ordinary note type. The pinned type means "Neo wrote this", so stamping it on a note Autotask is recording under a real person would make your own workflow rules treat that technician's note as Neo's. Notes Neo writes on its own — every automation, and anything it isn't attributing to someone — still carry the pinned type. </Note> ### HaloPSA: blocking spam senders with Email Rules HaloPSA has an **Email Rules** permission group covering Halo's inbound email rules (*Configuration → Email → Email Rules*). Its main use is stopping repeat spam at source: instead of an agent closing the same spam ticket every time that sender writes in, it adds an **Ignore Email** rule for the address and Halo stops raising tickets from it at all. That saves the credits those repeat closures would burn, and it works where Halo's own "treat as spam" doesn't — that option is UI-only, gated on agent role, and can't be reached from Halo's quick actions or workflows. Email Rules is separate from the **Configuration** group and read-only in every profile except *IT Admin* and *Full Automation*, so nothing changes until you grant it. Two things to know before you do: * **It takes two switches, not one.** Granting the permission group lets Neo *read* your rules; creating one also needs the `admin` OAuth scope on your HaloPSA API application, which the standard Neo setup deliberately leaves off. Walkthrough: [Letting Neo Manage Email Rules](/integrations/psa/halopsa/managing-email-rules). * **A rule that matches too broadly silently drops mail.** Ignored email raises no ticket, so nothing surfaces for a technician to notice. Neo blocks one exact sender address per rule and won't ignore a whole domain on its own; deleting the rule restores delivery. Turn on technician approval for this group if you'd rather see each block first. ### Syncro: separating public comments from internal ones Syncro has one comment endpoint for both kinds — a comment is customer-facing unless it carries `hidden=true`, and Syncro emails the requester when a public one is added. Neo splits them into two permission groups anyway: a comment marked hidden needs **Work Notes**, and everything else needs **Client-Facing Notes**. A comment sent with no visibility flag counts as public and needs **Client-Facing Notes**, because that is what Syncro does with it. To let an agent take notes without ever mailing a customer, grant **Work Notes** at Read / Write and leave **Client-Facing Notes** at Read Only. Syncro's permission groups are **Tickets**, **Work Notes**, **Client-Facing Notes**, **Time Entries**, **Customers**, **Contacts**, and **Technicians**. **Tickets** also covers the read-only status, priority, and ticket-type catalogs the agent reads before a ticket write, and reading a ticket's comments — a plain ticket read returns them anyway, so the two notes groups control who can *write* a comment. The **Tickets** group's **Fields** selector lists Status, Priority, Problem Type, Subject, Assigned Technician, Contact, Customer, Custom Fields, Ticket Type, Due Date and Tags. A selection limits what a ticket update (`PUT tickets/{id}`) may set; ticket creates are not limited, and comments added in the same update are governed by **Work Notes** and **Client-Facing Notes**. Everything Syncro exposes beyond those areas — invoicing, estimates, products, purchase orders, payments, appointments, assets, wiki, and its bundled RMM — is out of reach for agents. Two things are blocked even though they sit under an area agents can reach: **ticket line items**, because they feed invoices, and a customer's **stored payment methods**, which agents can neither read nor change no matter how their permissions are set. ### ServiceNow: limiting which ticket fields an agent changes The **Tickets** group's **Fields** selector lists State (Status), Priority, Urgency, Impact, Assignment Group, Assigned To, Caller (Contact), Company, Category, Subcategory, Configuration Item, Short Description, Description, Close Code and Close Notes. A selection limits what an update of one ticket record (a PATCH on a record's `sys_id`) may set, on every ticket table the group covers. Ticket creates are not limited, and `comments` and `work_notes` are governed by the **Client-Facing Notes** and **Work Notes** groups. With a selection in place, an update that sets any other column, such as a `u_*` custom field, is refused. Keep **All fields** for an agent that writes custom fields. ### ServiceNow: what agents can read from attachments The **Attachments** group lets an agent list what's attached to a ticket — file name, type and size — read the contents of small text files (`.csv`, `.txt`, `.log`, `.json`, `.xml` and similar) up to 1 MB, and read images (screenshots, photos — `.png`, `.jpeg`, `.gif`, `.webp`) up to 8 MB. Images are never shown to the agent as raw pixels: Neo generates a written description of what the image shows — error dialogs, codes, visible UI state — and the agent works from that. It stops there by design. Spreadsheets, `.msg` files, PDFs and other binary formats are listed but not opened, and files over the size limits are refused rather than truncated — an agent that guessed at a spreadsheet's contents from its filename would be worse than one that says it can't open it. The group is read-only in every access profile, including Full Automation: Neo cannot upload or delete attachments through it. Screenshots embedded inline in ticket notes need no permission group — those are already described to the agent as part of the ticket. The Attachments group adds on-demand reads of files that aren't referenced in the notes. <Note> ServiceNow stores attachments per record, not per customer. Agents are directed to scope every attachment read to the ticket they're working on, but the group itself has no company boundary — worth knowing before you grant it on an agent that serves multiple end clients. </Note> ### ServiceNow: reading knowledge articles The **Knowledge Base** group lets an agent search and read published articles, along with the knowledge bases and categories that organise them and any feedback left on an article. Grant it when your agents should resolve tickets using what your team has already written up — an agent handed a KB number in a ticket description can read that article instead of replying that it has no access. Articles built from templates (how-to, known-error, or your own custom templates) are covered too — their body lives in the template's own table rather than the base article record, and Neo reads it from there. It is read-only in every access profile, including Full Automation. ServiceNow publishes articles through draft → review → published, and an article created over the API would sit as a draft nobody sees — a Business Rule quietly reverts `published` when the connected account lacks publish rights. If you want an agent to help write articles, have it draft the content in its reply for a technician to publish. <Note> If you run a separate knowledge base per end client, note that this group can read all of them — ServiceNow applies no company boundary to knowledge articles. Neo is directed to identify the knowledge base belonging to the ticket's company and search within it, and never to quote another customer's article. The connected ServiceNow account already has this same access, so this grants Neo no more reach than the technicians it works alongside — but it is worth knowing before enabling it. </Note> ### ServiceNow: reading approvals The **Approvals** group lets an agent read the approver rows on changes, requests and catalog items — who is on the approval, which group they belong to, and whether it is requested, approved, rejected or not required. It answers "who is this change waiting on", and lets an agent build an approver list from your ServiceNow assignment groups. It is read-only, and unlike the other read-only groups this one isn't a technical limitation: recording an approval is a decision that belongs to a person, and ServiceNow offers no way to undo it through the API. An agent can tell you a change is sitting with a particular approver; it won't approve it for you. If you want that to change, it should be a deliberate conversation rather than an access-level toggle — approvals would come back with technician approval always required, regardless of how the rest of the agent is configured. ### ServiceNow: creating and updating people The **Users and Groups** group covers the people records in ServiceNow — platform users, CSM contacts, assignment groups, group membership and role assignments. At Read Only an agent looks people up: find the contact who raised a request, check which assignment group someone belongs to, resolve a caller to their record. At Read/Write it also creates and updates them, which is what an onboarding agent needs to add a new starter as a contact without a technician retyping the form. Read and write CSM contacts on the `customer_contact` table rather than `sys_user`. Both return the same people, but only `customer_contact` carries the contact-only fields such as the end client the person belongs to, so a write through `sys_user` silently leaves those empty. <Note> Read/Write here means the agent changes identity records, and only your access level and the technician-approval toggle stand in front of it. The Full Automation profile sets this group to Read/Write with approval off, so an agent on that profile creates and updates people unattended. If you want a person to see each one, set the group to Read/Write with technician approval on, or leave it Read Only and have the agent draft the details for a technician. The connected ServiceNow account's own roles still apply on top: the agent can never do what that account cannot. </Note> ### ServiceNow: contracts and who they cover The **Contracts** group lets an agent read the contracts a client holds (`ast_contract`) and, at Read/Write, record which contacts each one covers (`contract_rel_contact`). Grant it when onboarding should finish the job — a new starter added as a contact and covered under the right support contract, without a technician retyping the link. The contract record itself stays read-only at every access level, including Full Automation. Term, cost, renewal and payment schedule are commercial data, and an agent linking to a contract is a different act from authoring or repricing one. Read/Write here adds the coverage link and nothing else. <Note> Contract product codes repeat across clients, with one row per account carrying the same code, so the agent matches on the account-qualified name in `vendor_contract` rather than the description. If your contracts are named another way, say so in the agent's instructions. </Note> ## Access Profiles Quick-start profiles configure every permission group at once: | Profile | Best for | | - | - | | **Read Only** | Monitoring, triage, and reporting agents | | **Helpdesk** | Tier 1 agents — status changes, notes, basic ticket updates | | **IT Admin** | Tier 2/3 agents — full ticket lifecycle, time entries, contacts, configurations | | **Full Automation** | Fully autonomous agents — all operations, no approval required | ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval before writes — configurable per permission group | | **Field-level control** | Whitelist exactly which ticket fields the agent may change, on every PSA, and which time-entry fields on ConnectWise, Autotask and Halo. The list limits updates to an existing record; it does not limit creates | | **Delete control** | Delete permissions are off by default and must be explicitly enabled per group | | **Audited writes** | Every change is attributed to the API member / service account you connected, so it shows up in your PSA's audit trail | | **Test mode** | When test mode is on, the agent plans the writes but doesn't execute them | ## Self-Correcting Field Errors PSAs often reject a bad request with an opaque error, which can send an agent into a loop of guessing field names. Neo catches these at the source: when a write uses a field the entity doesn't have (a typo, or a field borrowed from a different entity), the error the agent receives is rewritten to name the invalid field and — for Autotask — list the entity's actual valid field names. The agent corrects itself on the next attempt instead of retrying blindly. This runs automatically for every PSA write; there's nothing to configure. Neo also checks the **value** of a dropdown field against your tenant's own synced options before the write is sent — a status, priority, type, or queue the agent invented is rejected with your real options listed inline, so the agent picks a valid one rather than writing a wrong value or looping on a rejection. Which fields are covered varies by PSA, and a field is only checked once its options have synced; anything not covered still falls through to the PSA's own validation. Autotask can accept a write and still leave a field empty, such as a ticket's **Resolution**. After many Autotask creates and updates, such as a ticket update, Neo reads the record back. When that check finds a field the agent sent was not saved, Neo sends that field once more on its own, with nothing else in the update, and reads the record back again. If the field is now saved, the write succeeds. If it is still empty, the agent gets the write as failed, with the field named, reports that Autotask did not save it, and does not treat the ticket as finished. If Neo cannot tell, because the second update timed out or the record could not be read back, the agent reads the record once itself before it reports. ## How to Configure <Steps> <Step title="Connect your PSA"> Set up the integration: [ConnectWise](/integrations/psa/connectwise/overview), [Autotask](/integrations/psa/autotask/overview), [HaloPSA](/integrations/psa/halopsa/overview), [ServiceNow](/integrations/psa/servicenow/overview), or [Syncro](/integrations/psa/syncro/overview). </Step> <Step title="Choose an access profile"> On the workflow's **Integrations** tab, pick a quick-start profile or customize each permission group's access level. </Step> <Step title="Pick allowed ticket fields"> On the **Tickets** permission group, choose in **Fields** which fields the agent may update (status, priority, type, custom fields, and so on), or keep **All fields**. The list also limits the [Update Ticket Fields](/agents/tools/management/update-ticket-fields) tool. </Step> <Step title="Set approval requirements"> Decide which permission groups require technician approval for writes. Approval applies to the **whole group** — on **Tickets** that includes closing a ticket, not just creating one. See [where approval can be required](/core/technician-in-the-loop#where-approval-can-be-required). </Step> </Steps> <Tip> Start with **Helpdesk** and technician approval on for writes. Watch the agent's actions in [Executions](/product/executions), then widen the permissions and turn approval off for routine operations as you build confidence. </Tip> # Find RMM Scripts Source: https://docs.neoagent.io/agents/tools/rmm/find-rmm-scripts Search the scripts Neo syncs from your RMM by name or by what they do, without running anything <Info> Switch this tool on in the agent's tool list. It reads only the script library Neo syncs from your RMM, so it needs no RMM permission. On an RMM that [Execute RMM Script](/agents/tools/rmm/run-rmm-script) supports, turning on **script execution** on the **Integrations** tab also gives the agent this tool. </Info> ## What It Does * Search your RMM's script library by name, or by a description of what the script should do * Search the whole library, or only the scripts for one device * Return each script's name, description and variables, so the agent can say which script fits the ticket The tool never runs a script. Use it for agents that recommend a fix to a technician, or that report which scripts exist, without the right to run them. ## Good to Know * **Your RMM must have a script catalog.** Neo syncs scripts from NinjaOne, Datto RMM, N-Sight, ConnectWise Automate, ConnectWise Asio, N-Central, Kaseya VSA X and Addigy. ConnectWise ScreenConnect and Syncro publish no script catalog, so the search finds nothing there. * **No match is not proof.** A script added in the RMM since the last sync is not in the search yet. The agent tells you which search it tried and what to try next. * **The result is the catalog record.** It holds the script's name, description and variables, but not its source code. Before it runs a script, an agent with script execution tries to read the source through your RMM. When the agent cannot read the source, it checks the name, description and variables, and then follows your approval setting. If the run needs approval, the request says the source was not read, so the technician can check the script in the RMM console. If it needs no approval, the agent runs the script and says in its summary that it did not read the source. # RMM API Source: https://docs.neoagent.io/agents/tools/rmm/rmm-api How Neo Agents read your RMM — devices, organizations, software, alerts, and patch state Neo Agents read your RMM through a single API-backed tool — **NinjaOne RMM API**, **Datto RMM API**, **N-Sight RMM API**, **N-Central RMM API**, **ConnectWise Automate API**, **ConnectWise Asio API**, **Kaseya VSA X API**, **ConnectWise ScreenConnect API**, **Syncro RMM API**, or **Addigy API**, depending on which RMM you've connected. It gives the agent the device and monitoring context it needs to triage tickets, pick the right remediation, and spot upsell opportunities. <Info> The RMM API tool appears in your agent automatically once you connect an RMM — there's no separate toggle in the tool list. You control what it can do on the workflow's **Integrations** tab. To **run scripts** on a device, see [Execute RMM Script](/agents/tools/rmm/run-rmm-script). </Info> <Note> **ConnectWise ScreenConnect** is a remote-support tool rather than a full RMM, so its API is organized around **sessions** (the installed access agents). Its permission groups are **Sessions** (read device/session data; manage session metadata), **Commands** (run a command on an endpoint), and **Toolbox & Messaging**. Because a command runs with the agent's privileges (SYSTEM on Windows, root elsewhere), keep **Commands** read-only — or turn on **Require approval** for it — unless you intend the agent to run commands autonomously. </Note> <Note> **Syncro RMM** has a much smaller API than the other RMMs, so its tool has two permission groups rather than the usual six or seven: * **Devices** — managed devices, their installed applications, and Windows patch status. Write additionally allows creating an asset and updating one's name, customer, serial, type and properties. * **Alerts** — read, mute, raise, and resolve RMM alerts. Resolving is behind its own **Resolve** toggle and always asks for technician approval, because it clears the alert off your technicians' console and can't be undone from Neo. **Syncro script execution is not available to agents.** Syncro's schedule endpoint reports no result — no run id, no output — so an agent could never tell you whether a script ran or what it did. Rather than offer that blind, Neo leaves it out: [Execute RMM Script](/agents/tools/rmm/run-rmm-script) does nothing on Syncro, and scripts stay a technician action in the Syncro console. </Note> <Note> **Addigy** manages Apple devices only (Macs, iPhones and iPads). Its tool has seven permission groups: * **Devices & Facts**: search devices by any device fact, and read installed apps, certificates, custom facts and child organizations. Write sets static field values on devices. * **Alerts & Monitoring**: read received alerts, monitoring items and system events. Write acknowledges, mutes and resolves alerts. * **Scripts & Commands**: read the script library and earlier command output. Write runs a command or script on named devices, as root on a Mac. The agent runs scripts from your Addigy library through [Execute RMM Script](/agents/tools/rmm/run-rmm-script) and ad-hoc commands through this tool. * **MDM Device Actions**: restart, shut down or rename a device, unlock a user account, and turn lost mode off. * **Policies**: read policies, MDM profiles, declarations, compliance and benchmarks. Write moves devices between policies, deploys a profile and forces a declarative management sync. * **System Updates**: read installed and available OS updates. Write schedules an update install on named devices, which can restart them. * **Users**: read Addigy console users and end-user device assignments. Write assigns a device to an end user. The agent calls only the Addigy endpoints Neo supports: the reads in these groups and the actions listed above. Neo refuses any other Addigy write before sending it. Some actions always ask for technician approval, whatever the group is set to: erasing, locking or removing a device, turning on lost mode, rotating the FileVault key or the managed admin password, and creating, changing or removing an Addigy console user. The agent never reads the managed admin password or other stored secrets, and it has no access to billing, impersonation or TempAdmin. </Note> ## What It Does * Look up devices and their details — OS, last check-in, online status, owner, organization * Map a ticket's configuration item to the right RMM device * Check installed software and software inventory * Read open alerts and monitoring conditions * Check patch and OS-update status * Read backup status (where the RMM exposes it) * Map RMM organizations to your PSA companies * Reach any endpoint your RMM's API exposes, gated by the permission groups you enable ## Permission Groups Each RMM integration is split into permission groups — for example **Devices**, **Organizations**, **Software**, **Alerts**, **Automation**, **Backup**, and others (the exact set varies by RMM). Every group has an access level: | Level | What the agent can do | | - | - | | **Disabled** | No access to this category | | **Read Only** | Query and list operations only | | **Read / Write** | Create and update operations (where the RMM supports it) | Most RMM use cases only need **Read Only** — the agent reads device and monitoring state to make decisions, and acts through [Execute RMM Script](/agents/tools/rmm/run-rmm-script). ## Safety Controls | Control | Behavior | | - | - | | **Read-by-default** | Start with Read Only — the agent observes, scripts do the acting | | **Technician-in-the-Loop** | Require human approval before writes — configurable per permission group | | **Test mode** | When test mode is on, the agent plans writes but doesn't execute them | ## How to Configure <Steps> <Step title="Connect your RMM"> Set up the integration for [your RMM platform](/integrations/rmm/intro). </Step> <Step title="Choose permission group access levels"> On the workflow's **Integrations** tab, set each RMM permission group to Read Only or Read / Write. </Step> <Step title="Enable script execution if needed"> Turn on the RMM scripting permission to let the agent find and run scripts — see [Execute RMM Script](/agents/tools/rmm/run-rmm-script). </Step> </Steps> <Tip> Pair the RMM API with your PSA and documentation tools: the agent can read a disk-space alert, check the device age in the RMM, run a cleanup script, and — if the device is old — message the customer about a refresh. That's a maintenance ticket turned into a hardware quote. </Tip> # Execute RMM Script Source: https://docs.neoagent.io/agents/tools/rmm/run-rmm-script Find and run scripts from your RMM library on target devices to fix issues automatically This tool lets a Neo Agent find a relevant script in your RMM's library, run it on the right device, wait for the job to finish, and act on the result — close the ticket on success, escalate or try an alternative on failure. It's how Neo does zero-touch remediation. <Info> Enabled automatically when you turn on RMM **script execution** on the workflow's **Integrations** tab — there's no separate toggle in the tool list. Requires a connected RMM that supports script execution (NinjaOne, Datto RMM, N-Sight, ConnectWise Automate, ConnectWise Asio, Kaseya VSA X, Addigy; more in progress). For read-only device and monitoring data, see [RMM API](/agents/tools/rmm/rmm-api). </Info> ## What It Does * Search your RMM's script library by description and match it to the ticket's issue * Resolve the ticket's configuration item to the right RMM device * With several RMMs connected, run on the exact RMM the device belongs to — if a device ID matches devices in more than one RMM, the agent is shown the candidates and picks one explicitly instead of guessing * Run the script on that device * Wait for the job to complete and read its output * Verify the issue is resolved, then take follow-up action — close and notify, escalate, or try another fix Finding scripts, executing them, waiting for results, and reading output are all part of this capability — you don't enable them separately. To let an agent search the script library without running anything, switch on [Find RMM Scripts](/agents/tools/rmm/find-rmm-scripts) alone. ## Burst Protection RMM devices run one job at a time, and Neo marks a job failed when it has not finished in time: 60 minutes after Neo sends it to the RMM, or 30 minutes when the agent waits for the result in the same step. When many jobs target the same device at once — end-of-month change requests, bulk maintenance — Neo holds the excess in a dispatch queue and releases each job as the device frees up, so a busy device does not build a backlog that times out. Queued jobs show as **queued** in Executions and dispatch automatically — no action needed. A job that can't be dispatched within 8 hours (device offline or saturated) is marked failed with a clear reason. Datto RMM Quick Jobs do not expire. After Neo marks a Datto job failed for time, at 30 or 60 minutes, the job stays in Datto RMM and can still run, for example when an offline device comes back online. Neo does not record or act on that later result, so check the job in Datto RMM before you run the script again on that device. Until Datto reports that job finished, or you remove it in Datto RMM, it still counts against the device's limit of 5 jobs, for up to 7 days. <Note> **Completed with no output.** Occasionally a job finishes but returns no logs or output — the script produced nothing, the device didn't report its result back, or the run logs are unavailable. Neo flags this case explicitly instead of treating the empty result as success, so the agent re-runs the job, checks the device's connectivity in the RMM, or escalates to a technician rather than closing a ticket on a result it couldn't verify. </Note> <Note> **A script the RMM keeps refusing.** Datto RMM can reject a script submission with a plain server error and no reason, which usually clears in minutes — Neo retries and carries on. When the same script and device have been rejected repeatedly for over a day, Neo stops retrying and escalates instead. Open the component in Datto RMM and check that it still exists, is permitted on that device, and has the variables the agent supplies. </Note> <Note> **A server error on submission.** An RMM can report a server error after it has already queued the run, so a submission that fails this way may still execute. Neo treats the outcome as unverified instead of assuming the run was rejected. Check the device's scheduled jobs and script history in the RMM before running the script again. </Note> <Note> **A script NinjaOne accepted but Neo can't track.** NinjaOne confirms a script run without returning a job ID, so Neo identifies the run by matching it against the device's activity feed straight afterwards. If NinjaOne hasn't published that activity in time — a lagging feed, or a script renamed in NinjaOne since Neo last synced your script library — Neo has no handle to poll for the result. Neo says NinjaOne accepted the run and its state cannot be read, and tells the agent not to start a second copy until someone reads the outcome, because the two would collide. Check the device's activity feed in NinjaOne for the outcome, and re-sync your script library if the name has changed. </Note> ## Safety | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval before any script runs — strongly recommended until you trust the agent's choices. Set by **Require Technician Approval** on the RMM's script-execution permission group (Integrations tab) | | **Pre-approved scripts** | Keep approval on for everything, but list specific known-safe scripts (e.g. read-only health checks) that may run without a per-run approval. Set them under **Pre-approved scripts** on the RMM's script-execution permission group: a script ID and the exact variables. Matched **exactly** on the script and its variables, so a different script — or the same script with different variables — still requires approval. Each entry applies only to the RMM whose group holds it, because script IDs are only unique within one RMM. With several RMMs connected, a run skips approval only when the agent names the RMM it runs on. The agent sees the list, including the variable values, so never pre-approve a variable that holds a password or token. It reads a matching script where the RMM exposes its body, and runs it without a request. Only ConnectWise Automate exposes a script's body, so on every other RMM the agent runs a pre-approved script without reading its body and says so in its summary. Keep the list to scripts whose content you control, because the entry approves whatever the script ID holds when it runs. On a [supervised run](/core/supervised-mode) the list does not apply, and every script asks | | **Script library is yours** | The agent can only run scripts that already exist in your RMM — it can't write new ones | | **Custom instructions** | Tell the agent which scripts to prefer, which to avoid, and when to escalate instead of running anything | | **Test mode** | When test mode is on, the agent picks the script and device but doesn't run anything | <Note> When technician approval is enabled for this tool, the agent must obtain an actual approved Technician-in-the-Loop request before a script runs — it requests approval first, then executes once approved. The one exception is a script on the **Pre-approved scripts** list, run with exactly the listed variables: the agent is told which scripts are on the list, and runs a matching one without a request. Marking a script "pre-approved, no approval needed" in **custom instructions** does not waive this: custom instructions guide which scripts the agent prefers, but they can't bypass the approval requirement. To let specific known-safe scripts run without a per-run approval, add them to **Pre-approved scripts** on the RMM's script-execution permission group — matched exactly on the script and its variables — rather than relying on a note. Everything not on the allowlist still requires approval, so you keep the guard where it matters while letting routine read-only diagnostics run immediately. </Note> <Note> **What the run record shows about approval.** When a script run needed a Technician-in-the-Loop approval, the step that started the job names the approval that permitted it, once that call returns. Neo reads the request ID and the approver off the request it matched for that call, so that first line comes from the approval itself. When the agent sends the reference only it holds — the runbook or knowledge-base article, and a one-line justification — it is added on a second line, marked as agent text Neo did not verify. Open the run in [Executions](/product/executions) and read it on the Execute RMM Script step, instead of relying on the agent remembering to write a note. A retry that finds the job already running attaches to it and names no approval again, because the approval belongs to the call that started the job. So if the call that started the job stops before it returns, no step names the approval for that job. It lives on the starting step and not on the RMM job, so a later read of the job's result does not repeat it and Neo writes no ticket note. It is a record of the authorization, not the authorization itself: an approval-gated script still needs a real approved request before it runs. </Note> <Note> **Where approval is set.** Approval for script execution comes from **Require Technician Approval** on the permission group that grants scripting for your RMM — Datto RMM **Jobs**, NinjaOne / VSA X / CW Asio **Automation**, N-Sight **Tasks**, CW Automate **Script Execution**, Addigy **Scripts & Commands**. Turning it on there gates script runs as well as that RMM's API calls. If you connect several RMMs and any one of them has approval on, script execution asks for approval on all of them — the agent has a single approval setting covering every RMM. </Note> <Note> **Which devices the agent can target.** A chat agent can run a script on any device in your synced inventory that belongs to an RMM you have enabled script execution for — a technician naming a machine in chat is the instruction, and no ticket is required. An automation with a ticket can only act on devices belonging to the **ticket's company**, so it can't reach another customer's machine. A run without a ticket — a chat turn, or a scheduled agent with no ticket in context — skips that company scope, so target the device explicitly. </Note> <Note> **Enabling one RMM does not enable the others.** Script execution is granted per RMM. If you enable it on ConnectWise Automate but not on NinjaOne, the agent can run scripts on Automate devices only. When it targets a NinjaOne device it stops and tells the technician that an administrator must enable NinjaOne script execution on that agent first — it will not fall back to another RMM. This matters most when one customer's machines are split across two RMMs, because the agent picks the device by name and the device decides which RMM the script runs on. </Note> <Note> **ConnectWise Automate — script priority.** Automate runs scheduled scripts by priority (1 lowest, 15 highest). Neo submits Automate scripts at **15 (highest) by default**, so remediation runs right away instead of waiting behind lower-priority queued work. To make a specific script yield to your other Automate jobs instead, tell the agent in **custom instructions** to run it at a lower priority — for example, "run cleanup scripts at priority 5." Other RMMs ignore this setting. If your Automate server fails the submission with a server-side error, Neo may run the script through Automate's batch endpoint instead, at the same priority. The agent's run notes say when that happened. </Note> <Note> **ConnectWise Asio.** Neo runs Asio scripts by scheduling them on the endpoint. The agent reads each script's parameters and fills them in — including the built-in **"PowerShell script"** template, whose `body` parameter takes an entire ad-hoc PowerShell payload (for example, download an installer and run a silent install). Grant the **Automation** permission group **Read & Write** to allow execution. Newly connected or changed scripts expose their parameters after the next RMM sync. </Note> <Note> **Addigy.** Neo runs scripts from your Addigy script library on Macs. They run as root, as macOS shell (bash or zsh), never PowerShell. Each run sends the script as it is in Addigy at that moment, so an edit made after the last sync still applies. Addigy scripts take no variables. Grant the **Scripts & Commands** permission group **Read & Write** to allow execution; the API key needs the **View Predefined Commands** and **Execute Commands** permissions. </Note> ## How to Configure <Steps> <Step title="Connect an RMM that supports script execution"> Set up [NinjaOne, Datto RMM, or N-Sight](/integrations/rmm/intro). </Step> <Step title="Enable RMM script execution"> On the workflow's **Integrations** tab, turn on script execution for that RMM. </Step> <Step title="Set approval requirements"> Start with **Require Technician Approval** on for that RMM's script-execution permission group — the same toggle you used in the previous step. To skip approval for known-safe scripts, add each one under **Pre-approved scripts** on the same group. Add custom instructions about which scripts to prefer or avoid. </Step> <Step title="Watch the results"> Review every run in [Executions](/product/executions) before widening automation. </Step> </Steps> <Tip> Keep approval on while you build a track record. Once you've seen the agent reliably pick the right script for a class of tickets — password-reset agents, printer-spooler restarts, disk cleanups — you can turn approval off for just those. </Tip> # Get Synced Devices Source: https://docs.neoagent.io/agents/tools/rmm/synced-devices Device records and per-company workstation/server counts from Neo's synced RMM inventory <Info> This is an always-on, read-only tool. Every agent has it, on the native tool surface and inside the code sandbox (`from neo.client import list_synced_devices, get_synced_device_counts`). There is nothing to enable. </Info> ## What It Does Reads `client_rmm_devices`, the RMM inventory Neo already syncs from every connected RMM and maps to PSA companies. Neo resolves the RMM-to-PSA company mapping and the workstation/server type **at sync time**, and `data_as_of` says when that sync ran. The agent picks one of two views per call: | View | Answers | Returns | | - | - | - | | `devices` | *Which* devices | One record per device | | `company_counts` | *How many* devices | Counts per company and for the whole tenant | Both views return `data_as_of`, the time of the latest device sync. ### The `devices` view For each device: * `rmm_device_id`: the RMM's device ID, which works with `find_configurations` and the RMM tools. * `rmm_vendor`: the RMM the device came from. Device IDs are per-vendor, so a tenant with several RMMs needs this before it sends an ID to one vendor's API. * `name`: the device hostname as synced. * `device_type`: `WORKSTATION`, `SERVER` or `UNKNOWN`. * `psa_company_id` and the resolved `company_name`. Plus `returned` and `truncated`, which is true when more devices matched than `limit` returned. ### The `company_counts` view * Per company: `workstations`, `servers`, `unknown` and `total`, with the PSA company name. * Per company, the PSA account status and type: `is_active`, `account_types` (for example `["Client"]` on ConnectWise, `["Customer"]` on Autotask and ServiceNow) and `status_name` (ConnectWise's company status label; `null` on other PSAs). On ConnectWise a label such as `Client` can be a company type, a company status, or both, so a report filters on the one the MSP means and says which. * Totals for the whole tenant. * The mapped and unmapped split: how many devices Neo matched to a PSA company. * `unresolved_companies`: companies mapped to a PSA company ID whose PSA record did not resolve, so their `company_name` is empty. A report names these as a caveat. On a row for a mapped company whose PSA record resolved, the company name is the **PSA account name**, resolved through Neo's company hub and never an RMM-side label, and the row carries the PSA account status and type. So the agent answers a "clients only" or "active only" report from this view without a live RMM pull. The Unmapped row and the unresolved companies have no name, status or type; a report names them as caveats. ## Why It Exists Reporting and reconciliation agents (billing reconciliation, seat true-ups, asset audits) used to pull the live RMM and match hundreds of company names by hand on every run, and the same monthly report could change between runs. This tool gives them the inventory Neo has already mapped. When a count looks wrong, the `devices` view names the machines behind it. ## How to Use * Pass `name_contains` in the `devices` view to find a device by hostname. It is a case-insensitive substring match that runs **server-side**, so the agent gets only the matching devices. Add `psa_company_id` to search one company. * Pass `psa_company_id` to read one company. Omit it for every company. * `unmapped_only` (`devices` view) lists only the devices Neo could not match to a PSA company. * `include_unmapped` (`company_counts` view, default true) adds the "Unmapped" bucket as a row. The totals include it either way. * `limit` (`devices` view, default 1000, maximum 5000) caps the list. When `truncated` is true, narrow the scope or raise `limit`. * State `data_as_of` in a report, and name a large `unmapped_devices` count or a non-zero `unknown` bucket as a coverage caveat. The sandbox helpers return the same data with the same arguments: `neo.client.list_synced_devices` for the `devices` view and `neo.client.get_synced_device_counts` for the `company_counts` view. Use them when the agent builds the report in Python. ## Notes * **Read-only** and tenant-scoped. It reads only data Neo has already synced, and never calls the RMM or PSA. * Device type comes from each RMM's metadata. A device with no clear type signal counts as `unknown`, so it does not add to the workstation total. * For live device state (online or offline, last check-in, patch or antivirus status), use the live `*_rmm_request` tools. The synced record leaves volatile state out. # ConnectWise CPQ API Source: https://docs.neoagent.io/agents/tools/sales/connectwise-cpq-api Draft and update ConnectWise CPQ quotes from an agent: copy a template, fill the lines from a PSA opportunity, change an expiry date and ask for approval ConnectWise CPQ was called ConnectWise Sell, and its API still uses that name. The tool reaches quotes with their lines, tabs, customers and payment terms, and the approval decisions on them. An agent never sees a quote's Order Porter passcode: Neo removes it from every answer. <Info> Automatically enabled when you configure ConnectWise CPQ permissions in your agent workflow. </Info> ## What It Does * Find quotes by customer, number, status or opportunity, and read their lines, totals, expiry date and approval state * Draft a quote from a ConnectWise PSA opportunity: read its notes, product lines and files, price each line from your PSA catalog, copy a template, and link the quote and the opportunity both ways * Change a quote: its expiry date, a line's quantity or price, its payment terms, or archive it * Ask for approval: write the reason on the quote, find the rep's approver among your CPQ users and message them through the agent's email or chat tools * Read your templates, tax codes and recurring billing periods CPQ computes every total, tax and margin. The agent takes part numbers and prices from your catalog or the opportunity and never invents them. A quote's Order Porter passcode opens that quote on your customer's acceptance page, so Neo removes it from every response before the agent or a sandbox script reads it, and refuses any request that filters on it or writes it. The agent cannot read, search on or change the passcode; send the quote to the customer from CPQ. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Quotes | Disabled, Read Only, Read/Write | Quotes with their versions, tabs, line items, payment terms and the customer records on each quote. Quotes carry your cost, margin and internal notes | | Quote Approval Decisions | Disabled, Read/Write | Whether a quote needs approval, and its approval status, approver, approval date and manager approval: the fields that record an approver's decision | | Users | Disabled, Read Only, Read/Write | Your CPQ users with their email address, manager and approver, and the user settings CPQ uses on quote email | | Templates and Lookups | Disabled, Read Only | Quote templates, tax codes and recurring revenue periods | Leave **Quote Approval Decisions** off on an agent that drafts quotes, so it cannot approve its own quote or clear the need for approval. The agent can still ask for approval: writing the reason on the quote is part of **Quotes**. Recording a decision also needs **Quotes** at Read Only or above, because CPQ answers with the whole quote. | Profile | Quotes | Quote Approval Decisions | Users | Templates and Lookups | | - | - | - | - | - | | Read Only | Read Only | Disabled | Read Only | Read Only | | Helpdesk | Read/Write, with approval | Disabled | Read Only | Read Only | | IT Admin | Read/Write | Read/Write, with approval | Read/Write, with approval | Read Only | | Full Automation | Read/Write | Read/Write | Read/Write | Read Only | ## Drafting from a PSA opportunity The agent reads the opportunity in ConnectWise PSA, drafts the quote in CPQ, and links the two: 1. It reads the opportunity, its notes, its product lines and up to 10 attached files. It reads PDF, DOCX, XLSX, XLS and CSV files; it names any other file, a scanned PDF, an image or a file past the tenth in its report instead of guessing what it holds. 2. It looks up each product in your ConnectWise catalog and takes the part number, description, price and cost from there. When several catalog items match, or none does and the opportunity states no unit price, the item is left out and listed for the rep. 3. It copies your template, sets the quote's name and opportunity, and adds the lines. 4. It adds a note on the opportunity with the quote number, total and expiry date, and a second note when it asks for approval. Give the agent these ConnectWise PSA groups as well: | ConnectWise PSA group | Level | Why | | - | - | - | | **Opportunities** | Read/Write | Read the opportunity, its notes and product lines, and add the notes that link it to the quote. Read Only works too; the agent then reports the link instead of writing it. | | **Documents** | Read Only | Read the files attached to the opportunity. | | **Products** | Read Only | Look up part numbers, prices and costs in your catalog. | ## Asking for approval The agent asks the approver itself. It writes the reason on the quote's approval comment, finds the rep's approver among your CPQ users, and sends them the quote number, total and reason with the email or chat tool you give it. It never says a quote is approved unless CPQ shows it. ## Setup See [Connecting ConnectWise CPQ to Neo](/integrations/connectwise-cpq/connecting-to-neo). # Kaseya Quote Manager API Source: https://docs.neoagent.io/agents/tools/sales/kaseya-quote-manager-api Read quotes, sales orders and purchase orders from Kaseya Quote Manager so an agent can answer where an order stands The Kaseya Quote Manager API tool gives Neo agents read access to Kaseya Quote Manager (formerly Datto Commerce). The common use is a question like "where is the order for quote QO10001?": the agent follows the quote to its sales order and to the purchase orders behind it, and reports the status of each. <Info> Automatically enabled when you configure Kaseya Quote Manager permissions in your agent workflow. </Info> ## What It Does * Find a quote by its number and read its status, expiry date, sections and lines * Read the quote's linked Autotask opportunity, company and quote ids. Kaseya Quote Manager's published API documents Autotask link fields and no ConnectWise link * Follow a won quote to its sales order: status, fulfilment, lines and payments * Find the purchase orders behind a sales order: supplier, status, items received and serial numbers * Look up customers, their contacts and addresses * Read the product catalog with prices, and each supplier's stock and cost The Kaseya Quote Manager API is read-only. Neo cannot create, send or change a quote, sales order or purchase order in Kaseya Quote Manager; a person does that in Kaseya Quote Manager. ## Quotes and Autotask * Ask about a quote or an Autotask opportunity. The agent links them and answers in one view: the quote, its sales order and purchase orders, and the Autotask company, opportunity, projects, contracts and tickets. * Ask the agent to price an upgrade for an opportunity. It finds each item in your Kaseya Quote Manager catalog and writes a draft to the Autotask opportunity: a note, or a to-do for the opportunity owner if your instructions ask for a task. To make the quote, open the opportunity, start a new Kaseya Quote Manager quote and add the listed items. * The draft is an Autotask write. Set the agent's Autotask **Opportunities** group to Read Only, and **Companies** (notes) or **Company To-Dos** (to-dos) to Read/Write; its approval setting applies. For notes, also set **Admin** to Read Only, so the agent can read your note types. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Quotes and Orders | Disabled, Read Only | Quotes with sections and lines, sales orders with lines and payments, purchase orders with lines, serial numbers and costs, and your employees. Quotes carry your private notes | | Customers and Contacts | Disabled, Read Only | Customers, contacts and addresses. Holds personal data: names, emails, phone numbers and addresses | | Catalog and Suppliers | Disabled, Read Only | Products, prices, brands, categories, supplier stock and cost, suppliers and warehouses. Shows your supplier cost | Every group is read only, because the Kaseya Quote Manager API has no write. Turn off Catalog and Suppliers on an agent that writes text your customers read, so it never sees your cost. ## Setup See [Connecting Kaseya Quote Manager to Neo](/integrations/kaseya-quote-manager/connecting-to-neo). # myITprocess API Source: https://docs.neoagent.io/agents/tools/sales/myitprocess-api Read myITprocess reviews, findings, recommendations and meetings so an agent can prepare a QBR The myITprocess API tool gives Neo agents read access to myITprocess, Kaseya's vCIO platform. The common use is a request like "prepare the QBR for Contoso": the agent reads the client's alignment score, its reviews and the answers to their questions, its roadmap of recommendations, and the next meeting's agenda. <Info> Automatically enabled when you configure myITprocess permissions in your agent workflow. </Info> ## What It Does * Read clients with their alignment score and last review date * Read reviews with their status, owners and due dates, and the categories up for review * Read findings: each review question the technician answered No, with the vCIO's alignment marking and the recommendation it led to * Read recommendations with budget, hours, type, status, priority and client feedback, and the initiatives they roll up to * Read QBR meetings with their date, purpose and agenda * Read the IT Glue configurations a recommendation names Neo reads myITprocess only, so it cannot answer a review question, change a recommendation or book a meeting in myITprocess; it proposes answers for a person to enter. A review question reaches the agent as the PSA ticket myITprocess opens for it, and the agent writes the proposed answer as an internal note when it can add internal ticket notes, and in its reply when it cannot. On Autotask, the agent finds a recommendation's opportunity by its title or its devices, and that opportunity's Kaseya Quote Manager quote; on another PSA it matches by title and amount. These jobs also use the agent's PSA permissions: internal ticket notes for the proposed answers; on Autotask, Opportunities and Companies to read, create or note an opportunity, Tickets and Configurations for the device match, and Resources to find the owner you name. Creating an opportunity or a note on it also needs Admin at Read Only, for the picklists and required fields Autotask sets per tenant. The device match needs IT Glue, and the quote needs Kaseya Quote Manager. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Clients and Reviews | Disabled, Read Only | Clients and alignment scores, reviews, findings with the review questions and answers, categories up for review, and your myITprocess users | | Roadmap and Meetings | Disabled, Read Only | Recommendations with budget and hours, initiatives, meetings with their agenda, and the IT Glue configurations a recommendation names. Shows your budget figures | Every group is read only. Turn off Roadmap and Meetings on an agent that writes client-facing text, so it never sees your budget figures. ## Setup See [Connecting myITprocess to Neo](/integrations/myitprocess/connecting-to-neo). # QuoteWerks API Source: https://docs.neoagent.io/agents/tools/sales/quotewerks-api Find open quotes and create new ones in QuoteWerks Web, so an agent can answer about a quote or draft one from a customer's request The QuoteWerks API tool gives Neo agents access to the QuoteWerks Web database. The common uses are a question like "where is my quote?", and a customer's request for new equipment that the agent turns into a quote. <Info> Automatically enabled when you configure QuoteWerks permissions in your agent workflow. </Info> ## What It Does * Find a customer's open quotes and read each quote's status, lines and total. The agent matches the ticket's PSA opportunity or contact first, and the company name only when neither finds an open quote * Tell whether the customer accepted a quote on QuoteValet, and when * Create a quote: the quote first, then one line per product. QuoteWerks calculates the extended prices, tax and totals * Update a quote or a line, and delete one when the request asks for exactly that * Look up products, contacts and the other tables of your QuoteWerks database * Run a saved Management Report as CSV and summarise it When the agent creates a quote, it tells you the new quote's number and asks your sales rep to upload it to QuoteValet, because that upload is a step a person does in QuoteWerks. On a later run or chat turn it reads the quote's customer link from the Autotask or ConnectWise opportunity, and gives the customer only the link for external viewing. Setup: [Link quotes to your PSA](/integrations/quotewerks/connecting-to-neo#4-link-quotes-to-your-psa-for-quotevalet-links). QuoteWerks' REST documentation does not confirm a few column names, such as the part number column on a quote line. Before the agent relies on one of them, it reads the table's schema from your account and uses the name it finds there. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Quotes and Documents | Disabled, Read Only, Read / Write | The DocumentHeaders and DocumentItems tables, and every other table whose name starts with Document. Documents carry your cost, profit and internal notes | | Products, Contacts and Other Tables | Disabled, Read Only, Read / Write | Every other table in your QuoteWerks database, except the settings tables (below). Neo cannot tell what each table holds before you connect, so Read Only and Helpdesk refuse writes here, and IT Admin asks a technician first | | Reports and Account | Disabled, Read Only | Saved Management Reports, QuoteWerks' report assistant, the list of tables and the user the key belongs to | Neo does not read or write QuoteWerks' cloud system settings, or any table whose name contains "settings", because they can hold the passwords of your account's mail server and integrations. ## Setup See [Connecting QuoteWerks to Neo](/integrations/quotewerks/connecting-to-neo). # Find Configurations Source: https://docs.neoagent.io/agents/tools/search/find-configurations Search for configuration items relevant to tickets The Find Configurations tool allows Neo Agent to search for configuration items (CIs) in your PSA that may be related to a ticket. ## What It Does When enabled, the agent can: * Search configuration items by name * Search by IP address when a ticket names only an IP (common on network, VPN, printer, and firewall tickets) — ConnectWise only * Trace a shared asset a ticket names only indirectly — the file server behind a mapped drive letter such as `Y:`, or a phone system behind a call-quality complaint — by searching the company's configuration names for that asset's role * Match CIs to ticket issues * Identify target devices for RMM operations ## How to Use This tool helps the agent: * Find devices mentioned in tickets * Identify targets for script execution * Link tickets to the correct configuration items ## Results By default the tool returns a concise, ranked summary rather than every full record, so the agent can quickly tell whether a single device matches: * **Summary** — the total number of matches, a breakdown by device type and by source (PSA vs. RMM), and a match classification (a unique match, an ambiguous set that should go to a technician, or no match — with suggested next steps). * **Top candidates** — the best matches, each with a 0–100 match score and the reasons it matched (for example: serial number, device name, IP address, contact, last-logged-in user). This is enough to pick or rule out a device without pulling every detail into view. When the agent has narrowed down to a specific device, it can request the full configuration and device records for that match. # Find Documentation Source: https://docs.neoagent.io/agents/tools/search/find-documentation Search your documentation for relevant solutions and information The Find Documentation tool allows Neo Agent to search your synced documentation sources for information relevant to tickets. ## What It Does When enabled, the agent can: * Search every documentation source you've connected, in one query * Find relevant articles, SOPs, and knowledge base entries * Use documentation context for better resolution suggestions ## How to Use 1. Ensure your documentation is synced with Neo Agent 2. Enable this tool in your workflow 3. The agent will automatically search documentation when analyzing tickets ## Supported Documentation Sources * [IT Glue](/integrations/documentation/itglue-api) * [Hudu](/integrations/documentation/hudu) * [Lexful](/integrations/documentation/lexful) * [Confluence](/integrations/documentation/confluence) * [SharePoint](/integrations/documentation/sharepoint) Content from every connected source is searched together and scoped to the same company, so an agent asks one question rather than one per platform. ## Tickets With No Company Internal and MSP-own tickets often have no company on them. There is no company to scope to, so the agent searches everything you have synced and lets relevance ranking decide — the same scope the Neo Support Agent uses in chat. The search still stays inside your own tenant, and still honours your IT Glue restricted-document setting and the agent's documentation-source permissions. # Find PSA Companies Source: https://docs.neoagent.io/agents/tools/search/find-psa-companies Search for companies in your PSA by name, contact, site or id The agent uses this tool to find a company from a name it read in a ticket or an email. On ConnectWise, Autotask and Halo, a partial or misspelled name still finds the right company. ## What It Does When enabled, the agent can search by: * Company name * Contact email or contact name * Site name, which finds the company that owns the site (ConnectWise and Autotask only) * Company id The result is the union of every search you supply. The agent also finds your own company record, for its address and similar details. ## Fuzzy Matching How a name is matched depends on your PSA: * **ConnectWise, Autotask and Halo**: the match is approximate. "Acme Corp" finds "ACME Corporation", and a misspelled contact name still finds the person. Neo matches the name against its own synced copy of your PSA data, so the matching itself is fast and sends nothing to your PSA. Reading a matched company's full details can still call your PSA when that company is not in the synced copy. * **ServiceNow and Syncro**: Neo searches your PSA directly for companies and contacts whose name contains the text. A partial name works, but a misspelled one finds nothing. The generic PSA API tools cannot match approximately. They can filter on `contains` and wildcard patterns, but they have no similarity matching, so a name your PSA does not hold in that shape returns nothing. Keep this tool enabled when your agent must work from a name a person typed. ## How to Use This tool supports: * Resolving the company on a ticket with no company set * Finding the company that owns a contact, before a notification * Looking up a company's address, type or status # Find PSA Contacts Source: https://docs.neoagent.io/agents/tools/search/find-psa-contacts Search for contacts in your PSA system The Find PSA Contacts tool allows Neo Agent to search for contacts in your PSA. ## What It Does When enabled, the agent can: * Search contacts by name or email * Find contacts for a specific company * Identify contacts to notify or add to tickets ## How to Use This tool supports: * Send to Additional Contact workflows * Contact identification for communication # Find PSA Resources Source: https://docs.neoagent.io/agents/tools/search/find-psa-resources Search for technicians and users in your PSA by name Neo matches a technician's name against its own synced copy of your PSA and returns up to 10 candidates with their PSA ids. A partial or misspelled name still finds the person. ## What It Does When enabled, the agent can: * Search technicians and users by name * Get the PSA id it needs to assign a ticket or a schedule entry ## Which PSAs ConnectWise, Autotask, Halo and ServiceNow. On any other PSA the tool is not offered, and the agent reads technicians through the PSA API tool. ## Fuzzy Matching The search is approximate. A partial or misspelled name still finds the person. Neo matches the name against its own synced copy of your PSA data, so the search is fast and sends nothing to your PSA. The generic PSA API tools cannot do this. They can filter on `contains` and wildcard patterns, but they have no similarity matching, so a name your PSA does not hold in that shape returns nothing. Keep this tool enabled when your agent must turn a name a person typed into a PSA id. ## How to Use This tool supports: * Assigning a ticket to a named technician * Naming an owner on a schedule entry or a service call # Find Tickets by Content Source: https://docs.neoagent.io/agents/tools/search/find-tickets-by-content Search tickets based on their content and descriptions The Find Tickets by Content tool allows Neo Agent to search your ticket history based on content similarity—finding tickets about similar issues. ## What It Does When enabled, the agent can: * Search tickets by description and note content * Find similar past issues * Detect duplicate tickets — including ones whose summary was reworded, since it matches by meaning rather than keywords * Identify how similar problems were resolved * Support ticket merging and bundling workflows <Note> Ticket data syncs from your PSA every 24 hours, so results may have up to a 24-hour lag. If the search finds nothing for a recent time window, the tool automatically runs a real-time query against your PSA — scoped to the same company and date range — so a just-created duplicate that hasn't been indexed yet is still surfaced. No extra step is needed to catch same-day tickets. </Note> <Note> Search results come back up to 10 tickets at a time, most relevant first, each labelled highly, medium or low relevant. The real-time PSA query returns up to 20 tickets, newest first, without a relevance label. Low-relevance matches are left out unless the agent asks for them. The result says how many more matches there are at each relevance level, and the agent can ask for them without running the search again. Each ticket shows a short summary and its key details; the agent can open a specific ticket to read its full content. </Note> <Note> A match is a lead, not proof. When an agent reads and writes your PSA through its API, before it merges or bundles a ticket onto a match, it reads that ticket's description and its notes live from your PSA and checks that both describe the same issue, such as the same device, user, mailbox, error or outage. A shared word like "VPN" or a broad title like "Master Ticket VPN issues" is not enough. If the content does not confirm the match, the agent does not merge or bundle. </Note> ## How to Use Use this tool when you want the agent to: * Find similar tickets for merge candidates * Look up how past issues were resolved * Identify patterns in recurring problems ### Example Use Cases ``` Find tickets about Outlook crashes from the past 30 days. Search for tickets mentioning "VPN connection issues." ``` # Get Ticket Source: https://docs.neoagent.io/agents/tools/search/get-ticket Read a ticket with its notes, time entries and configurations in one call Neo turns images attached to notes into text, so the agent can read a screenshot a user sent. One call returns the ticket's fields, notes, time entries and linked configurations. The ticket that started a run is already in the agent's instructions. Use this tool when the agent must read **another** ticket, for example a related or parent ticket, or when it must read the current ticket again after a change. ## What It Does When enabled, the agent can: * Read any ticket by its id * See the ticket's notes and time entries in date order * Read text from images in notes * See ticket, company and contract custom fields ## Which PSAs ConnectWise, Autotask, Halo, ServiceNow and Syncro. ## Compared with the PSA API tool The PSA API tool can read the same ticket, but it returns the raw PSA record, one call per record type, and it does not read images. Keep this tool enabled when your agent reads other tickets often. # Get Ticket Audit Trail Source: https://docs.neoagent.io/agents/tools/search/get-ticket-audit-trail Read the change history of a ticket: who changed what, and when Neo gives the agent the same history format on ConnectWise, Autotask and Halo, and by default reads the last 7 days. ## What It Does When enabled, the agent can: * Read the history of a ticket, by default for the last 7 days * Filter the history by text or by change type * Page through a long history Each change shows who made it and when. ## Which PSAs ConnectWise, Autotask and Halo. ServiceNow and Syncro have no history endpoint the tool can read. ## How to Use Use it when a decision depends on what happened to a ticket, for example: * Do not reopen a ticket that a technician closed today * Find who last changed the priority * Check whether a ticket moved between boards or queues # Web Fetch Source: https://docs.neoagent.io/agents/tools/search/web-fetch Fetch and read pages from a curated set of public documentation sites The Web Fetch tool lets Neo Agent retrieve the content of a specific public web page — Neo's own docs, Microsoft Learn, or vendor knowledge bases — and read it inline as part of resolving a ticket or answering a question. ## What It Does When enabled, the agent can: * Pull a specific page from an allowlisted host by URL * Read product documentation, vendor KBs, and configuration guides * Pair with Web Search — search to find the URL, then fetch to read it HTML pages are automatically converted to clean Markdown so the agent gets only the content (no page chrome, scripts, or styles). Plain text and Markdown pages pass through unchanged. ## Allowlist For safety, only a curated set of public documentation hosts is reachable: * Neo: `docs.neoagent.io` * Microsoft: `learn.microsoft.com`, `docs.microsoft.com`, `developer.microsoft.com`, `support.microsoft.com` * PSA vendors: `developer.connectwise.com`, `halopsa.com`, `webservices.autotask.net`, `developer.servicenow.com` * RMM and doc vendors: `docs.ninjaone.com`, `rmm.datto.com`, `support.huduapi.com`, `kb.itglue.com` You can add extra hosts per agent under the tool's settings (e.g. your own runbook site). Anything not on the allowlist — including internal IPs, private networks, and unrecognized hosts — is rejected. The allowlist also governs the agent's sandbox: scripts it runs there can reach exactly these hosts and nothing else. That lets an agent pull a large or paginated data source itself — an open data feed, a status API — and process it in the sandbox in one step. Agents without the Web Fetch tool have no outbound web access from the sandbox at all. ## How to Use 1. Enable the Web Fetch tool on the agent. 2. (Optional) Add additional hosts under the tool settings for this agent. 3. The agent uses Web Fetch when it needs the full content of a specific page — typically after a Web Search returns a relevant URL. ## Large Pages A fetch returns the whole page in a single call. When a page is too large to fit in the agent's working context, Neo saves it to a file in the agent's sandbox and gives the agent a map of the page's parts plus the file path; the agent then reads the part it needs from the file, or processes the file there — parsing the JSON, filtering rows. Nothing is silently dropped, and a large page costs one fetch rather than one per chunk. ## Limits * HTTPS only. * Pages up to 5 MB. Beyond that the response is truncated, and the agent is told so. * 10-second total timeout. * An agent's additional hosts can take up to 1,500 bytes in total, counting a comma between each pair. A plain letter, digit, dot or hyphen is one byte, so that is about 50 typical hostnames; a non-ASCII letter takes two to four bytes. The hosts listed above do not count toward this limit. # Web Search Source: https://docs.neoagent.io/agents/tools/search/web-search Search the web for troubleshooting information The Web Search tool allows Neo Agent to search the internet for troubleshooting information and solutions. ## What It Does When enabled, the agent can: * Search the web for error messages * Find vendor documentation * Look up troubleshooting guides * Research unknown issues ## How to Use Enable this tool when you want the agent to research issues beyond your internal documentation: * Unknown error messages * New software issues * Vendor-specific problems * General IT troubleshooting ## When the Search Provider Cannot Answer Sometimes the search provider cannot generate an answer for a query. The tool then tells the agent to search again with a shorter, more general query, or to read the vendor's documentation with [Web Fetch](/agents/tools/search/web-fetch) when the agent has it. # AutoElevate API Source: https://docs.neoagent.io/agents/tools/security/autoelevate-api Read AutoElevate elevation requests and the file, publisher and user behind each one, and approve or deny — deciding a request always requires technician approval The AutoElevate API tool gives Neo agents direct access to the CyberFOX AutoElevate Partner API. An agent finds the elevation request behind a ticket, reads the evidence it should be judged on, and resolves the "I need admin rights to install this" workflow without opening the AutoElevate portal. <Info> Automatically enabled when you configure AutoElevate permissions in your agent workflow. </Info> ## What It Does * Find the pending elevation request behind a ticket, scoped to the client on it * Read the elevation event that carries the decision detail: file name and path, size, both hashes, digital signature state, publisher, signing certificate and the OS user * Approve or deny a pending request (always behind technician approval) * Look up managed computers with their OS, elevation mode and last check-in * Read the auto-approval and auto-denial rules that may already cover the software * Read just-in-time admin sessions for audits and "who had admin on this machine" questions * Enumerate companies and locations to scope a call to a specific client ## The decision detail is on the event, not the request An AutoElevate elevation *request* carries only its id, the computer, its approval state and a timestamp. Its `requestedBy` and `targetDescription` fields are usually empty. On the first live account they were empty on all 107 records, including the pending one. Everything a technician judges on lives on the matching **elevation event**, which the agent finds by matching the computer and the timestamp. The agent's skill tells it to do this, so a well-formed AutoElevate summary names the file, its path, its publisher and whether it was signed. Neo drops five display-only paths from every event before the agent sees them: the base64 application icon (on the trigger and again on any rule that matched), the signer's raw public key, and the two RDN lists that restate the certificate's own issuer and subject. They were 62% of the payload and no decision reads them. ## Permission Groups | Permission Group | What It Covers | | - | - | | **Elevation Requests** | Pending and historic elevation requests, and deciding them | | **Elevation Events** | File, path, hashes, signature, publisher and user behind a request | | **Elevated Sessions** | Just-in-time admin sessions | | **Elevation Rules** | Auto-approval and auto-denial rules and their scope | | **Computers** | Managed machines, OS, elevation mode, last check-in | | **Companies & Locations** | The client hierarchy every other call scopes to | | **Account & Audit** | Partner usage figures and the admin audit log | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. Only Elevation Requests offers Read/Write. AutoElevate's Partner API has fourteen read routes and two write routes, and both writes are on elevation requests, so every other group is read-only by API design. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. The agent can find a request, read its evidence and report, but never decides one. </Accordion> <Accordion title="Helpdesk"> Elevation Requests at Read/Write (still requires technician approval on every decision). Everything else Read Only — enough to work the elevation ticket end to end with a technician signing the decision. </Accordion> </AccordionGroup> There is no Full Automation profile. The only write this API has is the one that can never go through unattended. ## Safety Controls | Control | Behavior | | - | - | | **Elevation decision protection** | Approving or denying a request always requires technician approval, regardless of settings | | **Decisions are final** | Once a request leaves `PENDING`, AutoElevate refuses any further decision on it with a `409`. There is no un-approve endpoint | | **Rule creation is not automatic** | Approve and deny can also create an auto-approval or auto-denial rule, and at account scope that decides every future matching elevation across every client. The agent is instructed to leave it off unless a technician asked for it, and the technician sees it in the approval either way | | **Read-only areas** | Every group but Elevation Requests has no write endpoint, so there is nothing to approve or restrict there | | **Authentication is Neo's** | The API key and AutoElevate's required beta header are set by Neo on every call. The agent cannot set, replace or read either | | **Rate limit** | 100 requests per hour per operation during beta. Neo throttles its own calls to stay inside it, so a saturated operation fails the agent's call instead of rate-limiting your account | ## How to Configure <Steps> <Step title="Connect AutoElevate"> Save your AutoElevate API key in the Neo Dashboard under the **Security** integrations category. Create it on a service user with the **API Token (AE-BEARER)** scheme; the HMAC scheme cannot be used. See [Connecting AutoElevate to Neo](/integrations/autoelevate/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> <Step title="Decide whether the agent may act"> Leave Elevation Requests at Read Only for an agent that should only gather and report. Set it to Read/Write for one that should propose a decision. A technician still approves every one. </Step> </Steps> <Tip> Start with **Read Only**. An agent that reliably names the file, the path, the publisher and the signing state in its summary has already removed most of the work from the elevation queue, before it decides anything. </Tip> # BeyondTrust EPM API Source: https://docs.neoagent.io/agents/tools/security/beyondtrust-epm-api Find the JIT request, computer and group behind a BeyondTrust EPM elevation email and move the ticket to the right client; read and manage computers, groups, policies and console users The BeyondTrust EPM API tool gives Neo agents access to the BeyondTrust Endpoint Privilege Management for Windows and Mac (EPM-WM) Management API. The common use is the elevation email: BeyondTrust emails your PSA when a user asks to run an application with admin rights, and the ticket lands on the wrong client. The agent finds the request, its computer and the computer's group, and moves the ticket to the client the computer belongs to. <Info> Automatically enabled when you configure BeyondTrust EPM permissions in your agent workflow. </Info> ## What It Does * Find the JIT application access request from the ticket number in the email title (`EPM000123`) * Read the request's user, computer, application, publisher, reason and decision * Read the computer's group, domain, policy and last connection * Find the client: from the group's company mapping, from the RMM device with the same name, or from the computer's domain * Read JIT admin access requests, policies and their application groups, console users and roles, activity audits and endpoint events * Authorise, reject, archive and move computers, request their logs, and manage groups and policies ## How the agent handles an elevation email The email names the user and the application, but not the computer or the group. The agent reads the request by its ticket number, then the computer named on the request, then the computer's group. It moves the ticket to the client that group or computer maps to, and adds an internal note with the computer, the group, the user, the product, the publisher and the reason. It never picks a client from the user name alone. If it cannot find exactly one client, it leaves the ticket where it is and writes what it found in an internal note. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | JIT Application Access | Disabled, Read Only, Read / Write | JIT application access requests and their audit trail; the write records an approve or deny decision | | JIT Admin Access | Disabled, Read Only, Read / Write | JIT admin access requests; the writes create or decide one | | Computers | Disabled, Read Only, Read / Write | Computers, their command log and logs; authorise, reject, archive, request logs or status, renew a certificate, deactivate or delete | | Groups | Disabled, Read Only, Read / Write | Computer groups; create, change, move computers, assign or clear a policy, delete | | Policies | Disabled, Read Only, Read / Write | Policies, revisions and Policy Editor application groups; change, discard a draft, add applications, delete | | Console Users and Access | Disabled, Read Only, Read / Write | Console users, roles, accepted domains, the sign-in provider, API accounts and SCIM users | | Activity and Events | Disabled, Read Only | Console activity audits, endpoint events and task status | ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Every write | | **IT Admin** | Computer and group changes | Policy and console-user changes | | **Full Automation** | Every write below | Only the writes below | ## Safety Controls | Control | Behavior | | - | - | | **JIT decisions** | Approving or denying a JIT application request, and creating or deciding an admin access request, always ask a technician. An approval runs the software with admin rights | | **Computer removal** | Deleting or deactivating a computer always asks a technician, because the endpoint leaves protection | | **Policy removal** | Clearing a group's policy, deleting a group and deleting a policy always ask a technician, because computers are left without a privilege policy | | **Computers by id only** | A write that selects computers must name them by id. Neo does not send a selection of every computer (`allComputers`) | | **Refused** | Neo does not download the binary agent-log archive, and does not call the console's internal product switcher | ## How to Configure <Steps> <Step title="Connect BeyondTrust EPM"> Save your EPM API account in the Neo Dashboard under the **Security** integrations category. See [Connecting BeyondTrust EPM to Neo](/integrations/beyondtrust-epm/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> Start with **Read Only**. Moving an elevation ticket to the right client needs only reads in BeyondTrust; the ticket change is made with the PSA tools. </Tip> # CyberQP API Source: https://docs.neoagent.io/agents/tools/security/cyberqp-api Verify end users, manage just-in-time admin accounts and read CyberQP customers, passwords and events from an agent The CyberQP API tool gives Neo agents access to CyberQP (formerly Quickpass), your privileged access platform. The common uses are verifying a caller before a password reset, giving a technician temporary admin rights at a customer for one ticket, and running your RMM's CyberQP install script to deploy the agent. <Info> Automatically enabled when you configure CyberQP permissions in your agent workflow. </Info> ## What It Does * Find a customer in CyberQP, with its agent GUID, and read its user, admin, service and JIT accounts * Send an end user an identity verification push; CyberQP adds the result to the PSA ticket * Create a just-in-time (JIT) admin account under one of your JIT policies, enable it for a duration, disable it, or delete it * Read a customer account's or a JIT account's password and a JIT account's OTP codes, for a technician who asks * Read the agent install token, so your RMM can deploy the CyberQP agent * Read CyberQP's audit events from the last three months Neo never refreshes or revokes CyberQP tokens on request, never downloads the agent installer, and never saves an OTP secret on a JIT account: that secret would sit in the agent's run log. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Customers & Accounts | Disabled, Read Only | Customers and their agent GUIDs, each customer's accounts and their counts, your company data | | Agent Deployment | Disabled, Read Only | Your agent install token. It installs the agent for any of your customers | | Identity Verification | Disabled, Read / Write | Send an end user an identity verification push | | Just-In-Time Accounts | Disabled, Read Only, Read / Write | JIT accounts and policies; create, enable, disable and delete a JIT account | | Passwords & OTP | Disabled, Read Only, Read / Write | Account and JIT account passwords, JIT OTP codes, and removing a JIT account's OTP secret | | Events | Disabled, Read Only, Read / Write | Audit events; record an event on an account | | Profile | What it does | | - | - | | Read Only | Reads customers, accounts, JIT accounts and events. The install token, passwords and identity verification stay off | | Helpdesk | Sends identity verifications on its own. Every JIT account change asks a technician first; events are read-only | | IT Admin | Identity verification, disabling or deleting a JIT account, and events on their own | | Full Automation | Every supported call with no approval, except the calls below | ### Calls that always ask a technician These calls wait for a technician's approval under every profile, whatever you set on the group: * Creating a JIT admin account, and enabling one * Reading a customer account's password, a JIT account's password or a JIT account's OTP codes * Removing a JIT account's OTP secret Each gives a person admin rights at a customer, hands over a live credential, or weakens an account's sign-in, so no setting runs them unattended. The agent sends the approval request with the customer, the account and the ticket. Turn Passwords & OTP on only for agents that hand credentials to your team, such as an internal chat agent. ## Setup See [Connecting CyberQP to Neo](/integrations/cyberqp/connecting-to-neo). # Datto EDR API Source: https://docs.neoagent.io/agents/tools/security/datto-edr-api Investigate Datto AV quarantines and Datto EDR alerts: find the alert, the quarantined file, its reputation and the device; restore a file, respond on a device, manage exclusions The Datto EDR API tool gives Neo agents access to your Datto EDR console, which covers Datto EDR and Datto AV. The common use is a ticket about a Datto AV quarantine or a Datto EDR alert: the agent finds the alert, reads the quarantined file, its reputation and the device, judges whether it is a false positive, and writes its verdict in an internal note. <Info> Automatically enabled when you configure Datto EDR permissions in your agent workflow. </Info> ## What It Does * Find the alert behind a ticket: from the Alert URL of a Datto EDR Autotask ticket, from the device and time of a Datto RMM alert ticket, or from an alert email * Read the quarantine record, the file's reputation (engine detections, signer, threat score), your own file flags and how many devices have the file * Read the device, its policies and its other alerts * List new quarantines since a time, for a scheduled agent * Archive (acknowledge) an alert and add a comment * Restore or delete a quarantined file, isolate a device or restore its network, and run response extensions * Scan devices, locations and organizations; manage devices, device groups, organizations and locations * Read and change exclusions, policies, suppression rules and detection rules ## How the agent handles a quarantine ticket The agent finds the alert id: Datto EDR's own Autotask ticket carries it in the Alert URL field, and an alert email in its link. A ticket from Datto RMM (the path for Halo and ConnectWise, which Datto EDR does not ticket into) carries the hostname and the time, so the agent reads the RMM alert first when it has Datto RMM, then finds the Datto EDR alert by device and time. It reads the quarantine record, the file's reputation and the device, weighs the signer, the engine count, the path and the device's other alerts, and writes what it found in an internal note. ## Permission Groups | Group | Covers | | - | - | | Alerts | Alerts, alert details, the archive, comments and AI assist answers | | Quarantine and Files | Quarantined files, file reputation, file flags, prevalence and Datto AV lab submissions | | Response Actions | Isolation and network restore, response extensions and their results, AV alert actions, ransomware rollback | | Devices | Devices, device groups, applications, licences, scans and scan tasks, network scanners | | Exclusions, Policies and Rules | Datto AV exclusions, policies and their assignment, suppression rules, detection rules | | Organizations and Locations | Organizations (your clients) and locations (their sites) | | Scan Data | Datto EDR scan data (processes, modules, autostarts, connections, accounts) and searches | | Account and Integrations | Console users and roles, tenant settings, PSA and RMM integration set-up, webhooks, reports and notifications | Each group is Disabled, Read Only or Read / Write. ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Every write | | **IT Admin** | Alert archive and comments, scans, searches, lab submission, file retrieval, licence assignment, device and organization and location housekeeping, reports | The writes that always ask (below) | | **Full Automation** | Every write except those below | Only the writes below | ## Safety Controls | Control | Behavior | | - | - | | **Quarantine** | Restoring or deleting a quarantined file, and flagging a file or an application, always ask a technician | | **Response actions** | Isolating a device or restoring its network, killing a process, deleting or quarantining a file, running a command, rebooting and ransomware rollback always ask a technician | | **Exclusions and policies** | Every exclusion, policy, policy assignment, suppression rule and detection rule change always asks a technician | | **Devices** | Uninstalling an agent, removing its licence, approving or denying an agent or a network scanner, and any direct edit of a device record always ask a technician | | **Clients** | Deleting an organization or a location always asks a technician | | **Account** | Every change to users, roles, tenant settings, PSA and RMM integrations and webhooks always asks a technician. Reports and your own notifications follow the access profile | | **Named records** | A bulk action that selects its records with a filter or a list must name them by id, and an isolation or a response must name its device or alert. Neo does not send one that could reach every record | | **Refused** | Neo does not read or create API tokens, agent deploy keys or uninstall tokens, sign in on a user's behalf, write the records Datto EDR keeps itself (endpoint callbacks, device telemetry, the audit log), download or upload files, read secrets in clear, or bulk-delete by filter. Credentials in your PSA and integration set-up are removed from what Neo reads | ## How to Configure <Steps> <Step title="Connect Datto EDR"> Save your console address and API token in the Neo Dashboard under the **Security** integrations category. See [Connecting Datto EDR to Neo](/integrations/datto-edr/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> Start with **Read Only**. Investigating a quarantine needs only reads in Datto EDR; the note on the ticket is written with the PSA tools. </Tip> # Duo API Source: https://docs.neoagent.io/agents/tools/security/duo-api Work Duo MFA tickets: find the user, verify the caller with a Duo Push, clear a lockout, enroll a new starter, offboard a leaver, and read the authentication log The Duo API tool gives Neo agents access to the Duo Admin API, in your own Duo account or in a client's subaccount. The common use is a ticket from a user locked out of Duo: the agent finds the user, reads why they are locked out, verifies the caller with a Duo Push, and sets the user active again. <Info> Automatically enabled when you configure Duo permissions in your agent workflow. </Info> ## What It Does * Find a user by username or email, and read their status, lockout reason, phones, tokens, groups and last sign-in * Send a verification Duo Push to the user's phone and read whether they approved it * Set a locked-out user active again, or set a user to bypass or disabled * Create and enroll a new starter, add a phone, and have Duo send the Duo Mobile activation SMS or the enrollment email * Disable or remove a leaver, and remove their phones, tokens, security keys and bypass codes * Read the authentication, administrator and telephony logs, and which policy applies to a user and an application * Manage groups, blocked devices, policies, applications, administrators and account settings when you allow it ## Client subaccounts With a Duo MSP account, the agent works in a client's subaccount by passing its account id (`account_id`) on the call. Neo looks up that subaccount's own API hostname and sends the call there. Without an account id, the call goes to your own account. Each subaccount is mapped to a client in your PSA, so the agent knows which account id belongs to the ticket's client: see [Duo overview](/integrations/duo/overview#your-subaccounts-are-mapped-to-clients). On a ticket, Neo checks the account id against that mapping before it sends the call. Neo knows your subaccounts from the subaccount list, so this check needs **Grant accounts - Read** on the Duo application. With it, the agent can reach only the subaccount mapped to the ticket's client; Neo refuses any other account id. When the ticket's client has a subaccount, Neo also refuses a call without an account id, because that call would reach your own account. When the ticket's client has no mapped subaccount, the agent can reach no subaccount on that ticket, and on a Duo MSP account it cannot reach your own account either, because your own users are your staff: map the client on the Duo card's **Organization Mapping** tab. Without **Grant accounts - Read**, Neo may not know your subaccounts, and a ticket call without an account id can then reach your own account. Listing or creating subaccounts is refused on a ticket, because the list names every client. A mapping counts once it is a name match or one you confirmed. Runs with no ticket, such as a chat or a scheduled agent with no ticket, are not limited to one client. ## Permission Groups | Group | Covers | | - | - | | Users | Find, create, enroll, change status (active, bypass, disabled; read a lockout and clear it by setting active), send to Trash and restore, delete, and group membership | | Caller Verification | The verification Duo Push and its answer, and Duo identity verification | | Phones and Authenticators | Phones, hardware tokens, security keys and Duo Desktop authenticators: add, attach to a user, re-send the Duo Mobile activation by SMS, resync, remove | | Bypass Codes | List bypass codes, create new codes for a user, delete. Duo never returns an existing code | | Groups | Create, rename, change status, delete, and list members | | Endpoints and Devices | Endpoints Duo has seen and Duo Desktop registered devices: read, remove, block and unblock | | Policies | The global policy and custom policies, which policy applies to a user and application, create, copy, change, delete | | Applications | The applications Duo protects: read, create, change, delete | | Administrators | Duo administrators, roles and administrative units: read, create, change, reset a lockout, delete | | Account Settings | Global account settings, branding, custom messaging and Duo Passport | | Logs and Reports | Authentication, activity, administrator, telephony and offline enrollment logs, Trust Monitor events, and account summary and usage. Read only | | Subaccounts and Billing | List and create client subaccounts, and read or set a subaccount's edition, telephony credits and user limit | Each group is Disabled, Read Only or Read / Write. Logs and Reports is Disabled or Read Only, because Duo has no write there. ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read, and the verification Duo Push | Changes to users, phones, bypass codes and groups. Every other area is read only | | **IT Admin** | Changes to users, phones and groups, and the verification Duo Push | Changes to bypass codes, devices, applications and subaccounts, plus the changes that always ask | | **Full Automation** | Every change except the ones below that always ask | The changes that always ask | Under every profile, a technician approves setting a user or group to bypass, adding a user to a group, creating bypass codes, deleting a phone, hardware token, security key or desktop authenticator, detaching a phone or token from a user, every policy, account setting and administrator change, creating or deleting an application, resetting its secret key or granting it Admin API permissions, and changing a subaccount's edition, telephony credits or user limit. ## Safety Controls | Control | Behavior | | - | - | | **Bypass codes and the bypass status** | Creating bypass codes always asks a technician, under every profile, because a code passes MFA as the user. So does a user or group change that sets the status to bypass, which turns off MFA, the bulk user create included. A change Neo cannot read counts as one that sets bypass. Adding a user to a group always asks too, because the call names only the group, and a group set to bypass turns off the user's MFA | | **Authenticators** | Deleting a phone, a hardware token, a security key or a desktop authenticator, or detaching a phone or token from a user, always asks a technician, because the user loses that second factor | | **Policies and account settings** | Every policy change and every account setting change always asks a technician, because a policy can turn off MFA for the users it covers, and a setting can widen who may let users skip MFA | | **Administrators** | Every change to an administrator, a role, an administrative unit or an activation link always asks a technician | | **Applications** | Creating or deleting a Duo-protected application, resetting its secret key, or granting an application an Admin API permission always asks a technician, because that permission widens what the application's key may do in your Duo account | | **Billing** | Changing a subaccount's edition, telephony credits or user limit always asks a technician, because it costs you money | | **Client scope** | On a ticket, a call reaches only the subaccount mapped to the ticket's client, when the Duo application has **Grant accounts - Read**. See [Client subaccounts](#client-subaccounts) | | **Neo's own application** | Neo does not change, delete or reset the secret key of the Admin API application it is connected with, because that would break its connection to Duo | | **Secrets in answers** | Neo removes an application's secret key and an OAuth or OIDC client secret from every answer, the answer to creating an application included, so the agent and the run log never see them | | **Activation links and enrollment codes** | Neo removes a pending administrator's activation link and the enrollment code of a new user from what the agent reads. Duo emails them to the person instead | | **Refused** | Neo does not delete a subaccount, send Duo's bulk call, read an application's secret key or an OAuth or OIDC client secret, create a phone's Duo Mobile activation link or an administrator's activation link, or download the account logo. The agent has Duo send the activation SMS or email instead | ## How to Configure <Steps> <Step title="Connect Duo"> Save your Admin API application's integration key, secret key and API hostname in the Neo Dashboard under the **Security** integrations category. See [Connecting Duo to Neo](/integrations/duo/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> For lockout tickets, **Helpdesk** fits: the agent verifies the caller on its own, and a technician approves the change to the user. </Tip> # Hornetsecurity API Source: https://docs.neoagent.io/agents/tools/security/hornetsecurity-api Search a client's email in Hornetsecurity 365 Total Protection, release held email, and allow or deny senders — each area follows the approval setting you give it The Hornetsecurity API tool gives Neo agents access to the Hornetsecurity Control Panel API, which also serves Proofpoint 365 Total Protection. An agent finds the email behind a "my email never arrived" ticket, releases it to the user, and allows the sender when the ticket asks. <Info> Automatically enabled when you configure Hornetsecurity permissions in your agent workflow. </Info> ## What It Does * Find the client from the [Organization Mapping](/integrations/hornetsecurity/overview#your-clients-are-mapped-automatically), or by its domain * Search the client's email log by user, sender, subject and date, and read one email's detail and header * Release a held email to its recipient, or release it and allow the sender in one step * Add or remove allow and deny list entries for a client or one user * Look up mailboxes, aliases and protected domains ## How the agent releases an email The agent searches the client's email log for the email the ticket describes. If more than one email could match, it lists them and asks. It checks the result of every release, because Hornetsecurity reports success per email. When it releases an email classified as a threat, it names the classification on the ticket. ## Permission Groups | Group | Access levels | Always waits on a technician | | - | - | - | | Emails | Disabled, Read Only | — | | Quarantine Actions | Disabled, Read Only, Read and Write | — | | Allow & Deny Lists | Disabled, Read Only, Read and Write | — | | Customers | Disabled, Read Only | — | | Mailboxes | Disabled, Read Only | — | | Domains | Disabled, Read Only | — | No operation always waits on a technician: each group follows the approval setting you give it, and the Helpdesk profile asks for approval on every quarantine action and list edit. ## Setup See [Connecting Hornetsecurity to Neo](/integrations/hornetsecurity/connecting-to-neo). # Huntress API Source: https://docs.neoagent.io/agents/tools/security/huntress-api Investigate and resolve Huntress incidents, read agents and detections, and manage access rules — host isolation, incident resolution, and portal access changes always require technician approval The Huntress API tool gives Neo agents direct access to the Huntress Platform API — read the incident behind a Huntress-generated ticket, gather the evidence, approve the remediation, isolate a compromised host, and file the travel exception that stops an escalation recurring. <Info> Automatically enabled when you configure Huntress permissions in your agent workflow. No manual toggle needed. </Info> <Tip> Agents load the Huntress API skill first, which carries the endpoint table, request-body shapes, and the ordering rule that matters most: **every remediation must be approved before an incident can be resolved.** </Tip> ## What It Does * Pull the incident report behind a Huntress ticket — findings, indicators, severity, affected host * Approve or reject the report's remediations, then resolve the incident or escalation * Look up any deployed host, edit its tags and tamper protection, isolate it or release it, or uninstall its Huntress agent (offboarding, or before a reinstall) * Investigate signals, managed identities and their MFA/risk state, exposed ports, and SIEM logs * Create time-boxed travel/geolocation exceptions that expire on their own, plus VPN and IP rules * Enumerate, create, rename, or remove customer organizations * Read who has portal access, invite users, change permission levels, revoke access * Read summary reports for QBRs and invoices for billing reconciliation ## Permission Groups | Permission Group | What It Covers | | - | - | | **Incidents** | Incident reports, their remediations, and escalations — including resolution | | **Agents** | Deployed hosts: details, tags, tamper protection, isolation, removal | | **Detections** | Signals, identities, external ports, platform actions, known VPNs, SIEM queries — **read-only by API design** | | **Unwanted Access Rules** | Travel/geolocation, VPN, and IP access rules | | **Organizations** | Customer organizations and accounts — the scope every other call uses | | **Users** | Portal memberships and permission levels | | **Reporting & Billing** | Summary reports and invoices — **read-only** | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. Detections and Reporting & Billing only ever offer Read Only — Huntress has no write endpoint for them. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. The agent can investigate any alert, host, identity, or report but never changes anything. </Accordion> <Accordion title="Helpdesk"> Incidents at Read/Write (still requires technician approval on every write). Everything else Read Only — enough to work an alert to resolution without touching hosts, access rules, organizations, or users. </Accordion> <Accordion title="IT Admin"> Every writable group at Read/Write, with technician approval required on all writes — not just the mandatorily-forced ones. The cautious rollout tier. </Accordion> <Accordion title="Full Automation"> Unwanted access rules and organization changes run autonomously. Host isolation and removal, remediation approval, incident resolution, and portal access changes still always require technician approval. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes — configurable per group | | **Agents protection** | Isolating, releasing, or removing a host always requires technician approval, regardless of settings | | **Incidents protection** | Approving or rejecting remediations and resolving an incident or escalation always require technician approval — approval executes assisted remediations on the endpoint immediately | | **Users protection** | Inviting, changing, or removing portal access always requires technician approval | | **Read-only areas** | Detections and Reporting & Billing have no write endpoint | | **Subscriptions excluded** | Huntress's reseller subscription endpoints are deliberately not exposed to agents — Reporting & Billing is for reconciliation, not buying | <Note> Host isolation is asynchronous. A successful call returns the host as "Pending Isolation", not isolated — the agent is instructed not to report a host as contained until Huntress confirms it. </Note> ## How to Configure <Steps> <Step title="Connect Huntress"> Save your Huntress API key pair in the Neo Dashboard under the **Security** integrations category. See [Connecting Huntress to Neo](/integrations/huntress/connecting-to-neo). <Warning> The default Huntress **account** API key is read-only. Writes need a user-based key whose Huntress user holds the matching portal permission. </Warning> </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Agents, Incidents, and Users always require technician approval on writes; decide whether access rules and organizations should too. </Step> </Steps> <Tip> Start with **Read Only** or **Helpdesk**. Because containment and remediation approval are permanently gated, most of the value — the alert context arriving with the ticket — is available before you grant any write access at all. </Tip> # Mimecast API Source: https://docs.neoagent.io/agents/tools/security/mimecast-api Find a reported or held email in Mimecast, judge it from Mimecast's own scan results, release or reject held mail, block senders and URLs, and remove a malicious email from every mailbox The Mimecast API tool gives Neo agents access to Mimecast API 2.0 for each client you manage in Mimecast. The common uses are a reported phishing email, where the agent finds the message, reads Mimecast's verdicts and writes the evidence in an internal note, and a wanted email that Mimecast held. <Info> Automatically enabled when you configure Mimecast permissions in your agent workflow. </Info> ## What It Does * Pick the client's Mimecast account from the company link, or by name and mail domain * Find a message by sender, recipient, subject, link or Message-ID, and read its delivery, spam and policy verdicts and its attachments' scan results * Read who clicked the links and what URL Protect decided, the attachment sandbox result, impersonation hits, the real target of a rewritten link, and whether the account has seen a file hash * Read the held queue and the hold reason; release or reject a held email * Block a sender for a recipient, block a URL for the whole account, and permit them * Read and change policies: blocked senders, anti-spoofing and its bypass, greylisting, delivery routes, DNS authentication * Remove a malicious email from every mailbox it reached * Read and manage users, profile groups, domains, connectors, directory sync and DMARC Analyzer * Read awareness training results and human risk scores (read-only) ## How the agent handles a phishing ticket The agent finds the account for the ticket's company, searches Message Finder for the reported email, and reads its detail. It checks the link clicks, the attachment sandbox result and impersonation hits, decodes any rewritten Mimecast link in the ticket, and searches the account for the attachment's hash. It writes the evidence and its verdict in an internal note. A block or a remediation follows your permissions below. Message Finder and the held queue answer for Cloud Gateway clients (mail routed through Mimecast). For a Cloud Integrated client, when the agent also has Microsoft Graph access, it reads the reported message through Graph; without it, the agent has Mimecast's SIEM events only. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Messages & Tracking | Disabled, Read Only, Read / Write | Message Finder, the archive, rejections, queues and the audit log; send an email from the account, tag archived messages | | Threat Intelligence | Disabled, Read Only | Threat events, URL, attachment and impersonation protection logs, decoded links, hash search, the threat feed, SIEM events, reported emails | | Held Messages | Disabled, Read Only, Read / Write | The held queue and its release log; release or reject a held email | | Sender & URL Lists | Disabled, Read Only, Read / Write | Managed senders, managed URLs and Web Security block and allow lists | | Policies | Disabled, Read Only, Read / Write | Gateway and Cloud Integrated policies | | Remediation | Disabled, Read Only, Read / Write | Remediation incidents, removing an email from every mailbox, your own threat-intelligence block lists | | Users & Groups | Disabled, Read Only, Read / Write | Internal users, aliases, delegates, profile groups and members, roles | | Account & Domains | Disabled, Read Only, Read / Write | The account and your managed clients, domains, connectors, journaling, directory sync, configuration snapshots | | DMARC Analyzer | Disabled, Read Only, Read / Write | DMARC Analyzer domains, sources, reports, DNS checks and tasks | | Awareness & Human Risk | Disabled, Read Only | Awareness training results and human risk scores | ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Rejecting held email, blocking senders and URLs, and removing list entries | | **IT Admin** | Rejecting held email, blocks, users, groups, remediation block lists, DMARC Analyzer | Policies and account changes | | **Full Automation** | Every write except those below | Only the writes below | ## Safety Controls | Control | Behavior | | - | - | | **Releases** | Releasing a held email always asks a technician | | **Permits** | Permitting a sender or a URL, and every Web Security list change, always asks a technician. A block follows the access profile | | **Policies** | Every policy create, change or delete, the protection mode and a configuration restore always ask a technician | | **Remediation** | Removing an email from every mailbox always asks a technician | | **Sending email** | Sending an email from the client's Mimecast account always asks a technician | | **Right account** | With a partner credential, every call names the client's account; Neo refuses a call that would reach your own Mimecast account instead | | **Refused** | Neo does not delete or disable its own Mimecast API application, remove a client's directory sync, purge archived mail, fetch download links to messages or attachments, or register webhooks | ## How to Configure <Steps> <Step title="Connect Mimecast"> Save your Mimecast API 2.0 credential in the Neo Dashboard under the **Security** integrations category. See [Connecting Mimecast to Neo](/integrations/mimecast/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> Start with **Read Only**. Judging a reported email needs only reads in Mimecast; the note on the ticket is written with the PSA tools. </Tip> # Proofpoint Essentials API Source: https://docs.neoagent.io/agents/tools/security/proofpoint-essentials-api Add senders to Proofpoint Essentials safe and block lists, and manage users, domains and organization settings — the API cannot release quarantined email The Proofpoint Essentials API tool gives Neo agents direct access to the Proofpoint Essentials REST API. An agent finds the client organization behind a ticket and adds the sender to the right safe list, so the sender's next email is not held. <Info> Automatically enabled when you configure Proofpoint Essentials permissions in your agent workflow. </Info> ## What It Does * Find the client organization from the [Organization Mapping](/integrations/proofpoint-essentials/overview#your-clients-are-mapped-automatically), the requester's email domain, or the list of organizations under your partner account * Read and add to safe and block lists, for a whole organization, one user or one group * Look up, create and update users and aliases * Check a domain's mail routing health, verify domains and manage DKIM keys * Read and change filtering features, external-sender tagging and Azure AD user sync * Read licence counts and mail flow statistics ## What It Cannot Do Neo sends only the operations in Proofpoint's published Essentials API document, and that document has no quarantine endpoint. An agent cannot search for, read or release a held message. When a ticket asks for a release, the agent adds the sender if it may, and says that the held message must be released from the user's quarantine digest email or in the Proofpoint Essentials console. ## How the agent adds a safe sender The agent picks the narrowest entry that meets the request: the exact address rather than the whole domain, and the one user rather than the whole organization, unless the ticket or your custom instructions say otherwise. It never allows a whole public mail domain such as `gmail.com`. Neo reads the list before and after every addition and restores any earlier entry the change removed. If an entry cannot be restored, the agent reports the list as it was, so a technician can restore it in the Proofpoint console. The agent never clears a list to remove one entry. ## Permission Groups | Group | Access levels | Always waits on a technician | | - | - | - | | Sender Lists | Disabled, Read Only, Read and Write | — | | Users | Disabled, Read Only, Read and Write | Granting impersonation rights | | Organizations | Disabled, Read Only, Read and Write | Deleting a client organization; creating a console login token | | Domains | Disabled, Read Only, Read and Write | Deleting a domain | | Organization Settings | Disabled, Read Only, Read and Write | — | | Login & SSO | Disabled, Read Only, Read and Write | — | | Licensing & Products | Disabled, Read Only, Read and Write | — | | Reporting & Billing | Disabled, Read Only | — | Every other write follows the approval setting you give its group. ## Setup See [Connecting Proofpoint Essentials to Neo](/integrations/proofpoint-essentials/connecting-to-neo). # RoboShadow API Source: https://docs.neoagent.io/agents/tools/security/roboshadow-api Read RoboShadow CVE and missing-update reports, the fix for each CVE and remediation attempts, so an agent can patch vulnerable devices through your RMM The RoboShadow API tool gives Neo agents read access to RoboShadow, the vulnerability management and endpoint security platform. The common use is a request like "analyse the missing CVEs for Contoso and remediate them": the agent reads the client's CVE report, the fix for each CVE, the affected devices and RoboShadow's own remediation attempts, then updates the devices with your RMM tools. <Info> Automatically enabled when you configure RoboShadow permissions in your agent workflow. </Info> ## What It Does * Read the organisations your RoboShadow login reaches * Read devices with their health scores, CVE counts and missing-update counts, and each device's installed applications, services, disks and hardware * Read the CVE, CPE and vulnerable-application reports, with CVSS, EPSS and the known-exploited flag, and the fixes RoboShadow lists for each CVE * Read missing Windows updates per device, and RoboShadow's remediation attempts with the CVEs each one addressed * Read antivirus, ransomware protection, detected threats, Windows Defender and firewall status * Read the users on each device and the Microsoft 365 MFA report * Read external vulnerability scans and what each scanned IP address exposes Neo reads RoboShadow and changes nothing there. To fix what it finds, the agent uses the RMM tools you give it, under their own approval rules, and reports what it changed. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Organisations, Devices and Inventory | Disabled, Read Only | Organisations, devices, installed applications, services, disks, shares and hardware | | Vulnerabilities and Updates | Disabled, Read Only | CVE, CPE and vulnerable-application reports, fixes per CVE, missing Windows updates and remediation attempts | | Antivirus and Firewall | Disabled, Read Only | Antivirus and ransomware protection, threats, Windows Defender settings and firewall profiles | | Users and MFA | Disabled, Read Only | RoboShadow users of an organisation, users and profiles on each device, and the Microsoft MFA report | | External Scans | Disabled, Read Only | External vulnerability scans, their status and the vulnerabilities found per IP address and web target | Every group is read only. Device rows in the other groups still name the logged-on user and carry IP and MAC addresses and serial numbers. ## Setup See [Connecting RoboShadow to Neo](/integrations/roboshadow/connecting-to-neo). # SaaS Alerts API Source: https://docs.neoagent.io/agents/tools/security/saas-alerts-api Investigate SaaS Alerts alert tickets: find the event, the user's other activity, the account and the client; manage suppressions, approved locations and Respond actions The SaaS Alerts API tool gives Neo agents access to the SaaS Alerts Reports, Manage and Respond APIs. The common use is the alert ticket that SaaS Alerts writes in your PSA: the agent reads the event behind it, the user's other activity, the account and the client, and writes its verdict in an internal note. <Info> Automatically enabled when you configure SaaS Alerts permissions in your agent workflow. </Info> ## What It Does * Find the event behind a SaaS Alerts ticket from its `Event ID`, with its severity, IP, location and operation * Read the user's other events around the alert, and count how often the event type fires for the client * Read the user's account (enabled or not, admin role) and the client's SaaS Alerts customer record and approved locations * Read pending Respond rule triggers and the recommended actions * Create, change or delete suppressions for one client or for named users of one client * Set the approved countries, IP ranges and ASNs of a client or of named users, so activity from there stops raising alerts * Run Respond actions on Microsoft 365 accounts (block sign-in, expire sessions, reset or force a password change, set up MFA, delete the user), and approve, reject, ignore or manually remediate a rule trigger * Manage Respond rules, application connections, Unify devices, PSA mapping and scheduled reports ## How the agent handles an alert ticket SaaS Alerts writes the ticket on the PSA company it maps to the SaaS Alerts customer. The body carries the `Event ID`, the user, the severity and a link with the SaaS Alerts customer id. The agent looks up the event by its id, reads the same user's events over a wider window, and checks whether the account is enabled and holds an admin role. It weighs the severity, the IP threat flags, the history and the recommended action, and writes what it found in an internal note. An alert on an anonymous SharePoint link (`urn:spo:tenantanon#...`) names no person, so the agent checks no account. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Events and Alerts | Disabled, Read Only | Events, event search and counts, recommended actions, MFA and mailbox-rule reports | | Customers and Users | Disabled, Read Only, Read / Write | SaaS Alerts customers, their users, the partner profile and billing; create, update or delete a customer | | Approved Locations | Disabled, Read Only, Read / Write | Set the approved countries, IP ranges and ASNs for a client or for named users. The current lists are read from the customer record, which needs Customers and Users read access | | Suppressions | Disabled, Read Only, Read / Write | Suppression rules; create, change or delete one | | Respond Rules | Disabled, Read Only, Read / Write | Respond rules, rule templates, IOC rules and the Respond on/off state | | Respond Triggers and Actions | Disabled, Read Only, Read / Write | Rule triggers and response-action jobs; trigger decisions and response actions | | Connections and Devices | Disabled, Read Only, Read / Write | Respond organizations and application connections, Unify devices | | PSA Mapping | Disabled, Read Only, Read / Write | The SaaS Alerts customer to PSA company mapping | | Reports | Disabled, Read Only, Read / Write | Scheduled reports, report emails, report branding and uploaded report files | ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Every write | | **IT Admin** | Ignoring a rule trigger, customer changes, connections, devices and reports | Suppressions, approved locations, Respond rules and PSA mapping | | **Full Automation** | Every write except those below | Only the writes below | ## Safety Controls | Control | Behavior | | - | - | | **Response actions** | Every Respond action on a Microsoft 365 account always asks a technician | | **Trigger decisions** | Approving, rejecting or manually remediating a rule trigger always asks a technician. Ignoring one follows the access profile | | **Removals** | Deleting a customer, deleting an application connection and turning Respond off always ask a technician | | **Suppression scope** | A suppression covers one client (customer scope) or named users of one client (users scope). Neo does not send a partner-scope suppression, which would cover every client | | **Named accounts** | A response action must name each account it acts on | | **Own events only** | An event search never names an Elasticsearch index, so it reads only your own SaaS Alerts events | | **Refused** | Neo does not read or reset the partner API key, upload files, request a Respond access token, or call the event webhook services, which take a separate Webhooks API key | ## How to Configure <Steps> <Step title="Connect SaaS Alerts"> Save your partner API key in the Neo Dashboard under the **Security** integrations category. See [Connecting SaaS Alerts to Neo](/integrations/saas-alerts/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> Start with **Read Only**. Investigating an alert needs only reads in SaaS Alerts; the note on the ticket is written with the PSA tools. </Tip> # SentinelOne API Source: https://docs.neoagent.io/agents/tools/security/sentinelone-api Triage and close SentinelOne threats and alerts, investigate endpoints, and respond — mitigate, isolate, exclude and run scripts, with approvals you set per agent The SentinelOne API tool gives Neo agents direct access to the SentinelOne Management API (v2.1). An agent can read the threat behind a ticket, check the endpoint and its timeline, record the verdict, and close the threat in the console. It can also mitigate the threat or isolate the endpoint, on its own or after a technician approves, as you set it. <Info> Automatically enabled when you configure SentinelOne permissions in your agent workflow. No manual toggle needed. </Info> <Tip> Agents load the SentinelOne API skill first. The skill carries the site scoping rule, the `filter` and `data` body shape, and the endpoint tables for threats, alerts, endpoints and response actions. </Tip> ## What It Does * Read the threat behind a SentinelOne ticket: classification, confidence, file, hashes, storyline, and whether it is already mitigated * Read its timeline, notes and storyline events, and the endpoint's current status * Set the analyst verdict and incident status, add notes, and write the PSA ticket number on the threat * Read and update STAR alerts, and read unified alerts through Unified Alert Management * Find endpoints by name, user, IP or status; run and stop scans; collect logs and files; tag endpoints * Mitigate threats, isolate or reconnect endpoints, reboot or shut down * Read and change exclusions and the hash blocklist * Run Deep Visibility and PowerQuery event searches, and read the console activity log * Run a library script on named endpoints ## Permission Groups | Permission Group | What It Covers | | - | - | | **Threats & Alerts** | Threats, STAR alerts and unified alerts: verdicts, incident status, notes, ticket number, mitigation | | **Endpoints** | Agents, installed applications and vulnerabilities, scans, log and file collection, endpoint actions | | **Exclusions & Blocklist** | Exclusions, the hash blocklist, threat-intelligence IOCs | | **Deep Visibility & Activities** | Event searches, the activity log, hash verdicts: **read-only** | | **Remote Scripts** | The script library, script runs and results | | **Accounts, Sites & Groups** | The client hierarchy every other call scopes to | | **Users & Roles** | Console users, service users and roles: **read-only** | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write**. ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. The agent investigates any threat or endpoint and reports, but never changes anything. </Accordion> <Accordion title="Helpdesk"> Threats & Alerts and Endpoints at Read/Write, everything else Read Only. The agent triages, mitigates and closes threats on its own. Endpoint actions, such as a scan, isolation or a reboot, require technician approval. </Accordion> <Accordion title="IT Admin"> Every writable group at Read/Write. The agent mitigates, isolates, reboots, runs scripts and manages sites and groups autonomously. Exclusion and blocklist changes require technician approval. </Accordion> <Accordion title="Full Automation"> Every supported write runs autonomously. Only uninstalling, decommissioning or disabling the SentinelOne agent, and Unified Alert Management changes, require technician approval. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes, configurable per group | | **Agent removal** | Uninstalling, approving an uninstall, decommissioning or disabling the SentinelOne agent always requires technician approval, because it removes the client's protection | | **Unified alert changes** | Every Unified Alert Management GraphQL mutation always requires technician approval, because Neo cannot tell from the request what a mutation does | | **Named targets only** | A threat, alert or endpoint action must list the ids it acts on; an empty filter, which SentinelOne applies to everything in scope, is refused | | **Write allowlist** | Every write must match Neo's explicit list of supported SentinelOne writes, and any other is refused. Policy changes, site deletion, user and token management, remote shell and other console administration are not on the list | | **Secrets** | Registration tokens, agent passphrases and the uninstall password are never read, and registration tokens are removed from site and group records | <Note> Network isolation is asynchronous. After the call, the endpoint shows `disconnecting` and then `disconnected`. The agent is instructed to report an endpoint as isolated only after SentinelOne confirms it. </Note> ## How to Configure <Steps> <Step title="Connect SentinelOne"> Save your console URL and a service-user API token in the Neo Dashboard under the **Security** integrations category. See [Connecting SentinelOne to Neo](/integrations/sentinelone/connecting-to-neo). <Warning> The service user's role limits what any agent can do: each API operation needs its own permission. Other MSP tools ask for **Viewer** to read, and for **SOC** or **IR Team** to set verdicts and respond to threats. </Warning> </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Decide per permission group whether writes need a technician. Removing or disabling the SentinelOne agent always does. </Step> </Steps> <Tip> Start with **Read Only** to see the threat context an agent brings to each ticket before it changes anything. **Helpdesk** adds triage, mitigation and closing threats on its own. </Tip> # Sophos API Source: https://docs.neoagent.io/agents/tools/security/sophos-api Check a device in Sophos when your RMM says it is offline, read and act on Sophos alerts, isolate and scan endpoints, manage allow and block lists, and read firewalls, email quarantine, mobile devices and licences, for each Sophos Central tenant you manage A common use is an RMM alert that a device is offline: the agent checks the device in Sophos Central, and when Sophos still sees it online, it writes that only the RMM agent stopped. <Info> Automatically enabled when you configure Sophos permissions in your agent workflow. </Info> ## What It Does * Pick the client's Sophos Central tenant from the tenants you manage * Find a computer or server and read whether it is online, when it was last seen, its health, IP and MAC addresses, user and isolation state * Read Sophos alerts, XDR detections and MDR cases, and acknowledge, clean or clear an alert * Isolate an endpoint or lift the isolation, scan it, check for updates and collect a forensic log * Read the endpoint installer links, for an RMM script that deploys Sophos * Read and change allowed and blocked items, exclusions and endpoint policies * Run Live Discover and XDR queries * Read Sophos Firewalls: connection, firmware and groups; upgrade firmware and manage MDR threat feed indicators * Search Sophos Email quarantine, release or delete a message, and claw back a delivered one * Find a Sophos Mobile device and sync, locate, lock or scan it * Read DNS Protection, web filtering and switch and Wi-Fi settings * Read the directory, admins and roles, your tenants, licences, usage and the account health check ## How the agent checks an RMM offline alert The agent finds the tenant for the ticket's company, then the device by its host name, or by its MAC address when no device has that exact name or two share it. When Sophos shows the device online now, the agent writes that the device is up and only the RMM agent stopped. When Sophos does not see it either, the agent writes when Sophos last saw it. What happens to the ticket next follows your instructions. ## Permission Groups | Group | Access levels | Covers | | - | - | - | | Endpoints | Disabled, Read Only, Read / Write | Computers and servers, isolation, scans, groups, tags, Tamper Protection, forensic logs | | Endpoint Policies and Settings | Disabled, Read Only, Read / Write | Endpoint policies and global settings, cloud workload profiles | | Allowed and Blocked Items, Exclusions | Disabled, Read Only, Read / Write | Allowed and blocked items and addresses, exclusions, local website categories | | Alerts, Detections and Cases | Disabled, Read Only, Read / Write | Alerts and alert actions, detections, MDR cases, the SIEM feed | | Live Discover and XDR Query | Disabled, Read Only, Read / Write | Queries on live devices and the XDR data lake | | Firewalls | Disabled, Read Only, Read / Write | Sophos Firewalls, groups, firmware, MDR threat feed | | Email Security | Disabled, Read Only, Read / Write | Quarantine, clawback, protected mailboxes, S/MIME | | Mobile Devices | Disabled, Read Only, Read / Write | Sophos Mobile devices, groups, apps, policies and actions | | DNS Protection, Web Filtering, Switches and Wi-Fi | Disabled, Read Only, Read / Write | DNS Protection, web filtering profiles and site lists, MAC filtering | | Directory Users and Groups | Disabled, Read Only, Read / Write | The tenant's Sophos users and user groups | | Admins, Roles and API Tokens | Disabled, Read Only, Read / Write | Admins and roles at every level, account access tokens | | Tenants, Licences and Account Health | Disabled, Read Only, Read / Write | Your tenants, licences and usage, the account health check, the audit log | ## Access Profiles | Profile | What runs on its own | What asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Every write | | **IT Admin** | Isolating and scanning endpoints, alert actions, email releases and clawback, mobile actions, directory changes | Policies, block lists, filtering lists, admins and account changes, and every write under Safety Controls | | **Full Automation** | Every write except those below | Only the writes below | ## Safety Controls | Control | Behavior | | - | - | | **Endpoints** | Lifting an isolation, deleting an endpoint, turning Adaptive Attack Protection off, turning Tamper Protection off and regenerating its password always ask a technician | | **Allow lists and exclusions** | Every change to an allowed item, an exclusion (scanning, intrusion prevention, isolation, TLS decryption), an Exploit Mitigation application or a local site, taking a website category out of TLS decryption, and removing a blocked item or blocked addresses, always ask a technician | | **Endpoint policies** | Changing assigned device software always asks a technician. So does a policy change whose settings turn a protection off, set an allow, exclusion or block list, turn on a monitor-only or skip mode, limit web control to a schedule, pick another web filtering or runtime detection profile, or lower an action or level, and a cloud runtime detection profile that turns a rule off or changes a list other than adding to a block list. Turning a policy off, assigning it or resetting it follows the group, because its devices fall back to the base policy | | **Alerts** | Authorizing a potentially unwanted application always asks a technician | | **Email** | A release that adds the sender to the allow list, removing a mailbox from protection and every S/MIME change always ask a technician | | **Mobile** | A wipe, an unenroll, deleting a device, creating or deleting the Intercept X for Mobile auto-enrollment or rotating its connection code, and a device group change that sets iOS auto-enrollment always ask a technician | | **Firewalls** | Deleting a firewall, removing MDR threat feed indicators, and turning the MDR threat feed off or to log only always ask a technician | | **DNS Protection and web filtering** | Replacing a web filtering profile, a new profile that allows, warns or turns filtering off, and a DNS Protection policy change that allows a category or custom domains, removes a block, turns safe search or custom domains off or picks a category preset always ask a technician | | **Access and billing** | Every admin, role and access token change, and creating or changing a tenant, its products or the default products, always ask a technician | | **Passwords** | Neo removes every password, Tamper Protection passwords included, from what Sophos returns | | **Installer links** | An agent with Endpoints access can read the endpoint installer links, which carry your tenant's installer token, so an RMM script can deploy Sophos | | **Right tenant** | A call names the client's tenant; a tenant your credential does not manage is refused | | **Refused** | Neo does not create an access token, migrate endpoints to another tenant, delete the S/MIME configuration, export or import a firewall configuration or read an export's download link, download quarantined attachments or read their download links, download S/MIME certificate files, or call the distributor-only Business Automation API | ## How to Configure <Steps> <Step title="Connect Sophos"> Save your Sophos Central API credential in the Neo Dashboard under the **Security** integrations category. See [Connecting Sophos to Neo](/integrations/sophos/connecting-to-neo). </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or set each permission group by hand. </Step> </Steps> <Tip> Start with **Read Only**. Checking a device after an RMM offline alert needs only reads in Sophos; the note on the ticket is written with the PSA tools. </Tip> # ThreatLocker API Source: https://docs.neoagent.io/agents/tools/security/threatlocker-api Read and action ThreatLocker computers, applications, approval requests, and policies — approving software and editing policies always require technician approval The ThreatLocker API tool gives Neo agents direct access to the ThreatLocker Portal API — read computers, applications, and policies, and resolve pending software-approval requests (the "app won't run" workflow) during ticket resolution. <Info> Automatically enabled when you configure ThreatLocker permissions in your agent workflow. No manual toggle needed. </Info> ## What It Does * Find the pending approval request behind an "app won't run" ticket, and the computer/application it's for * Approve or deny pending software-approval requests (always behind technician approval) * Look up computers, computer groups, and online status * Look up applications and application files ThreatLocker has observed * View and edit allowlist / Config Manager / network access policies (writes always behind technician approval) * Enumerate ThreatLocker organizations to scope a call to a specific customer ## Permission Groups | Permission Group | What It Covers | | - | - | | **Computers** | Computers, computer groups, online status, maintenance mode | | **Applications** | Applications and application files observed across the fleet | | **Policies** | Application Control / Config Manager policies, network access policies | | **Approval Requests** | Pending Application/Elevation/Storage Control approval requests | | **Organizations** | Organization hierarchy and org scoping — **read-only by API design** | Each group has an access level: **Disabled**, **Read Only**, or **Read/Write** (Organizations only ever offers Read Only — no write endpoint exists for it). ## Access Profiles <AccordionGroup> <Accordion title="Read Only"> All groups Read Only. Agent can look up any resource but cannot modify or act on approval requests. </Accordion> <Accordion title="Helpdesk"> Approval Requests at Read/Write (still requires technician approval on every write). Everything else Read Only — enough to resolve the "app blocked" workflow without touching computers, applications, or policies directly. </Accordion> <Accordion title="IT Admin"> Computers, Applications, Policies, and Approval Requests all at Read/Write — but every write requires technician approval, not just the mandatorily-forced ones. </Accordion> <Accordion title="Full Automation"> Computers and Applications writes run autonomously. Policy edits and approval actions still always require technician approval — that override is never optional. </Accordion> </AccordionGroup> ## Safety Controls | Control | Behavior | | - | - | | **Technician-in-the-Loop** | Require human approval for writes — configurable per group | | **Approval Requests protection** | Approving or denying software always requires technician approval, regardless of settings | | **Policy protection** | Editing allowlist / Config Manager / network access policies always requires technician approval, regardless of settings | | **Read-only areas** | Organizations has no write endpoint — nothing to approve or restrict there | ## How to Configure <Steps> <Step title="Connect ThreatLocker"> Connect your ThreatLocker Portal API credentials in the Neo Dashboard under the **Security** integrations category. </Step> <Step title="Configure permissions"> In your agent workflow's **Integrations** tab, choose an access profile or customize each permission group. </Step> <Step title="Set approval requirements"> Approval Requests and Policies always require technician approval on writes; decide whether Computers/Applications should too. </Step> </Steps> <Tip> Start with **Read Only** or **Helpdesk** and expand once you're confident in the agent's triage — the forced approval on software approvals and policy edits means expanding write access elsewhere is lower-risk than it looks. </Tip> # Wizer API Source: https://docs.neoagent.io/agents/tools/security/wizer-api Manage a client's security awareness training in Wizer: users, groups, course starts and progress reports — each area follows the approval setting you give it An agent with this tool works on a client's training from the ticket, so nobody opens the Wizer admin panel. <Info> Automatically enabled when you configure Wizer permissions in your agent workflow. </Info> ## What It Does * Find the client's Wizer company from the [Organization Mapping](/integrations/wizer/overview#your-clients-are-mapped-automatically), or from your partner customer list * Add users to a client's training, disable, rename, and move them between groups and departments * Start a course for a client, or share your own custom course with them * Read per-user progress for courses, policies, monthly videos and phishing exercises ## How the agent assigns training Wizer assigns a course to a client company, usually to its groups or departments. To put a user on a course, the agent adds the user to the client and to the group or department the course targets. Before it starts a course, it checks that the client does not already run that course. A batch start always names its clients. ## Permission Groups | Group | Access levels | Always waits on a technician | | - | - | - | | Users | Disabled, Read Only, Read and Write | — | | Training Assignments | Disabled, Read Only, Read and Write | — | | Reports | Disabled, Read Only | — | | Customers | Disabled, Read Only | — | No operation always waits on a technician: each group follows the approval setting you give it, and the Helpdesk profile asks for approval on every write. ## Setup See [Connecting Wizer to Neo](/integrations/wizer/connecting-to-neo). # Vendor API Source: https://docs.neoagent.io/agents/tools/vendor-api One tool for every descriptor-backed vendor API — ScalePad, Huntress, ThreatLocker, Ubiquiti UniFi, AutoElevate, Proofpoint Essentials, Hornetsecurity, Mimecast, SentinelOne, Wizer, Uniview, Datto BCDR, BeyondTrust EPM, CIPP, Domotz, SaaS Alerts, Auvik, Cisco Meraki, ConnectWise CPQ, Kaseya Quote Manager, myITprocess, QuoteWerks, Datto EDR, WatchGuard, RoboShadow, Duo, CyberQP, TP-Link Omada, OpenText Secure Cloud, Zabbix, CentralReach, Sophos — selected per call by vendor id and gated by that vendor's permission groups Each call carries an API path, an HTTP method, and — where the endpoint needs them — query parameters, a request body, and headers from the vendor's allowlist. Neo adds the base URL and the authentication, so the agent never handles the credentials, and a header outside the allowlist is rejected. A vendor the agent's permissions do not cover is rejected before any HTTP call. <Info> Automatically enabled when you configure permissions for any of the covered vendors in your agent workflow. No manual toggle needed — and it never appears as a separate tool to configure. </Info> <Tip> The agent's instructions list the vendors your permissions enable, with a line on what each one covers. The endpoint tables, request shapes, and each vendor's quirks live in that vendor's skill, which the agent must load before its first call to the vendor. </Tip> ## What It Does * Calls the vendor's REST API directly — reads and (where permitted) writes * Routes each call through the vendor's own permission groups, exactly as the former per-vendor tools did * Applies the vendor's approval rules: operations a vendor always gates (Huntress host isolation, ThreatLocker software approvals and policy edits, AutoElevate elevation decisions, BeyondTrust EPM JIT request decisions and computer removal, SentinelOne agent uninstall and decommission, CIPP device wipe, retire and deletion, ScalePad ControlMap and Backup Radar writes, Domotz collector and Organization deletion, SaaS Alerts response actions and rule-trigger approve, reject and manual remediation, Datto EDR quarantine restore and delete, response actions, exclusions and policy changes, Mimecast held-mail releases, permits, policy changes, remediations and sending email, WatchGuard FireCloud allow exceptions, policy, VPN, certificate and template changes, disabling global exceptions, deployments, protection uninstalls, security configuration moves, undoing a containment, operator changes, deallocations and orders, Sophos allowed item, exclusion and local site changes, taking a category out of TLS decryption, block removals, turning the MDR threat feed off or to log only, lifting an isolation, turning Adaptive Attack Protection off, policy settings that turn protection off or allow, runtime detection rules turned off, web filtering profiles and DNS Protection policies that allow, endpoint deletes, device software changes, turning Tamper Protection off or regenerating its password, authorizing a PUA, releasing an email with its sender allowed, phone wipes and unenrolls, creating or deleting the Intercept X for Mobile auto-enrollment or rotating its connection code, setting iOS auto-enrollment on a device group, mailbox removals, S/MIME changes, firewall deletes, admin, role and token changes, and tenant and product changes, TP-Link Omada customer and site deletion, backup restores, device forgets, admin, role, SSO and two-factor changes, and writes that set a secret (a password, key, PIN, token or SNMP community), OpenText Secure Cloud admin and role changes, endpoint keycode changes, endpoint uninstalls and deactivations, site suspensions and deactivations, and product cancellations, the Zabbix writes listed under "Changes that always ask a technician" in [Connecting Zabbix](/integrations/zabbix/connecting-to-neo), the Cisco Meraki writes listed under "Changes that always ask a technician" in [Connecting Cisco Meraki](/integrations/meraki/connecting-to-neo), the Duo writes listed under "Safety Controls" in [Duo API](/agents/tools/security/duo-api)) still require technician approval regardless of automation level ## Covered Vendors | Vendor | vendor\_id | Details | | - | - | - | | ScalePad | `scalepad` | Read/write asset-lifecycle, compliance, quoting and backup data across Core, Lifecycle Manager, ControlMap, Quoter, and Backup Radar — gated by your ScalePad permission groups | | Huntress | `huntress` | See [Huntress API](/agents/tools/security/huntress-api) | | ThreatLocker | `threatlocker` | See [ThreatLocker API](/agents/tools/security/threatlocker-api) | | Ubiquiti UniFi | `unifi` | See [UniFi API](/agents/tools/networking/unifi-api) | | AutoElevate | `autoelevate` | See [AutoElevate API](/agents/tools/security/autoelevate-api) | | Pax8 | `pax8` | Pax8 companies and contacts, catalogue and prices, subscriptions, orders for a product a client does not hold yet, invoices and usage. See [Pax8](/integrations/marketplaces/pax8) | | TD SYNNEX ION | `td_synnex` | StreamOne ION customers, catalogue and prices, subscriptions, orders, carts and reports. See [TD SYNNEX ION](/integrations/marketplaces/td-synnex) | | TD SYNNEX Stellr | `td_synnex_stellr` | StreamOne Stellr customers, catalogue and prices, subscriptions, provisioning operations and invoices. See [TD SYNNEX Stellr](/integrations/marketplaces/td-synnex-stellr) | | Proofpoint Essentials | `proofpoint_essentials` | See [Proofpoint Essentials API](/agents/tools/security/proofpoint-essentials-api) | | Hornetsecurity 365 Total Protection | `hornetsecurity` | See [Hornetsecurity API](/agents/tools/security/hornetsecurity-api) | | Mimecast | `mimecast` | See [Mimecast API](/agents/tools/security/mimecast-api) | | SentinelOne | `sentinelone` | See [SentinelOne API](/agents/tools/security/sentinelone-api) | | Wizer | `wizer` | See [Wizer API](/agents/tools/security/wizer-api) | | Uniview Backup | `uniview` | Read-only. See [Uniview API](/agents/tools/backup/uniview-api) | | Datto BCDR | `datto_bcdr` | See [Datto BCDR API](/agents/tools/backup/datto-bcdr-api) | | BeyondTrust EPM | `beyondtrust_epm` | See [BeyondTrust EPM API](/agents/tools/security/beyondtrust-epm-api) | | CIPP | `cipp` | Microsoft 365 tenants managed through your CIPP instance. See [CIPP API](/agents/tools/m365/cipp-api) | | Domotz | `domotz` | See [Domotz API](/agents/tools/networking/domotz-api) | | SaaS Alerts | `saas_alerts` | See [SaaS Alerts API](/agents/tools/security/saas-alerts-api) | | Auvik | `auvik` | See [Auvik API](/agents/tools/networking/auvik-api) | | Cisco Meraki | `meraki` | Organizations, networks and devices: availability, uplinks, VPN, events, switch ports, Wi-Fi clients, live tools, licences and firmware, and configuration changes. See [Connecting Cisco Meraki](/integrations/meraki/connecting-to-neo) | | ConnectWise CPQ | `connectwise_cpq` | Quotes with their lines, customer records and terms, templates and CPQ users; drafts a quote from a template. See [ConnectWise CPQ API](/agents/tools/sales/connectwise-cpq-api) | | Kaseya Quote Manager | `kaseya_quote_manager` | Read-only. See [Kaseya Quote Manager API](/agents/tools/sales/kaseya-quote-manager-api) | | myITprocess | `myitprocess` | Read-only. See [myITprocess API](/agents/tools/sales/myitprocess-api) | | QuoteWerks | `quotewerks` | QuoteWerks Web quotes, orders and the other database tables, and saved reports. See [QuoteWerks API](/agents/tools/sales/quotewerks-api) | | Datto EDR | `datto_edr` | Datto EDR and Datto AV. See [Datto EDR API](/agents/tools/security/datto-edr-api) | | WatchGuard | `watchguard` | Firebox, access points, Endpoint Security and ThreatSync in WatchGuard Cloud. See [WatchGuard API](/agents/tools/networking/watchguard-api) | | RoboShadow | `roboshadow` | Read-only. See [RoboShadow API](/agents/tools/security/roboshadow-api) | | Duo | `duo` | Duo MFA in your own account or a client subaccount. See [Duo API](/agents/tools/security/duo-api) | | CyberQP | `cyberqp` | Customers and agent GUIDs, identity verification, just-in-time admin accounts, passwords, OTP codes and events. See [CyberQP API](/agents/tools/security/cyberqp-api) | | Sophos | `sophos` | Endpoints, alerts, allow and block lists, firewalls, email quarantine and mobile in Sophos Central, per tenant. See [Sophos API](/agents/tools/security/sophos-api) | | TP-Link Omada | `omada` | Customers, sites, devices, clients, WiFi, networks, firewall and vouchers on an Omada Cloud-Based Controller, or a Software or hardware controller through Omada cloud access. See [TP-Link Omada API](/agents/tools/networking/omada-api) | | OpenText Secure Cloud | `opentext` | Secure Cloud (formerly AppRiver) customers, users and Microsoft 365 licences, subscriptions and charges, Webroot orders, sites and endpoints. See [OpenText Secure Cloud API](/agents/tools/marketplace/opentext-api) | | Zabbix | `zabbix` | Hosts, problems, latest data and history on your own Zabbix server. See [Zabbix API](/agents/tools/networking/zabbix-api) | | CentralReach | `centralreach` | Employees, contact labels and custom fields, tasks, schedules, files, patient records, billing and payroll in a client's CentralReach practice; connected per client. See [CentralReach API](/agents/tools/management/centralreach-api) | ## Permissions & Billing Each vendor keeps its own permission groups in the agent's settings — enabling one vendor never grants another. On a scheduled or chat agent each call prices by what it did ([Tool credit costs](/agents/tools/credit-costs)), and usage reporting keeps the per-vendor split. # Create an agent Source: https://docs.neoagent.io/api-reference/agents/create-an-agent https://api.neoagent.io/public-api/openapi.json post /public-api/agents Creates an agent/workflow for the caller's tenant. The body is a discriminated union on `autonomy_type` (CHAINED_ACTIONS / AGENTIC / CONVERSATIONAL). The contract is intent-shaped: callers describe `entity_type` + `ticket_conditions` / `time_entry_conditions`, and the server constructs the canonical `actions` array (prepending `FIND_ENTITIES` for CHAINED_ACTIONS / AGENTIC; the trailing `AGENTIC` action for AGENTIC; an empty list for CONVERSATIONAL). For CHAINED_ACTIONS, `actions` is the pipeline AFTER the auto-prepended `FIND_ENTITIES` — including `FIND_ENTITIES` yourself returns 400. AGENTIC agents may be entity-triggered (`trigger_type=TRIGGERED` + `callback_settings`, running against the entity `FIND_ENTITIES` resolves) or scheduled (`trigger_type=SCHEDULED` + `schedule`), which is ticketless — no `FIND_ENTITIES` and no `ticket_conditions`/`time_entry_conditions`. CONVERSATIONAL agents accept `audience` (MSP | END_USER, default MSP) — set END_USER to provision a user-facing chat agent that can bind an END_USER channel; it must then hold only END_USER tools. Audience is set at create and is immutable. They also accept `access` (ALL_USERS | ADMINS_ONLY | SPECIFIC_USERS, default ALL_USERS), controlling which of the MSP's own users may message the agent (set in the dashboard thereafter). `created_by_user` is derived from the authenticated identity — not accepted in the body. Toolboxes that supply external-API credentials are rejected (400 `validation_error`); configure those in the dashboard. Discover the shapes via the `/schemas/*` endpoints. # Delete an agent Source: https://docs.neoagent.io/api-reference/agents/delete-an-agent https://api.neoagent.io/public-api/openapi.json delete /public-api/agents/{agent_id} Soft-deletes the agent (credential cleanup + Temporal schedule teardown + Neo-team notify). Refuses Neo-managed agents with 403 `agent_managed_by_neo`. Refused with 409 `agent_has_dependents` (with `details.dependents`) when other workflows are configured to run when this agent finishes — delete those first. # Get agent execution stats Source: https://docs.neoagent.io/api-reference/agents/get-agent-execution-stats https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id}/stats Aggregate counts and timings for this agent's executions. # Get an agent Source: https://docs.neoagent.io/api-reference/agents/get-an-agent https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id} Returns the full current config of one agent: the summary fields plus the three config layers — `agent_settings`, `toolbox` + `integrations`, and the `actions` pipeline. Some are `None` depending on `autonomy_type` (CHAINED_ACTIONS has no `agent_settings`/`toolbox`/`integrations`; AGENTIC/CONVERSATIONAL configure behaviour through them). For a historical snapshot use `GET /agents/<id>/version-at`. # Get the agent version at a point in time Source: https://docs.neoagent.io/api-reference/agents/get-the-agent-version-at-a-point-in-time https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id}/version-at The agent's configuration as it was at `timestamp=<iso8601>` or at the time the given `execution_id` ran (provide exactly one). Useful for 'what did the agent look like when it processed this ticket'. If no recorded version exists at or before that moment (some workflows are provisioned outside the normal create path and have no `workflows_updates_log` rows), falls back to the live workflow row. # List agent versions Source: https://docs.neoagent.io/api-reference/agents/list-agent-versions https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id}/versions Change history of this agent, reconstructed from `workflows_updates_log`, newest first. Each item is a **lean summary** — identity + lifecycle metadata (name/state/trigger) + `version_timestamp` + `saved_by`, without the config layers. `saved_by.name` is who saved the version, as the dashboard's version history shows it; `saved_by.via` is how it was saved, or `UNKNOWN` for an older or internal save that did not record it. `PUBLIC_API_FOR_PERSON` is an API caller acting for that person: the Neo Support Agent saves this way, under the name of the person in the chat. For the full config at a point in time, call `GET /agents/<id>/version-at?timestamp=<iso>` (or `?execution_id=<run_id>`). # List agents Source: https://docs.neoagent.io/api-reference/agents/list-agents https://api.neoagent.io/public-api/openapi.json get /public-api/agents Agents and workflows for the caller's tenant (the `workflows_v2` table). Cursor-paginated, ordered by id. # List the pinned memories this agent reads Source: https://docs.neoagent.io/api-reference/agents/list-the-pinned-memories-this-agent-reads https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id}/pinned-memories The pinned memories one run of this agent reads beside its custom instructions, chosen as the run chooses them: the memories for the agent's surface (`surface`), minus those limited to other agents. Every run reads the MSP-wide ones; pass `end_company_id` to add the ones a run on that company's ticket or session also reads. Order is the prompt's order, company memories first. `block_chars` is the length of the pinned block before the prompt's cap, `block_char_cap`, and each memory's `chars_in_prompt` says how much of it the prompt holds: its length, fewer when the cap cuts it, 0 when it starts past the cap. `reads_company_memories: false` means no run of this agent has a company in context (a scheduled Agent, an internal Chat Agent), so `end_company_id` is ignored. `reads_pinned_memories: false` means no run of this agent reads pinned memories: the workspace has memories off, or the Workflow has no Acknowledge, Triage, Dispatch or L1 action. A Workflow reads only memories not limited to agents, and a Chat Agent reads none on a turn from a person who is not a member of the workspace. Reached through Neo Support, this route sits in the Agent Memories permission group. # List what this agent could still be given Source: https://docs.neoagent.io/api-reference/agents/list-what-this-agent-could-still-be-given https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id}/improvement-options The tools this workspace could still switch on for this agent, and the integration capabilities it could still be granted. Read it before concluding that Neo cannot do something an agent failed to do: an agent knows only its own enabled tools, and integration capabilities are permission groups that appear in no tool list and that the agent cannot see at all. So an agent reporting it 'has no tool for X' is evidence about its own configuration and not about what Neo ships. Two flags say why a list is empty. `tool_catalog_unavailable` means this workspace has no PSA connected, so the catalogue could not be built — a real configuration rather than a fault. `integration_connectivity_unavailable` means a read failed. Treat an empty list under either as unknown, and do not report the first as a service problem. It does NOT report the set an agent runs with: that is decided per run, not per agent — the same agent resolves differently on a ticket run and a ticketless one — so read the run's own trace for that. Agents only (`autonomy_type=AGENTIC`). A Workflow holds no toolbox, and a Chat Agent resolves its tools per conversation and per speaker, so no answer outside a live conversation describes what it can do; both return `400 agent_has_no_toolbox`. For those, read the stored configuration on `GET /agents/<id>`. # Run an agent now Source: https://docs.neoagent.io/api-reference/agents/run-an-agent-now https://api.neoagent.io/public-api/openapi.json post /public-api/agents/{agent_id}/run-now Triggers a run immediately. Async — returns `{"execution_id": "<temporal_run_id>", "status": "queued"}`; poll `GET /executions/<execution_id>` for completion. Triggered agents need `target_entity_id` in the body; scheduled agents need nothing. `target_entity_ids` (1 to 100, instead of `target_entity_id`) starts one run per entity in one call and returns `{"runs": [{"target_entity_id", "execution_id", "status": "queued" | "failed", "error"}]}`; a failed entity does not stop the others. `bypass_entities_filter: true` runs a triggered agent on its target entities even when they do not match the agent's ticket filter. Both are refused (400 `validation_error`) on a scheduled agent. Conversational agents are rejected (400 `invalid_for_conversational`) — reach them via `POST /chat/sessions`. `supervised_run` makes this one run supervised: every change waits for one of the named `approver_ids` to approve it, and those technicians replace the agent's own approvers for the run. An agent in test mode can run supervised: it still asks, but every change is simulated, approved or not. Refused (400 `validation_error`) for a workflow or an agent that processes entities sequentially, and (409 `agent_run_in_progress`) when the agent is already running on that entity, because a start against a live execution arrives as a signal whose arguments are dropped. A `target_entity_ids` call still returns 202 and reports that conflict as the entity's `failed` result. A disabled agent runs too, as with the dashboard's Run now, and stays disabled for its own triggers and schedule. At-least-once: a retried 5xx can produce a duplicate run. # Update an agent Source: https://docs.neoagent.io/api-reference/agents/update-an-agent https://api.neoagent.io/public-api/openapi.json put /public-api/agents/{agent_id} Accepts **PUT** or **PATCH** (identical partial-merge semantics). Partial-patches an agent — only the fields you send change. `autonomy_type`, `entity_type`, and `trigger_type` are immutable — `trigger_type` may be sent but must match the agent's current value, and a differing value returns 400. Send updated `ticket_conditions` / `time_entry_conditions` to change the entity filter; the server rebuilds the `FIND_ENTITIES` action. `actions` is the pipeline AFTER `FIND_ENTITIES` (CHAINED_ACTIONS only) — patching `actions` on an AGENTIC agent or conditions on a CONVERSATIONAL agent returns 400. An `actions` patch MERGES per-action: each entry targets one existing action by `id` (or unique `action_type`) and its `input_as_dict` is merged key-by-key, so changing one setting preserves the rest; unreferenced actions are kept and unmatched entries are appended. There is no wholesale-replace mode — a PUT can never drop or reorder an action (do structural pipeline edits in the dashboard). On a `TRIAGE_TICKET` / `TRIAGE_TIME_ENTRY` action, `fields_to_triage` is a list and so replaces wholesale under the normal merge — send `fields_to_triage_edits` in that action's `input_as_dict` to change one field keyed by `field_name`: a matching entry merges key-by-key (every other triage field stays byte-identical), an unmatched one is appended (`field_name` is the only setting it must carry), and an entry carrying `remove: true` drops its target instead of editing it — a removal names its target and nothing else, must match a configured field (a no-match returns 400 rather than silently doing nothing), and cannot remove the last remaining field. A PSA-unsupported `field_name` returns 400, and sending both `fields_to_triage` and `fields_to_triage_edits` in one action returns 400. Use the `field_name` spelling `GET /agents/<id>` returns (the PSA name, e.g. `contact`, `customFields`); the enum member name (`CONTACT`, `CUSTOM_FIELD`) is also accepted. A custom field is keyed by `field_name` (`customFields`) plus `custom_field_name`, since all custom fields share one `field_name` — send both to target the right one. A `toolbox` patch also MERGES per tool: each entry under `tool_settings_by_type` is merged key-by-key onto that tool's current settings (lists like `allowed_users` replace; `null` for a tool key disables it), so changing one tool's setting no longer requires resending the whole toolbox. `agent_settings`, `integrations`, `schedule`, and `callback_settings` MERGE the same way: send only the fields you're changing — e.g. `{"agent_settings": {"custom_instructions": "…"}}` edits only the instructions and leaves `test_mode`/`model`/`til_channel` intact, sending one integration's permissions leaves the others connected, and `{"schedule": {"timezone": "…"}}` leaves the run cadence and business-hours windows intact. To edit a long `custom_instructions` runbook without resending the whole blob, send `agent_settings_edits.custom_instructions` with either `edits` (a list of exact `old_string`/`new_string` search-replaces — each must match exactly once, or pass `replace_all`; zero or multiple matches reject the request and write nothing) or `append` (text added with a newline separator). An optional `base_hash` (`sha256:…` of the instructions you read) gives optimistic concurrency: a stale hash returns 409 `agent_stale_write` instead of clobbering a concurrent dashboard edit. This form is mutually exclusive with a full `agent_settings.custom_instructions` in the same request (400), and applies only to AGENTIC / CONVERSATIONAL agents (CHAINED_ACTIONS has no agent_settings layer → 400). Refuses Neo-managed agents (403 `agent_managed_by_neo`). Editing `actions`, `agent_settings`, `toolbox`, `integrations`, or the conditions is a destructive change (triggers a TIL approval when an agent makes the call via `NEO_API_REQUEST`). 409 `agent_update_conflict` on a concurrent edit. # Update an agent Source: https://docs.neoagent.io/api-reference/agents/update-an-agent-1 https://api.neoagent.io/public-api/openapi.json patch /public-api/agents/{agent_id} Accepts **PUT** or **PATCH** (identical partial-merge semantics). Partial-patches an agent — only the fields you send change. `autonomy_type`, `entity_type`, and `trigger_type` are immutable — `trigger_type` may be sent but must match the agent's current value, and a differing value returns 400. Send updated `ticket_conditions` / `time_entry_conditions` to change the entity filter; the server rebuilds the `FIND_ENTITIES` action. `actions` is the pipeline AFTER `FIND_ENTITIES` (CHAINED_ACTIONS only) — patching `actions` on an AGENTIC agent or conditions on a CONVERSATIONAL agent returns 400. An `actions` patch MERGES per-action: each entry targets one existing action by `id` (or unique `action_type`) and its `input_as_dict` is merged key-by-key, so changing one setting preserves the rest; unreferenced actions are kept and unmatched entries are appended. There is no wholesale-replace mode — a PUT can never drop or reorder an action (do structural pipeline edits in the dashboard). On a `TRIAGE_TICKET` / `TRIAGE_TIME_ENTRY` action, `fields_to_triage` is a list and so replaces wholesale under the normal merge — send `fields_to_triage_edits` in that action's `input_as_dict` to change one field keyed by `field_name`: a matching entry merges key-by-key (every other triage field stays byte-identical), an unmatched one is appended (`field_name` is the only setting it must carry), and an entry carrying `remove: true` drops its target instead of editing it — a removal names its target and nothing else, must match a configured field (a no-match returns 400 rather than silently doing nothing), and cannot remove the last remaining field. A PSA-unsupported `field_name` returns 400, and sending both `fields_to_triage` and `fields_to_triage_edits` in one action returns 400. Use the `field_name` spelling `GET /agents/<id>` returns (the PSA name, e.g. `contact`, `customFields`); the enum member name (`CONTACT`, `CUSTOM_FIELD`) is also accepted. A custom field is keyed by `field_name` (`customFields`) plus `custom_field_name`, since all custom fields share one `field_name` — send both to target the right one. A `toolbox` patch also MERGES per tool: each entry under `tool_settings_by_type` is merged key-by-key onto that tool's current settings (lists like `allowed_users` replace; `null` for a tool key disables it), so changing one tool's setting no longer requires resending the whole toolbox. `agent_settings`, `integrations`, `schedule`, and `callback_settings` MERGE the same way: send only the fields you're changing — e.g. `{"agent_settings": {"custom_instructions": "…"}}` edits only the instructions and leaves `test_mode`/`model`/`til_channel` intact, sending one integration's permissions leaves the others connected, and `{"schedule": {"timezone": "…"}}` leaves the run cadence and business-hours windows intact. To edit a long `custom_instructions` runbook without resending the whole blob, send `agent_settings_edits.custom_instructions` with either `edits` (a list of exact `old_string`/`new_string` search-replaces — each must match exactly once, or pass `replace_all`; zero or multiple matches reject the request and write nothing) or `append` (text added with a newline separator). An optional `base_hash` (`sha256:…` of the instructions you read) gives optimistic concurrency: a stale hash returns 409 `agent_stale_write` instead of clobbering a concurrent dashboard edit. This form is mutually exclusive with a full `agent_settings.custom_instructions` in the same request (400), and applies only to AGENTIC / CONVERSATIONAL agents (CHAINED_ACTIONS has no agent_settings layer → 400). Refuses Neo-managed agents (403 `agent_managed_by_neo`). Editing `actions`, `agent_settings`, `toolbox`, `integrations`, or the conditions is a destructive change (triggers a TIL approval when an agent makes the call via `NEO_API_REQUEST`). 409 `agent_update_conflict` on a concurrent edit. # Create an API key Source: https://docs.neoagent.io/api-reference/api-keys/create-an-api-key https://api.neoagent.io/public-api/openapi.json post /public-api/api-keys Mints a new key. The plaintext secret is returned once, in `data.key`, and never again. Admin dashboard JWT only. # List API keys Source: https://docs.neoagent.io/api-reference/api-keys/list-api-keys https://api.neoagent.io/public-api/openapi.json get /public-api/api-keys Active API keys for the caller's tenant. Admin dashboard JWT only — never returns the secret. # Revoke an API key Source: https://docs.neoagent.io/api-reference/api-keys/revoke-an-api-key https://api.neoagent.io/public-api/openapi.json delete /public-api/api-keys/{key_id} Immediately revokes the key. Admin dashboard JWT only. # Rotate an API key Source: https://docs.neoagent.io/api-reference/api-keys/rotate-an-api-key https://api.neoagent.io/public-api/openapi.json post /public-api/api-keys/{key_id}/rotate Mints a replacement key and sunsets the old one after a 24h overlap so callers can roll over without downtime. Takes no request body. The new plaintext secret is returned once, in `data.key`. A key that has expired, or expires within 24 hours, returns 409 `api_key_not_rotatable`; create a new key instead. Admin dashboard JWT only. # Audit Log summary — call counts per tool and per agent Source: https://docs.neoagent.io/api-reference/audit-log/audit-log-summary-—-call-counts-per-tool-and-per-agent https://api.neoagent.io/public-api/openapi.json get /public-api/audit-log/facets Call counts over the same 30-day window and the same workflow scope as the tool-call list: total calls, failed calls, and the tools and agents that made calls with a count each. Use it to answer "which agents were active" or "how many calls failed" before paging through rows, and to pick a `tool_type_name` / `agent_id` filter. # List agent tool calls (Audit Log) Source: https://docs.neoagent.io/api-reference/audit-log/list-agent-tool-calls-audit-log https://api.neoagent.io/public-api/openapi.json get /public-api/audit-log/tool-calls Every tool call the tenant's agents made in the last 30 days, one row per call, newest first — the API behind the dashboard's Reporting -> Audit Log page. Answers "did one of my agents do this?": search a ticket number, a user or a device name and the rows show which agent acted, when, with what input, and how it went. Triggered, scheduled and chat agents are all included. The window is always the last 30 days and cannot be widened. Rows follow the acting user's workflow access: an owner or admin sees every agent, a user or viewer only the agents they created or were shared; a person with no dashboard account gets 403. Cursor-paginated on `(created_at, step id)`. `execution_id` opens the run's full trace at `GET /executions/{execution_id}/steps`. # Cancel a backfill Source: https://docs.neoagent.io/api-reference/backfills/cancel-a-backfill https://api.neoagent.io/public-api/openapi.json post /public-api/backfills/{backfill_id}/cancel Terminal. Stops new dispatches; tickets already mid-run finish on their own. Returns 202 — the state updates within ~30s. If the backfill had already stopped running, cancel settles it directly and returns 200, and the response message names the state it settled on — Cancelled, unless the backfill recorded its own terminal state first. Either way the backfill stops blocking new backfills for its agent. # Create a backfill Source: https://docs.neoagent.io/api-reference/backfills/create-a-backfill https://api.neoagent.io/public-api/openapi.json post /public-api/backfills Create a backfill against a target workflow. Returns the row plus an upper-bound credit cost estimate. At most one Running or Paused backfill per target workflow per tenant — a second attempt while one is active returns 409 `backfill_already_active`. `filter_spec` is parsed here: a spec that cannot be parsed, or a rule that puts a list in `value` under an operator taking a single value (a list is valid only with `in` / `notIn`), returns 400 `validation_error`. The target agent must be enabled: Neo runs a backfill's tickets through it, so a disabled agent would process nothing and returns 409 `agent_disabled`. A deleted agent is not visible to this API at all and returns 404 `agent_not_found`. # Get a backfill Source: https://docs.neoagent.io/api-reference/backfills/get-a-backfill https://api.neoagent.io/public-api/openapi.json get /public-api/backfills/{backfill_id} # List a backfill's failed tickets Source: https://docs.neoagent.io/api-reference/backfills/list-a-backfills-failed-tickets https://api.neoagent.io/public-api/openapi.json get /public-api/backfills/{backfill_id}/failures Returns the failed child executions of one backfill, newest first. Each entry carries the entity reference, the user-facing failure message, and a `temporal_run_id` for deep-linking into the full execution detail. Returns an empty list for backfills that haven't started yet. # List backfills Source: https://docs.neoagent.io/api-reference/backfills/list-backfills https://api.neoagent.io/public-api/openapi.json get /public-api/backfills Backfills for the caller's tenant, newest first. A backfill applies an existing workflow to historical tickets the workflow's normal trigger would never re-fire for. # Pause a backfill Source: https://docs.neoagent.io/api-reference/backfills/pause-a-backfill https://api.neoagent.io/public-api/openapi.json post /public-api/backfills/{backfill_id}/pause Signals the orchestrator to stop dispatching new tickets. In-flight tickets still finish. Idempotent. Returns 202 — the state updates within ~30s; poll `GET /backfills/{id}` to observe it. # Preflight a backfill filter Source: https://docs.neoagent.io/api-reference/backfills/preflight-a-backfill-filter https://api.neoagent.io/public-api/openapi.json post /public-api/backfills/verify Counts the entities the filter would match and classifies the result (OK / WARNING / ERROR). Use this to validate a filter before committing to create. No backfill row is created. A malformed `filter_spec` — including a list in a rule's `value` under an operator taking a single value — comes back as 200 with `success=false` and `safety_level=ERROR`, never a 4xx. # Rerun a backfill against its failed tickets Source: https://docs.neoagent.io/api-reference/backfills/rerun-a-backfill-against-its-failed-tickets https://api.neoagent.io/public-api/openapi.json post /public-api/backfills/{backfill_id}/rerun-failed Spawn a new backfill scoped to the source's failed entities. The new backfill inherits the source's target workflow, execution windows, timezone, and concurrency cap; only the tickets that failed in the source are dispatched (no PSA filter re-evaluation). Eligibility: source state is terminal (Completed / Cancelled / Failed), `failed_count > 0`, and no active backfill exists for the same target workflow — otherwise `409 backfill_not_rerunnable` (or `409 backfill_already_active` for the conflict case). The target agent must still be enabled, as for create — `409 agent_disabled` if it is disabled, `404 agent_not_found` if it was deleted. Returns 201 with the new backfill + cost estimate (credits). # Resume a backfill Source: https://docs.neoagent.io/api-reference/backfills/resume-a-backfill https://api.neoagent.io/public-api/openapi.json post /public-api/backfills/{backfill_id}/resume Signals the orchestrator to resume dispatching. Idempotent. Returns 202 — the state updates within ~30s. # Detailed end-user bot (MAU) breakdown for a month Source: https://docs.neoagent.io/api-reference/billing/detailed-end-user-bot-mau-breakdown-for-a-month https://api.neoagent.io/public-api/openapi.json get /public-api/billing/end-user-teams/detail Per-company and per-user active-end-user breakdown (one or more messages that month) for the white-label end-user bot (Teams and Slack), each with the bot-raised PSA tickets behind it (deep-links when the PSA is configured), plus a monthly active-user trend ending at the selected month. Companion to /billing/end-user-teams-usage (headline MAU + dollar charge); this is the drill-down. Exposes the customer's own usage, never provider/LLM cost. # Get credit usage for a month Source: https://docs.neoagent.io/api-reference/billing/get-credit-usage-for-a-month https://api.neoagent.io/public-api/openapi.json get /public-api/billing/usage Credit usage for the given month. Defaults to the current calendar month. For past months, `credits_limit`, `credits_remaining`, and `reserve_balance` are null because historical plan data is not stored. `credits_cost` prices `credits_used` at the tenant's current price per credit (see `/billing/subscription`), also for a past month; it is null when no price is known. # Get credit usage per ticket for a period Source: https://docs.neoagent.io/api-reference/billing/get-credit-usage-per-ticket-for-a-period https://api.neoagent.io/public-api/openapi.json get /public-api/billing/usage-by-ticket Credits billed on each ticket between `since` and `until`, one row per ticket, highest first. A credit counts in the period it was billed in. Runs with no single ticket (scheduled and bulk runs) and chat-agent credits share one row with a null `entity_id`. `total_credits` is what the whole period billed for the agents you can view, and `total_rows` how many rows it has; `tickets` holds the `limit` highest of them. A row's `entity_type` is its agent's entity type; only a TICKET row carries its PSA company, as of the ticket's last sync (null when the sync does not hold the ticket). A period can be at most 93 days. `credits_cost` on each row and `total_credits_cost` price the credits at the tenant's current price per credit; null when no price is known. # Get end-user bot (MAU) usage and charge for a month Source: https://docs.neoagent.io/api-reference/billing/get-end-user-bot-mau-usage-and-charge-for-a-month https://api.neoagent.io/public-api/openapi.json get /public-api/billing/end-user-teams-usage End-user (white-label) bot usage, Teams and Slack together, for the given month (defaults to current): the number of active end-users (one or more messages that month; clients on the retired per-user schedule: two or more) and the resulting add-on charge. The charge is the MSP's own add-on bill for that month; for the current month it is a projection that finalizes at month close. Exposes the customer's own add-on charge, never provider/LLM cost or Stripe internals. # Get per-agent credit usage for a month Source: https://docs.neoagent.io/api-reference/billing/get-per-agent-credit-usage-for-a-month https://api.neoagent.io/public-api/openapi.json get /public-api/billing/usage-by-agent Credit usage broken down by agent for the given month. Defaults to the current calendar month. Each row's `credits_cost` prices its credits at the tenant's current price per credit, null when no price is known. # Get the tenant's referral program state Source: https://docs.neoagent.io/api-reference/billing/get-the-tenants-referral-program-state https://api.neoagent.io/public-api/openapi.json get /public-api/billing/referrals The tenant's referral code, the MSP that referred it, and every MSP it referred, trials included: each one's stage and, once it moved to a paid plan, the monthly credits it adds and the date they stop. Also the rewards the tenant holds and the program terms. Credits only, never dollar amounts. # Get the tenant's subscription / plan state Source: https://docs.neoagent.io/api-reference/billing/get-the-tenants-subscription-plan-state https://api.neoagent.io/public-api/openapi.json get /public-api/billing/subscription Customer-facing plan + credits state, and `credit_unit_price`: what one credit costs the tenant, in their billing currency. The price is what the tenant pays for the plan and top-up packs over the credits those include; bonus, referral, reserve and trial credits are free and count on neither side. It is null on a trial and when no billing system states the price. Deliberately excludes Stripe IDs, invoice lines and any provider cost attribute. # Get a callback Source: https://docs.neoagent.io/api-reference/callbacks/get-a-callback https://api.neoagent.io/public-api/openapi.json get /public-api/callbacks/{callback_id} # List callbacks Source: https://docs.neoagent.io/api-reference/callbacks/list-callbacks https://api.neoagent.io/public-api/openapi.json get /public-api/callbacks PSA callbacks (webhook events) received for the caller's tenant. Requires an indexed filter — `entity_type`+`entity_id`, `entity_number`, or `since` (≤ 7 days). **Default `page_size` is 20 here** (lower than the public-API global of 50): each row carries the per-workflow `workflow_matches` audit, so 50-row responses can exceed the chat-agent context budget. There is no cursor: `has_more: true` means rows beyond this page may match, so narrow the filter and read again. `since`/`until` bound only a `since` query; an entity query ignores them and returns its newest rows. With `agent_id` or `filtered_only`, `has_more: true` can also mean only that the bounded scan of the newest rows filled up before those filters applied: the page can be short or empty, and older matches may or may not exist. # Create a channel Source: https://docs.neoagent.io/api-reference/channels/create-a-channel https://api.neoagent.io/public-api/openapi.json post /public-api/channels Bind a CONVERSATIONAL agent to a transport. An ACTIVE channel must have an agent. `audience` (MSP | END_USER) declares the surface's trust domain and must match the bound agent's audience — an END_USER channel may only bind a user-facing agent, and an MSP (internal) channel only an internal agent. `audience` is fixed for the channel's whole life; pick it carefully. `internal_name` must be unique among your live channels (compared trimmed and case-insensitively). Omitting `show_agent_progress_steps` takes the audience default — the live "working…" card is off on an END_USER channel and on for MSP; send it explicitly to override, and it stays editable afterwards. `idle_reset_minutes` sets how long a Teams conversation may sit idle before the bot offers the user a "Start fresh / Continue" card; omit it to keep only the built-in behaviour, which offers the same card on conversations that have grown large enough to be slow to resume. A new END_USER Teams channel starts with `show_tickets_tab` TRUE and `default_tab` TICKETS, so its app opens on the Tickets tab; change either afterwards with an update. A new END_USER Slack channel starts with `show_tickets_tab` TRUE and `default_tab` CHAT, so its Slack app is built with the Home tab. Every other channel starts with no Tickets tab and `default_tab` CHAT. **A created channel is not yet reachable.** The response comes back with `install_required` TRUE and the outstanding step in `install_next_step`. A Teams channel's app still has to be installed into a Microsoft 365 tenant, which an administrator of that tenant approves — sending that administrator an install link does not clear it either. A Slack channel's app is installed into each client's Slack workspace by a Slack admin of that workspace, from the channel's Slack install link. Do not report the channel as live while `install_required` is TRUE. `type=SLACK` takes only an END_USER channel and is refused with `validation_error` otherwise. An MSP may hold several MSP-audience (internal) Teams channels: each is stamped at creation with its own bot identity from a fixed pool, so they install into the MSP's own tenant side by side. Creating one is refused with `validation_error` when the workspace has no Microsoft 365 directory connected yet, or once the pool is used up; the message names the remedy. End-user channels are not capped — each installs into a different end client's tenant. # Create a Slack install link Source: https://docs.neoagent.io/api-reference/channels/create-a-slack-install-link https://api.neoagent.io/public-api/openapi.json post /public-api/channels/{channel_id}/slack-install-link A Slack install URL for one client company, valid for two days. The company's Slack administrator opens it and approves the install; the workspace is then linked to that company. 400 until the channel's Slack app is `READY`. A workspace already linked to another company refuses the install until you remove it from every channel. # Delete a channel Source: https://docs.neoagent.io/api-reference/channels/delete-a-channel https://api.neoagent.io/public-api/openapi.json delete /public-api/channels/{channel_id} Deletes the channel. # Get a channel Source: https://docs.neoagent.io/api-reference/channels/get-a-channel https://api.neoagent.io/public-api/openapi.json get /public-api/channels/{channel_id} # Get a channel's Slack app Source: https://docs.neoagent.io/api-reference/channels/get-a-channels-slack-app https://api.neoagent.io/public-api/openapi.json get /public-api/channels/{channel_id}/slack-app The branded Slack app of a SLACK channel and where its build stands. 404 `slack_app_not_found` when none was requested. # List a channel's Slack workspaces Source: https://docs.neoagent.io/api-reference/channels/list-a-channels-slack-workspaces https://api.neoagent.io/public-api/openapi.json get /public-api/channels/{channel_id}/slack-installs The Slack workspaces the channel's app is installed in, each with the client company its users are scoped to. A workspace with no linked company cannot chat. # List a Teams channel's client tenants Source: https://docs.neoagent.io/api-reference/channels/list-a-teams-channels-client-tenants https://api.neoagent.io/public-api/openapi.json get /public-api/channels/{channel_id}/teams-installs The client tenants a TEAMS channel's app is installed in or has an install link for, each with its company, the app version it holds compared with the last publish, and what stops Neo publishing there, if anything. 400 on a channel that is not TEAMS. # List channels Source: https://docs.neoagent.io/api-reference/channels/list-channels https://api.neoagent.io/public-api/openapi.json get /public-api/channels Channels for the tenant — each binds a CONVERSATIONAL agent to a transport. Check `install_required` on each: a channel nobody has installed yet cannot receive a message, whatever its `status`. # Remove a Slack workspace Source: https://docs.neoagent.io/api-reference/channels/remove-a-slack-workspace https://api.neoagent.io/public-api/openapi.json delete /public-api/channels/{channel_id}/slack-installs/{install_id} Remove one workspace from a SLACK channel: Neo stops answering there and asks Slack to uninstall the app. If Slack refuses, a Slack admin of the workspace removes the app. When no other channel of yours is installed in the workspace, its company link is released too, so an install link for any company can connect it again. # Request a channel's Slack app Source: https://docs.neoagent.io/api-reference/channels/request-a-channels-slack-app https://api.neoagent.io/public-api/openapi.json post /public-api/channels/{channel_id}/slack-app Ask Neo to build the branded Slack app of an END_USER SLACK channel, named after the channel's `display_name` (at most 35 characters). Neo creates the app in Slack at once (`AWAITING_MANUAL_STEPS`), then finishes the icon and distribution setup in Slack and sets `READY`. Idempotent per channel: a repeat on a `FAILED` request retries it, and a repeat on a live app pushes changed name or description to Slack. A Slack failure answers 200 with `status` `FAILED` and `failure_reason`. After an interrupted create (`failure_reason` starts `Interrupted create:`) a repeat changes nothing until Neo staff release the request. # Resolve install greeting branding Source: https://docs.neoagent.io/api-reference/channels/resolve-install-greeting-branding https://api.neoagent.io/public-api/openapi.json post /public-api/channels/install-events Platform callers only — the Teams relay reports an `installationUpdate add` and gets back the channel's greeting branding. A registered white-label install on an ACTIVE channel already routes (the inbound message proves the install — there is no status to flip). On a match the call also records the install as verified and starts the owning MSP's end-user trial; both are idempotent, so repeating the call changes nothing. `matched=false` means no routable white-label channel claims the `(bot_id, tenant)` — e.g. the shared marketplace bot — and the relay greets with its default. The Slack relay passes `channel=SLACK`, the Slack app id as `bot_id` and the Slack workspace (team) id as `end_client_tenant_id`. The response has the same shape, and carries the channel's own display name, description and welcome message. # Update a channel Source: https://docs.neoagent.io/api-reference/channels/update-a-channel https://api.neoagent.io/public-api/openapi.json patch /public-api/channels/{channel_id} Partial patch. Only the supplied fields are changed. `audience` cannot be changed — sending the channel's current audience is accepted (so agent and audience can always travel together), any other value returns 400; create a new channel for the other audience. A new `internal_name` must not collide with another live channel's. Teams app settings (`display_name`, `description`, the icons, `show_tickets_tab`, `default_tab`) reach installed tenants only after the app update is published. On a Slack channel, a change of `show_tickets_tab` goes to the Slack app (its Home tab) at once; when Slack refuses it, the Slack app's `manifest_pending` is true until the app is requested again. `tickets_tab_links` replaces the whole list and needs no publish: the Tickets tab shows it the next time it loads or is refreshed. # Upload a Slack channel's icon Source: https://docs.neoagent.io/api-reference/channels/upload-a-slack-channels-icon https://api.neoagent.io/public-api/openapi.json post /public-api/channels/{channel_id}/slack-app/icon Set a SLACK channel's icon from a base64 PNG or JPEG of at least 512 x 512 px (Slack refuses smaller icons). Neo stores it as a 512 px square. On a channel whose Slack app already exists, Neo uploads the new icon to Slack for you; a 502 means the icon is saved but that hand-off failed, so upload it again. # Append a user message + enqueue a chat turn Source: https://docs.neoagent.io/api-reference/chat/append-a-user-message-+-enqueue-a-chat-turn https://api.neoagent.io/public-api/openapi.json post /public-api/chat/sessions/{session_id}/messages Persists the user message and enqueues a `ChatTurnWorkflow`. Returns 202 Accepted with the persisted message id + the Temporal workflow id. The agent's streamed response is consumed via `GET /chat/sessions/<id>/events`. Pass `client_message_id` for idempotent retries — a duplicate returns 409 with the original message id and no new turn is enqueued. The response also includes `since_cursor`: the SSE stream id snapshotted right before this turn was enqueued. Pass it as `?since=<since_cursor>` on the very next call to `/chat/sessions/<id>/events` so the tail skips envelopes from prior turns on this session — skipping the cursor on a 2nd+ turn against the same session causes the tail to return the previous turn's final state. To include images or documents, first upload each via `POST /chat/sessions/<id>/attachments/upload-url`, then pass the returned `blob_path` values in `attachments`. `message` may be empty when at least one attachment is provided. Attachments are surfaced on later `GET .../messages` replays. # Create a chat session Source: https://docs.neoagent.io/api-reference/chat/create-a-chat-session https://api.neoagent.io/public-api/openapi.json post /public-api/chat/sessions Create a session against a CONVERSATIONAL agent. Returns the session resource; messages are appended via `POST /chat/sessions/<id>/messages`. Select the agent with **exactly one** of `agent_id` (numeric) or `managed_agent_key` (a stable key for a Neo-managed agent, e.g. `NEO_SUPPORT`); the latter lets a caller target the agent without knowing its per-tenant id. A **platform** service account may pass `client_id` to create the session for another tenant — used by the converged Neo Support relay to run each MSP technician's turn as their own tenant. For a platform caller the agent is resolved from `bot_id` (the inbound Teams bot app id) + `inbound_tenant_id` (the message's M365 tenant): a white-label bot with a channel installed for that tenant routes to the channel's agent acting as the owning MSP (the acting tenant is then resolved server-side, overriding `client_id`, and returned on the resource); else the ACTIVE channel registered for that bot; else that tenant's Neo Support agent. The caller is confined to those outcomes (never an arbitrary agent). Any non-platform caller passing `client_id` is rejected with 403, and a platform caller whose `client_id` names no active tenant with 400 `tenant_not_active` — end-user-relayable copy, because the relay passes the sender's own M365 tenant here and anybody may install the marketplace bot from the Teams store. A white-label session is always scoped to one end-company, resolved server-side from `inbound_tenant_id`. A tenant linked to several companies (branch offices) is narrowed to the company whose PSA contacts hold the caller-supplied `end_user_email`, then by deterministic tiebreaks. If the tenant isn't linked to any company in the owning MSP's dashboard, the create is refused with 409 `end_company_not_mapped`; the error message is end-user-relayable and tells the MSP admin what to link. `channel` names the relay's surface: `TEAMS` (the default) or `SLACK`. It is honored only for a platform caller; any other service-account or end-user-session caller's session is TEAMS, and a dashboard caller's is always a dashboard session. A platform caller with `SLACK` must pass `bot_id` (the Slack app id) and `inbound_tenant_id` (the Slack workspace id). The session routes to the channel whose Slack app is installed in that workspace, acting as its owning MSP, and is scoped to the company the workspace was linked to at install time. There is no Neo Support fallback for Slack: a workspace no active channel routes is refused with 409 `white_label_not_connected`, and an unlinked workspace with 409 `end_company_not_mapped`. # Get a chat session Source: https://docs.neoagent.io/api-reference/chat/get-a-chat-session https://api.neoagent.io/public-api/openapi.json get /public-api/chat/sessions/{session_id} # Get a signed URL to upload a chat image or document Source: https://docs.neoagent.io/api-reference/chat/get-a-signed-url-to-upload-a-chat-image-or-document https://api.neoagent.io/public-api/openapi.json post /public-api/chat/sessions/{session_id}/attachments/upload-url Issues a short-lived SAS URL to upload one attachment directly to storage, so multi-MB screenshots and documents never transit this API. PUT the bytes to `upload_url` with headers `x-ms-blob-type: BlockBlob` and `x-ms-blob-content-type: <mime>`, then reference the returned `blob_path` in the `attachments` of `POST /chat/sessions/<id>/messages`. Allowed types: images (image/png, image/jpeg, image/gif, image/webp) and documents (application/pdf, text/plain, text/csv, application/msword, the Word/Excel OpenXML types). Honour `max_image_bytes` — the API can't see the bytes on this path. The blob path is server-chosen and scoped to this session. # List messages in a chat session Source: https://docs.neoagent.io/api-reference/chat/list-messages-in-a-chat-session https://api.neoagent.io/public-api/openapi.json get /public-api/chat/sessions/{session_id}/messages Cursor-style history. Pass `?since=<message_id>` to fetch messages strictly after that id — used for reconnect catch-up before re-subscribing to `/chat/sessions/<id>/events`. # Mint an end-user session token Source: https://docs.neoagent.io/api-reference/chat/mint-an-end-user-session-token https://api.neoagent.io/public-api/openapi.json post /public-api/sessions Mints a short-lived JWT bound to one chat `session_id`. The Teams relay (or any future end-user-facing channel) attaches it as `Authorization: Bearer <token>` on subsequent `/chat/sessions/<session_id>/*` calls. Only service-account or dashboard callers can mint; the resulting token cannot mint or revoke. A **platform** service account may pass `client_id` to mint for another tenant, but only when `session_id` is that tenant's Neo Support session or a session of one of its ACTIVE channel agents (a Slack session only through a Slack channel); otherwise 403. Any non-platform caller passing `client_id` is rejected with 403. A Slack or white-label Teams session whose own channel now runs a different agent gets 409 `chat_session_agent_replaced` (a Teams session only once its agent backs no ACTIVE Teams channel): start a new session, which the channel's current agent answers. A session created with no channel keeps the 403. When the session is scoped to an end-company (white-label sessions are, at create), the minted `end_company_id` claim is taken from the session itself — a caller-supplied value never widens or changes the session's scope. # Reset a chat session (archive + start fresh) Source: https://docs.neoagent.io/api-reference/chat/reset-a-chat-session-archive-+-start-fresh https://api.neoagent.io/public-api/openapi.json post /public-api/chat/sessions/{session_id}/reset Archives this chat session and cancels any in-flight turn so the conversation starts fresh — the next message on the channel begins a new session with no carried context. Used by the Teams relay's `/new` command. Idempotent: resetting an already-archived session still returns 200. # Revoke an end-user session token by jti Source: https://docs.neoagent.io/api-reference/chat/revoke-an-end-user-session-token-by-jti https://api.neoagent.io/public-api/openapi.json delete /public-api/sessions/{jti} Adds the token's `jti` to the per-tenant Redis denylist for a 24h TTL ceiling. Future verifies reject it as long as the entry persists. # Stop the turn running on a chat session Source: https://docs.neoagent.io/api-reference/chat/stop-the-turn-running-on-a-chat-session https://api.neoagent.io/public-api/openapi.json post /public-api/chat/sessions/{session_id}/stop Stops the agent turn currently running on this session. The running agent refuses its next tool call, so an action it has not taken yet does not happen, and the run itself is ended — anything queued behind the stopped turn is dropped too. Use this whenever a surface's own stop control is pressed: aborting the SSE tail on your side only stops *you* receiving the reply, while the agent keeps running and may still write. Applies to whatever turn is live, which is not necessarily the one answering the most recent message. Idempotent, and a no-op on an idle session, so a caller never has to check whether a turn is running first. `stopped` reports whether a live run was signalled; `false` means there was nothing left to signal. # Tail chat-session events (SSE) Source: https://docs.neoagent.io/api-reference/chat/tail-chat-session-events-sse https://api.neoagent.io/public-api/openapi.json get /public-api/chat/sessions/{session_id}/events Server-Sent Events stream of Vercel AI SDK v6 envelopes for the session. Response is `text/event-stream` — stream it, don't buffer. Use `?since=` (or the `Last-Event-Id` header) in two cases: 1. First connection for a turn just enqueued via `POST .../messages` — pass the `since_cursor` from that POST response so the tail starts strictly after the previous turn's terminal envelopes. 2. Reconnect of an already-tailing stream — pass the last event id you received so playback resumes at the right spot. Add `?for_message=<user_message_id>` (from the POST response) to pin the tail to the single turn that answers that message. Without it the tail attaches to the first turn boundary after `since`, which can be a sibling turn's when several messages are queued behind one running turn. # Create or replace an agent's credit alert rule Source: https://docs.neoagent.io/api-reference/credit-alert-rules/create-or-replace-an-agents-credit-alert-rule https://api.neoagent.io/public-api/openapi.json put /public-api/agents/{agent_id}/credit-alert-rule Saves the rule in the body in place of any rule the agent has, computes its cap, and returns the saved rule. Send every field; a missing `notify_admins` means true. The alert goes to `recipients`, plus the account's active owners and admins when `notify_admins` is true. A rule with `notify_admins` false and no address is refused with 400. The cap is `multiplier` (above 1, at most 100) times the agent's average over its last 7 days with credits within the last 30 days, rounded up and at least 50 credits; 1.3 means 30% above the average. With `disable_agent` true, Neo also turns the agent off when it goes over the cap. When someone turns it back on that day, the count starts again from that moment, so a second crossing alerts and turns it off again. A rule Neo cannot save answers 400 with the reason. Call the preview first to see the cap. # Delete an agent's credit alert rule Source: https://docs.neoagent.io/api-reference/credit-alert-rules/delete-an-agents-credit-alert-rule https://api.neoagent.io/public-api/openapi.json delete /public-api/agents/{agent_id}/credit-alert-rule Deletes the agent's rule. The agent goes back to the default unusual-usage check. Answers 404 `credit_alert_rule_not_found` when the agent has no rule. # Get an agent's credit alert rule Source: https://docs.neoagent.io/api-reference/credit-alert-rules/get-an-agents-credit-alert-rule https://api.neoagent.io/public-api/openapi.json get /public-api/agents/{agent_id}/credit-alert-rule The agent's daily credit alert rule (`rule` is null when it has none) and the values a new rule starts with. A rule sets a daily credit cap for the agent: `multiplier` times its average over its last 7 days with credits within the last 30 days, and never below `minimum_cap_credits` (50). With fewer than 3 such days `cap_credits` is null and the rule does nothing yet. Every 10 minutes Neo compares the agent's credits since 00:00 UTC with the cap, and emails once when they go over it. An agent with an enabled rule is left out of the default unusual-usage check. Chat agents take no rule. # List credit alert rules Source: https://docs.neoagent.io/api-reference/credit-alert-rules/list-credit-alert-rules https://api.neoagent.io/public-api/openapi.json get /public-api/credit-alert-rules Every credit alert rule in the tenant, on the agents the caller may see. At most one per agent. # Preview a credit alert rule Source: https://docs.neoagent.io/api-reference/credit-alert-rules/preview-a-credit-alert-rule https://api.neoagent.io/public-api/openapi.json post /public-api/agents/{agent_id}/credit-alert-rule/preview What the rule in the body would do if it were saved now: its cap, the average it is based on, and on how many of the last 30 days it would have alerted (`backtest_alert_days`). `daily` lists those 30 days, oldest first, each with the agent's credits and the cap the rule gave that day, null where the agent had too little history. Stores nothing. A rule Neo cannot save answers 400 with the reason. # Create a dashboard Source: https://docs.neoagent.io/api-reference/dashboards/create-a-dashboard https://api.neoagent.io/public-api/openapi.json post /public-api/dashboards Stores the dashboard (name, the Python module with one `widget_<id>(ctx)` per widget, the widget manifest, the read-only permission groups its vendor calls run under, the period rule), starts a refresh of every widget and returns at once with the dashboard id. A problem found without running it (manifest, module, groups, period rule) is a 422 listing every problem, and stores nothing. Read the results with `GET /dashboards/<id>`; through `NEO_API_REQUEST` the tool waits up to 60 s and returns the previews itself. **An acting user must be an admin** (403 `insufficient_scope` otherwise): a dashboard's code reads the whole workspace's data. A key with no acting user is a service account and is already tenant-wide, so it builds without one. The creator is the acting user. If the refresh cannot start, the call is a 5xx and the dashboard is taken back out (soft-deleted: it no longer lists or opens), so send the create again. Dashboards bill nothing. # Delete a dashboard Source: https://docs.neoagent.io/api-reference/dashboards/delete-a-dashboard https://api.neoagent.io/public-api/openapi.json delete /public-api/dashboards/{dashboard_id} Soft-deletes the dashboard and deletes its widget data. Creator or admin only. Via `NEO_API_REQUEST` always asks for approval. # Get a dashboard with its latest widget data Source: https://docs.neoagent.io/api-reference/dashboards/get-a-dashboard-with-its-latest-widget-data https://api.neoagent.io/public-api/openapi.json get /public-api/dashboards/{dashboard_id} The dashboard, its Python module, and each widget with its stored data, the period that data covers, `refreshed_at`, and the newest error: `error` is its full text (the route called, the status, the reason, the module line), for fixing the widget; `error_kind` is what the page tells a person: `PERMISSION` (a read refused for a permission group the dashboard lacks; add it to `permission_groups` with `PUT`), `VENDOR`, `TIMEOUT`, `CODE`, `INVALID_DATA`, `INPUT_FAILED` (an input widget failed), `CREDITS` or `SANDBOX`. **Reads only: never starts a refresh.** A widget is `stale` when its data is older than 15 minutes, never produced, or from an earlier definition; `pending` when a refresh was asked for after its last write (data or error): the current refresh run, or the next one to start, has it to do; also listed in `pending_widget_ids`. A widget nobody has asked to refresh is not pending. `?preview=true` caps each widget's `data` to its first rows and ~1 KB, for a model's context; without it `data` is complete (up to 512 KB per widget). To refresh, call `POST /dashboards/<id>/refresh`. 404 `dashboard_not_found` for another workspace's dashboard or a deleted one. # List a dashboard's versions Source: https://docs.neoagent.io/api-reference/dashboards/list-a-dashboards-versions https://api.neoagent.io/public-api/openapi.json get /public-api/dashboards/{dashboard_id}/definitions Every saved definition (module and widgets) of the dashboard, newest first: its id, `content_hash`, who saved it and when, its widgets' ids and titles, and `in_use` for the one the dashboard uses now. The module is not included. To undo a change, `PUT` the dashboard with `restore_definition_id`. Any member who can view the dashboard may list them. # List the workspace's dashboards Source: https://docs.neoagent.io/api-reference/dashboards/list-the-workspaces-dashboards https://api.neoagent.io/public-api/openapi.json get /public-api/dashboards Every dashboard of the workspace, newest first, without widgets or data. A dashboard is its own thing: not an agent, not a workflow. Every member who can sign in views them (a chat-only member cannot: 403 `insufficient_scope`). # Refresh every widget Source: https://docs.neoagent.io/api-reference/dashboards/refresh-every-widget https://api.neoagent.io/public-api/openapi.json post /public-api/dashboards/{dashboard_id}/refresh Starts one refresh of every widget over the period rule evaluated now, and returns at once: `started_widget_ids` and `skipped_fresh_widget_ids` (the pass that last wrote them, data or an error, started less than 60 seconds ago, so a widget skipped here may be showing a failure; a widget already pending counts as started). Two callers refreshing the same dashboard share one run, and a widget asked for while a run is going runs in that run's next pass (one that run is already refreshing is not run twice); a run has at most three passes, and a request that lands as it closes stays `pending` for the next refresh start. Any member who can view may refresh. The page's refresh button and its auto-refresh timer call this; besides a create or an update, nothing else refreshes a dashboard. Free. # Refresh one widget Source: https://docs.neoagent.io/api-reference/dashboards/refresh-one-widget https://api.neoagent.io/public-api/openapi.json post /public-api/dashboards/{dashboard_id}/widgets/{widget_id}/refresh Starts a refresh of one widget (its inputs run too unless stored data covers them). 409 `dashboard_refresh_too_soon` when the pass that last wrote it (data or an error) started less than 60 seconds ago, the time its data is as of; 422 for a widget the dashboard does not have. Read the result with `GET /dashboards/<id>`. # Update a dashboard Source: https://docs.neoagent.io/api-reference/dashboards/update-a-dashboard https://api.neoagent.io/public-api/openapi.json put /public-api/dashboards/{dashboard_id} Every field is optional, and a field left out keeps the stored value: send only what you change, so a rename someone made since you read the dashboard is not undone. `name` and `period_rule` replace theirs; `permission_groups` replaces the groups (`{}` clears them); `module` and `widgets` together replace the definition. Then asks for a refresh of every widget, a rename included, and returns at once; every widget is `pending` until it lands. `refresh_started` is false when the change was stored but the refresh could not start. `restore_definition_id` (an id from `GET /dashboards/<id>/definitions`) instead makes that earlier definition the one in use, stores no new one, and refreshes every widget; sent with `module` or `widgets` it is a 422, and so is an id that is not this dashboard's. Sending `module` or `widgets`, `restore_definition_id`, or other permission groups, is building: admins only. A rename or a period change: the creator or an admin. Otherwise 403. The old definition's data shows as `stale` until the refresh replaces it. `expected_definition_id`: the `definition_id` your `GET` returned (a UUID). Send it on every `PUT`: when the dashboard uses another definition now, the `PUT` is a 409 `dashboard_update_conflict` and nothing is stored. Without it, only a change made while this `PUT` was saving is a 409; a change made between your `GET` and the `PUT` is overwritten, and a `module` or `widgets` sent alone is paired with the other half as it is when the `PUT` arrives. After a 409, `GET` the dashboard and apply your change to what it has now. # Bulk-update end-companies Source: https://docs.neoagent.io/api-reference/end-companies/bulk-update-end-companies https://api.neoagent.io/public-api/openapi.json post /public-api/end-companies/bulk-update Applies the same partial patch to every listed `psa_company_id` (≤500). Always requires technician approval. Partial failures surface inside the 200 envelope as per-id `{id, status, error?}` rows — they do not raise a top-level error. Allowed patch fields: `auto_assign_exchange_admin`, `auto_assign_priv_auth_admin`, `employee_identity_provider`, `mailbox_provider`, `marketplace_company_ids`. Company-level guidance for agents lives in Memory — see the Memories endpoints. # Clear a manual company link Source: https://docs.neoagent.io/api-reference/end-companies/clear-a-manual-company-link https://api.neoagent.io/public-api/openapi.json post /public-api/company-links/clear Removes a `MANUAL` link, the same change as **Reset** on the Organization Mapping tab. The entity shows as `UNMAPPED`, and the integration's next sync may match it again; a SharePoint folder has no automatic match, so it stays unmapped until it is assigned again. An `AUTO` or `UNMAPPED` entity is `409 company_link_not_manual`: correct a wrong automatic match with the assign call instead. A `SLACK` link belongs to its Slack install, so its clear is `400` with the step to take. On SharePoint, an unmapped folder still accepts a clear: repeat it when `restamp_failed_folder_paths` is not empty, and the call re-stamps the folder's synced docs. # Create an end-company Source: https://docs.neoagent.io/api-reference/end-companies/create-an-end-company https://api.neoagent.io/public-api/openapi.json post /public-api/end-companies Onboard a new end-client. On-prem service-account passwords are dashboard-only and not accepted here. A `tenant_id` is not connected by this call: Neo acts in the tenant once it is connected from the Companies page (access link) or through GDAP. # Delete an end-company Source: https://docs.neoagent.io/api-reference/end-companies/delete-an-end-company https://api.neoagent.io/public-api/openapi.json delete /public-api/end-companies/{psa_company_id} Hard-deletes the end-company. Always requires technician approval when reached via `NEO_API_REQUEST`. # Exclude or include an end-company's tickets Source: https://docs.neoagent.io/api-reference/end-companies/exclude-or-include-an-end-companys-tickets https://api.neoagent.io/public-api/openapi.json put /public-api/end-companies/{psa_company_id}/ticket-exclusion `excluded: true` keeps the company's tickets out of Neo: ticket sync skips them, their PSA webhooks start no triggered agent, and the tickets Neo already synced are deleted from its ticket search. It takes full effect within a minute; the docs page on excluding a company's tickets says what can pass in that minute and what Neo's job queue keeps. `excluded: false` includes them again and starts a sync that brings back the tickets updated in the last 90 days. # Get an end-company Source: https://docs.neoagent.io/api-reference/end-companies/get-an-end-company https://api.neoagent.io/public-api/openapi.json get /public-api/end-companies/{psa_company_id} # List an integration's company links Source: https://docs.neoagent.io/api-reference/end-companies/list-an-integrations-company-links https://api.neoagent.io/public-api/openapi.json get /public-api/company-links How one integration's customers (IT Glue organizations, RMM sites, CIPP tenants, …) map to the tenant's PSA companies: the data behind the integration's **Organization Mapping** tab. Each row carries `link_state` (`AUTO` from a sync, `MANUAL` set by a person and kept by later syncs, `UNMAPPED`), `match_method` and `confidence`. An `AUTO` link below 0.95 is one the dashboard flags for a person to check. Unmapped rows sort first. `counts` covers the `system`, `psa_company_id` and `search` filters, never `status`. A SharePoint folder that was never confirmed is not listed: review new folders on the dashboard. # List end-companies Source: https://docs.neoagent.io/api-reference/end-companies/list-end-companies https://api.neoagent.io/public-api/openapi.json get /public-api/end-companies End-client companies for the tenant. # Map an integration's entity to a PSA company Source: https://docs.neoagent.io/api-reference/end-companies/map-an-integrations-entity-to-a-psa-company https://api.neoagent.io/public-api/openapi.json post /public-api/company-links/assign Sets a `MANUAL` link, the same change as **Map** or **Re-map** on the Organization Mapping tab. Later syncs keep it. The entity must already be listed by `GET /public-api/company-links`, else `404 company_link_not_found`; a `psa_company_id` that is not one of the tenant's synced PSA companies is `404 psa_company_not_found`. `M365` and `MARKETPLACE` links come from the company's own `tenant_id` and `marketplace_company_ids` (`PATCH /public-api/end-companies/{id}`), and a `SLACK` link from the Slack install, so all three are `400`. For a SharePoint folder, `restamp_failed_folder_paths` names a folder whose synced docs kept their previous scope (the old company, or none on a first mapping): retry the call. # Update an end-company Source: https://docs.neoagent.io/api-reference/end-companies/update-an-end-company https://api.neoagent.io/public-api/openapi.json patch /public-api/end-companies/{psa_company_id} Partial patch. Only the supplied fields are changed. A changed `tenant_id` is not connected: Neo acts in the new tenant once it is connected from the Companies page (access link) or through GDAP. # Ask the bot for a new ticket (Teams Tickets tab) Source: https://docs.neoagent.io/api-reference/end-users/ask-the-bot-for-a-new-ticket-teams-tickets-tab https://api.neoagent.io/public-api/openapi.json post /public-api/end-user/tickets/new-request Serves the New ticket button of a white-label Teams app's Tickets tab. Records that the signed-in end user asked for a new ticket, for one hour, and has the bot ask in their chat what the ticket is about, in the language of `locale` (English when it has no translation). On the user's next message the agent is told they asked for a new ticket, and the message is not recorded on a ticket the conversation was already on. Not called with a Neo API key: the `Authorization: Bearer` token is the Teams tab SSO token. Returns 401 for an invalid token, 404 `channel_not_found` when the channel's app is not installed in that tenant or has the tab switched off, and 429 past 30 requests a minute per user. It returns once the request is recorded and the question is started, without waiting for delivery; `asked` is false when the request could not be stored or the question could not be started, and says nothing about delivery. # Continue a ticket in the bot chat (Teams Tickets tab) Source: https://docs.neoagent.io/api-reference/end-users/continue-a-ticket-in-the-bot-chat-teams-tickets-tab https://api.neoagent.io/public-api/openapi.json post /public-api/end-user/tickets/chat-request Serves the Chat about this button of a white-label Teams app's Tickets tab. The ticket must be one of the signed-in end user's open tickets. The bot says in their chat which ticket the conversation is now on, with its title and status when the channel shows them, and asks what they would like to know or add, in the language of `locale` (English when it has no translation). From the user's next reply the conversation continues that ticket, and the technician's client-facing updates on it reach this chat. Not called with a Neo API key: the `Authorization: Bearer` token is the Teams tab SSO token. Returns 401 for an invalid token, 404 `channel_not_found` when the channel's app is not installed in that tenant or has the tab switched off, 404 `ticket_not_available` when the ticket is not an open ticket of the user, 409 `end_company_not_mapped` when the tenant is not linked to one of the MSP's companies, and 429 past 30 requests a minute per user. It returns once the request is recorded and the confirmation is started, without waiting for delivery; `started` is false when either could not be done, and says nothing about delivery. # List an end user's tickets (Teams Tickets tab) Source: https://docs.neoagent.io/api-reference/end-users/list-an-end-users-tickets-teams-tickets-tab https://api.neoagent.io/public-api/openapi.json get /public-api/end-user/tickets Serves the "Tickets" tab of a white-label Teams app: the signed-in end user's open tickets, and those closed in the last `closed_window_days` days, read live from the PSA. Not called with a Neo API key: the `Authorization: Bearer` token is the Teams tab SSO token that Microsoft Teams issues to the tab, and it identifies the user and their Microsoft 365 tenant. Returns 401 for an invalid token, 404 `channel_not_found` when the channel's app is not installed in that tenant or has the tab switched off, 409 `end_company_not_mapped` when the tenant is not linked to one of the MSP's companies, and 429 past 30 requests a minute per user. `state` is `NO_CONTACT` when no PSA contact at the user's company has their email address. `links` holds the MSP's links for the tab; the 409 error carries them in `details.links`, so the page can still show them. # Escalate to the Neo team Source: https://docs.neoagent.io/api-reference/escalation/escalate-to-the-neo-team https://api.neoagent.io/public-api/openapi.json post /public-api/escalate-to-neo-team Opens a HubSpot support ticket on the MSP's behalf (this is the agent / dashboard chat escalating, not an end-user feedback link). Returns the created ticket reference. # Cancel an execution Source: https://docs.neoagent.io/api-reference/executions/cancel-an-execution https://api.neoagent.io/public-api/openapi.json post /public-api/executions/{execution_id}/cancel Requests cancellation of an in-progress run (409 if it isn't cancellable). Not immediate, but nothing new starts: an AGENTIC run stops before its next tool call, so a tool that has not started will not start, and only the model response or tool call already in flight finishes. A CHAINED_ACTIONS run stops at the end of the action running now, which can take much longer. The run is marked cancelled once it stops. Returns 202 with `{status}`. # Get a download URL for a sandbox-file artifact Source: https://docs.neoagent.io/api-reference/executions/get-a-download-url-for-a-sandbox-file-artifact https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/artifacts/{artifact_id}/download-url Returns a short-lived SAS URL for the artifact's blob. 400 `validation_error` for MARKDOWN artifacts (content is inline on the list endpoint). Cross-tenant ids return 404 — the handler verifies the blob_path carries this tenant's `client_id` suffix. # Get an artifact's full body inline Source: https://docs.neoagent.io/api-reference/executions/get-an-artifacts-full-body-inline https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/artifacts/{artifact_id}/content Returns the artifact's real body inline, reading a `SANDBOX_FILE` from blob server-side — for callers that can't resolve the SAS `/download-url` (e.g. an in-product agent whose sandbox/`web_fetch` egress can't reach the blob host). MARKDOWN returns its inline content. Text (UTF-8) only: a binary or larger-than-1 MiB artifact returns 400 `validation_error` — use `/download-url` for those. Cross-tenant ids return 404 (blob_path carries this tenant's `client_id` suffix). # Get an execution Source: https://docs.neoagent.io/api-reference/executions/get-an-execution https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id} One execution row. A run of an agent the acting user may not view answers 404, the same as a run of another tenant, so an unshared agent's existence is not revealed. Every sub-resource of a run applies the same rule. `estimated_manual_minutes` is the technician time a successful run is estimated to have saved: fixed minutes per action for a workflow, the agent's own estimate for an agent. # Get the callback that triggered an execution Source: https://docs.neoagent.io/api-reference/executions/get-the-callback-that-triggered-an-execution https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/callback The PSA callback (webhook event) that started this execution, with the workflow-match details. `null` if the run wasn't callback-triggered. # Get the field-update audit for an execution Source: https://docs.neoagent.io/api-reference/executions/get-the-field-update-audit-for-an-execution https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/field-update-audit Per-field AI decision audit — one row per PSA field a CHAINED_ACTIONS smart action predicted for this run (triage/categorize, dispatch, field updates, merge, QA, tagging, sentiment, …): chosen value, justification, the raw LLM `system_prompt` / `user_prompt` / `gpt_response`, and the candidate `options_to_choose_from`. `should_update_field` does not record Neo's decision: it reads `true` on every row, a kept field included. Whether Neo wrote a field is in the run: a Workflow run's `message_for_dashboard` holds the write list its `UPDATE_TICKET_FIELDS` action reports (an `ASSIGN_TICKET` or dispatch write has no line there), and an Agent run's PSA tool steps show its requests. An AGENTIC agent's field writes appear here only as a stub (prompts `"N/A"`, no options) — its reasoning is in the step trace. # Get the per-run custom instructions Source: https://docs.neoagent.io/api-reference/executions/get-the-per-run-custom-instructions https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/additional-custom-instructions The free-form `additional_custom_instructions` string passed into this specific run (the agent- and company-level layers are not here — see /agents/<id>/version-at). # List artifacts an execution produced Source: https://docs.neoagent.io/api-reference/executions/list-artifacts-an-execution-produced https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/artifacts Artifacts (markdown notes inline, sandbox files referenced) the agent produced during this run. For `SANDBOX_FILE` artifacts, fetch the binary via the sibling `/download-url` endpoint — this list never returns the file content. # List execution steps Source: https://docs.neoagent.io/api-reference/executions/list-execution-steps https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/steps The ordered steps (tool calls, messages, errors) recorded for a run — the forensic trace of what the agent actually saw and did. The path id accepts either an AGENTIC / CHAINED_ACTIONS execution (run) id or a CONVERSATIONAL chat session id; both resolve their trace here. AGENTIC / CONVERSATIONAL traces can be large; use the filters to fetch only what you need (e.g. the agent's baseline ticket read) rather than pulling every step. `type` and `tool_type_name` narrow by step kind and tool; `include_data=false` returns a lightweight index (no per-step I/O) to locate a step, then re-fetch just it by `step_id`. An execution that paused for an approval or an RMM script continues in a new run, so its reasoning is spread over several: `include_chain=true` returns all of them as one trace, from any member's id. # List executions Source: https://docs.neoagent.io/api-reference/executions/list-executions https://api.neoagent.io/public-api/openapi.json get /public-api/executions Agent/workflow execution rows for the caller's tenant, narrowed to the agents the acting user may view — the same per-user boundary the agents endpoints apply. Cursor-paginated, newest first on a stable `(created_at, run_id)` cursor. A SCHEDULED / bulk run carries no single entity — its `entity_id`/`entity_number` are null and the entities it processed are on `processed_sub_entity_ids`, so pass `include_sub_entities=true` to see the sweeps that touched a given ticket alongside its per-ticket runs. # List the RMM script runs in an execution Source: https://docs.neoagent.io/api-reference/executions/list-the-rmm-script-runs-in-an-execution https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/rmm-script-executions # List the TIL requests raised in an execution Source: https://docs.neoagent.io/api-reference/executions/list-the-til-requests-raised-in-an-execution https://api.neoagent.io/public-api/openapi.json get /public-api/executions/{execution_id}/til-requests The TIL requests this execution raised, newest first, across every pause and resume of it: the server scopes them to the runs of its resume chain, so a caller needs no filter of its own. # Retry an execution Source: https://docs.neoagent.io/api-reference/executions/retry-an-execution https://api.neoagent.io/public-api/openapi.json post /public-api/executions/{execution_id}/retry Starts a fresh run for the same entity. Refused (409) while a sibling run is still in progress. Returns 202 with `{status, agent_id, entity_id}`. # Set support-chat contact Source: https://docs.neoagent.io/api-reference/feedback/set-support-chat-contact https://api.neoagent.io/public-api/openapi.json post /public-api/support-chat-contact Sets the person to invite to the MSP's Microsoft Teams support chat and immediately re-attempts the invite. Reached from the Neo-generated access-email link via the dashboard's no-login page — no Authorization header; the `signature` query param is the credential and authorizes only this action for this client. # Submit feedback Source: https://docs.neoagent.io/api-reference/feedback/submit-feedback https://api.neoagent.io/public-api/openapi.json post /public-api/feedback Records end-user feedback for an agent/workflow run. Reached from the Neo-generated feedback link — no Authorization header; the `signature` query param is the credential. # Update feedback Source: https://docs.neoagent.io/api-reference/feedback/update-feedback https://api.neoagent.io/public-api/openapi.json put /public-api/feedback/{feedback_id} Adds a comment / submitter name to a previously created feedback record. # Accept a Neo Pulse handover request Source: https://docs.neoagent.io/api-reference/handover/accept-a-neo-pulse-handover-request https://api.neoagent.io/public-api/openapi.json post /public-api/handover-requests/{request_id}/accept A technician accepts a pending end-user→technician handover. Flips the request to accepted, DMs the tech the tracking ticket, notifies the other technicians, and opens the cross-tenant tech↔end-user group chat. Returns 200 with `status` (`accepted` / `already_taken` / `expired` / `not_found`) — these are outcomes the caller renders onto the card, not transport errors. # List active announcements Source: https://docs.neoagent.io/api-reference/inbox-&-comms/list-active-announcements https://api.neoagent.io/public-api/openapi.json get /public-api/announcements Announcements active for the tenant. # List inbox messages Source: https://docs.neoagent.io/api-reference/inbox-&-comms/list-inbox-messages https://api.neoagent.io/public-api/openapi.json get /public-api/inbox Inbox messages for the tenant, most recently updated first. `updated_at` is when the message last recurred or was resolved; marking it read does not change it. # Mark an inbox message as read Source: https://docs.neoagent.io/api-reference/inbox-&-comms/mark-an-inbox-message-as-read https://api.neoagent.io/public-api/openapi.json post /public-api/inbox/{deduplication_message_id}/read # Insights presets — suggested region, period options, trial state Source: https://docs.neoagent.io/api-reference/insights/insights-presets-—-suggested-region-period-options-trial-state https://api.neoagent.io/public-api/openapi.json get /public-api/insights/defaults Region defaults (hourly rate + currency), available `period_days` options, the tenant's trial state, and current PSA-sync status (so callers don't kick off an analysis while a sync is still running). # Latest analysis status Source: https://docs.neoagent.io/api-reference/insights/latest-analysis-status https://api.neoagent.io/public-api/openapi.json get /public-api/insights/status Status of the most recent analysis on the tenant. Returns `{status: null}` when nothing has run. # Latest completed analysis Source: https://docs.neoagent.io/api-reference/insights/latest-completed-analysis https://api.neoagent.io/public-api/openapi.json get /public-api/insights/result Latest *completed* analysis with the full ROI payload (`result` is an opaque blob — render verbatim). `currency` is the lowercase ISO code the money figures are in, null for an analysis priced before it was recorded. 404 if nothing has completed yet. # Start an Insights analysis Source: https://docs.neoagent.io/api-reference/insights/start-an-insights-analysis https://api.neoagent.io/public-api/openapi.json post /public-api/insights/analyze Async. Queues a Temporal workflow that classifies the tenant's recent tickets and computes ROI. Returns 202 with `{analysis_id, status: PENDING}`; poll `/insights/status` for progress and `/insights/result` for the completed output. 409 if an analysis is already running or a PSA sync is in progress. Trial accounts are capped to 25 completed analyses. `hourly_rate` is the MSP's customer-facing ticket-handling rate (drives ROI dollars) — not Neo's LLM cost. `currency` is its lowercase ISO code (`usd`, `eur`, `gbp`, `cad`, `aud`); without it the currency follows `currency_symbol`. # Ask Neo to build an integration Source: https://docs.neoagent.io/api-reference/integrations/ask-neo-to-build-an-integration https://api.neoagent.io/public-api/openapi.json post /public-api/integrations/requests Asks Neo to build a native integration with a vendor that `GET /integrations` does not list. Neo's team reviews every request. When the vendor has a usable API, Neo builds it as a new tile on the Integrations page within 5 working days. A tenant may send 5 requests in any 7 days; the sixth returns `429 rate_limited`. # Auto-map technicians to their Microsoft user Source: https://docs.neoagent.io/api-reference/integrations/auto-map-technicians-to-their-microsoft-user https://api.neoagent.io/public-api/openapi.json post /public-api/teams-availability/auto-map Matches configured technician profiles to their Microsoft Entra identity by email/UPN against the members of every Team in the tenant and persists each match. Returns 400 when no technician profiles are configured. Takes no body. Manual mappings set on the Profiles tab are never overwritten. Always requires technician approval via NEO_API_REQUEST (rewrites who dispatch reads presence for). # Disconnect an integration Source: https://docs.neoagent.io/api-reference/integrations/disconnect-an-integration https://api.neoagent.io/public-api/openapi.json post /public-api/integrations/{name}/disconnect Dashboard-only in v1 — returns 501 with a pointer to the dashboard URL. Always requires technician approval once implemented (severs the PSA/M365/RMM link). # Get an integration Source: https://docs.neoagent.io/api-reference/integrations/get-an-integration https://api.neoagent.io/public-api/openapi.json get /public-api/integrations/{name} One integration with connection state and latest sync row. Returns `404 unknown_integration` if the name isn't in the canonical registry. # Get an integration's connect instructions Source: https://docs.neoagent.io/api-reference/integrations/get-an-integrations-connect-instructions https://api.neoagent.io/public-api/openapi.json post /public-api/integrations/{name}/connect-url Returns dashboard instructions for connecting the integration. v1 does not synthesize OAuth consent URLs — the dashboard owns those flows for every integration. # Get company-filter options Source: https://docs.neoagent.io/api-reference/integrations/get-company-filter-options https://api.neoagent.io/public-api/openapi.json get /public-api/company-filters/options The available filter dimensions and their selectable values: Active/Inactive for the active dimension, the tenant's own company account types, and — ConnectWise only — the tenant's own raw company-status names. # Get company filters Source: https://docs.neoagent.io/api-reference/integrations/get-company-filters https://api.neoagent.io/public-api/openapi.json get /public-api/company-filters The tenant's effective company filters — which PSA companies Neo tracks in its company directory. Returns the saved filters, or the default (Active + Customer) when none are set. # Get documentation storage usage against the plan allowance Source: https://docs.neoagent.io/api-reference/integrations/get-documentation-storage-usage-against-the-plan-allowance https://api.neoagent.io/public-api/openapi.json get /public-api/documentation/quota How much documentation Neo has indexed for the tenant, across every connected documentation platform (IT Glue, Hudu, Lexful, Confluence, SharePoint), against the allowance included in the tenant's plan. Counted in indexed chunks and also given in gigabytes of Neo's search index, which is a different quantity from the size of the tenant's own document libraries. `limit_chunks` is null when the workspace has no paid plan. `enforced` says whether a sync stops adding new documents once usage reaches the allowance; a run already in progress finishes what it has started, so usage can end above it. Documents already indexed keep updating either way. Returns 503 when the count cannot be read. # Get the Teams availability admin-consent URL Source: https://docs.neoagent.io/api-reference/integrations/get-the-teams-availability-admin-consent-url https://api.neoagent.io/public-api/openapi.json get /public-api/teams-availability/consent-url Builds the own-tenant admin-consent URL for the 'Microsoft Teams — Technician Mapping' integration. An M365 admin of the MSP's own tenant opens it to grant the read-only presence/shifts/group scopes, after which teams can be listed and technicians auto-mapped. # Get the tenant's ConnectWise customer-reply policy Source: https://docs.neoagent.io/api-reference/integrations/get-the-tenants-connectwise-customer-reply-policy https://api.neoagent.io/public-api/openapi.json get /public-api/integrations/customer-reply-policy Whether a ConnectWise reply from a sender ConnectWise holds as neither a contact nor a member fires the **Customer replied** trigger, and which senders never count. `allow_unregistered_contact_replies` is the **Replies from unregistered contacts** switch, off by default; `excluded_senders` is its exceptions list, consulted only while the switch is on. Both settings are account-wide: they apply to every ConnectWise agent and workflow on the tenant. Change it with `PUT` on the same path, or on the dashboard: an agent's **Triggers & Filters** tab or a workflow's **Schedule/Select** step, a **Customer replied** trigger condition, then **Configure** on the line below the conditions. There is no control for it on the ConnectWise integration page. Returns `404 integration_not_connected` when the tenant's connected PSA is not ConnectWise. # Get the tenant's ticket board/queue sync filter Source: https://docs.neoagent.io/api-reference/integrations/get-the-tenants-ticket-boardqueue-sync-filter https://api.neoagent.io/public-api/openapi.json get /public-api/integrations/ticket-sync-filter Which boards or queues Neo accepts tickets from, for the tenant's own PSA — a ConnectWise board, an Autotask queue, a HaloPSA ticket type, a ServiceNow assignment group. Read-only; the filter is edited on the dashboard's **Integrations → PSA Filters** card, where saving an added board also backfills that board's historical tickets. Neo evaluates this filter on every inbound ticket webhook and drops the ones it rejects **before writing any callback record**, so a ticket on a rejected board starts no agent and returns nothing from `GET /public-api/callbacks`. Read this filter before reading an empty callback history as the PSA not having sent the event. `active` is false when no board filter applies. `selected_options` is the accepted set under `include` and the rejected set under `exclude`; it carries the boards as the tenant saved them, and Neo matches a callback on the board id, not the name. Returns `404 integration_not_connected` when no PSA is connected. # Get the tenant's ticket-relay policy Source: https://docs.neoagent.io/api-reference/integrations/get-the-tenants-ticket-relay-policy https://api.neoagent.io/public-api/openapi.json get /public-api/integrations/relay-policy Which ticket entries the white-label end-user Teams bot relays back to an employee, for the tenant's own PSA. Read-only — the policy is edited on the dashboard's **Microsoft Teams — End-user Chat Bot** integration card. `relay_policy` is what this tenant's relay applies; `default_relay_policy` is what a tenant connecting the same PSA today would start from, and `differs_from_default` names every field where the two disagree. They can disagree: saved settings are never rewritten when a default moves, so a long-standing tenant keeps a value the product documentation no longer describes. Returns `404 integration_not_connected` when no PSA is connected. # List integration sync runs Source: https://docs.neoagent.io/api-reference/integrations/list-integration-sync-runs https://api.neoagent.io/public-api/openapi.json get /public-api/integrations/{name}/sync-runs Sync history for one integration on the caller's tenant — per-activity counts and per-resource failures from `pipeline_runs.sync_details`. Use when an MSP asks "I created X in PSA, where is it?": a recent successful run with empty failures means watermark-or-cadence latency; a run with failures on a specific resource means a real per-type problem. Default window is the last 30 days; max window is 30 days. Returns 404 `unknown_integration` for an unrecognised name, `integration_not_connected` if the tenant doesn't have it configured, and `integration_does_not_sync` for connected integrations that don't run scheduled syncs. # List integrations Source: https://docs.neoagent.io/api-reference/integrations/list-integrations https://api.neoagent.io/public-api/openapi.json get /public-api/integrations Every integration Neo supports with its current connection state for the tenant, plus `last_sync_at` / `last_sync_status` projected from `pipeline_runs`. Integrations that don't sync (e.g. ScalePad) return `null` for both last-sync fields. Each RMM vendor is its own row with an independent `connected` flag and per-vendor last-sync — a tenant can have several RMMs connected simultaneously. # List the MSP tenant's Teams Source: https://docs.neoagent.io/api-reference/integrations/list-the-msp-tenants-teams https://api.neoagent.io/public-api/openapi.json get /public-api/teams-availability/teams Lists the Microsoft Teams in the MSP's own tenant for the optional Shifts rota picker. Auto-map always scans every Team. Requires admin consent: a tenant that has not granted it gets 403 `insufficient_scope`, and an upstream Microsoft Graph or token failure gets 502. # Remove companies that no longer match Source: https://docs.neoagent.io/api-reference/integrations/remove-companies-that-no-longer-match https://api.neoagent.io/public-api/openapi.json post /public-api/company-filters/remove-unmatched Durably remove the tracked companies that no longer fit the current company filters. Idempotent; returns the number removed. # Update company filters Source: https://docs.neoagent.io/api-reference/integrations/update-company-filters https://api.neoagent.io/public-api/openapi.json put /public-api/company-filters Replace the company filters. Widening-only: newly in-scope companies are added immediately; the response previews the companies that no longer fit, which you remove via the remove-unmatched endpoint. # Update the tenant's ConnectWise customer-reply policy Source: https://docs.neoagent.io/api-reference/integrations/update-the-tenants-connectwise-customer-reply-policy https://api.neoagent.io/public-api/openapi.json put /public-api/integrations/customer-reply-policy Change the **Replies from unregistered contacts** switch, its exceptions list, or both. Partial: a field you leave out keeps its stored value. `excluded_senders` replaces the whole list, so send every entry to keep. An entry containing `@` matches the full address; anything else matches the whole domain. The change is account-wide; Neo applies it when it processes a reply, so a reply it already skipped does not run again. Turning the switch on also lets third-party mail on a ticket, such as a vendor's auto-acknowledgement, count as a customer reply; add those senders to `excluded_senders`. Returns the stored policy. `400` on an unknown field or an empty body; `404 integration_not_connected` when the tenant's connected PSA is not ConnectWise. # Create an intent Source: https://docs.neoagent.io/api-reference/intents/create-an-intent https://api.neoagent.io/public-api/openapi.json post /public-api/intents A curated request type — a menu name/description plus its intake: the free-text `ask_for` script, a typed `fields` form schema, or both. A non-empty `fields` makes the intent structured, so a chat surface renders it as a form (dropdowns, dates, toggles) instead of asking in prose; `ask_for` remains the intake everywhere a form cannot render, notably the TRIGGERED (ticket/email) surface. `surfaces` (END_USER_CHAT | MSP_CHAT | TRIGGERED, at least one) declares which agent kinds it runs on; every assigned `agent_id` must be valid for one of them (an end-user chat agent for END_USER_CHAT, an internal/MSP chat agent for MSP_CHAT, a ticket-triggered agent for TRIGGERED). Empty `agent_ids` applies it to all agents of the surface — except a Neo-managed agent, which applies only when named — and empty `end_company_ids` to all companies. MSP_CHAT sessions carry no end-company, so that surface offers only intents with an empty `end_company_ids`; a company-scoped intent still runs on its other surfaces. An enabled intent is capped at 40 per applicable agent. The agent picks an intent on its `name` and `description`; an enabled intent's `description` is at most 500 characters. Needs a caller whose role may author agents; a Viewer, or a person with no dashboard account, gets 403 `insufficient_scope`. # Delete an intent Source: https://docs.neoagent.io/api-reference/intents/delete-an-intent https://api.neoagent.io/public-api/openapi.json delete /public-api/intents/{intent_id} Soft-deletes the intent. Needs a caller whose role may author agents; a Viewer, or a person with no dashboard account, gets 403 `insufficient_scope`. # Get an intent Source: https://docs.neoagent.io/api-reference/intents/get-an-intent https://api.neoagent.io/public-api/openapi.json get /public-api/intents/{intent_id} # List intents Source: https://docs.neoagent.io/api-reference/intents/list-intents https://api.neoagent.io/public-api/openapi.json get /public-api/intents Every non-deleted intent for the tenant (enabled or not). # Update an intent Source: https://docs.neoagent.io/api-reference/intents/update-an-intent https://api.neoagent.io/public-api/openapi.json put /public-api/intents/{intent_id} Full replace of every editable field. Disabling is always allowed; re-enabling re-checks the 40-per-agent cap. Needs a caller whose role may author agents; a Viewer, or a person with no dashboard account, gets 403 `insufficient_scope`. # Accept an email invitation Source: https://docs.neoagent.io/api-reference/memberships/accept-an-email-invitation https://api.neoagent.io/public-api/openapi.json post /public-api/invitations/accept Binds the single-use invitation to the verified Microsoft identity. Requires the emailed token and matching sign-in email. Expired, cancelled and consumed invitations are rejected. Ignores X-Client-Id. API keys are denied. # Cancel a pending invitation Source: https://docs.neoagent.io/api-reference/memberships/cancel-a-pending-invitation https://api.neoagent.io/public-api/openapi.json delete /public-api/memberships/invitations Cancels a pending invitation by email in the selected workspace, including invitations without a Microsoft object ID. Only owners can cancel OWNER invitations. Returns 409 when no cancellable pending invitation exists; active memberships are unchanged. # Invite a workspace member Source: https://docs.neoagent.io/api-reference/memberships/invite-a-workspace-member https://api.neoagent.io/public-api/openapi.json post /public-api/memberships Invite by name, email and role. Sends a single-use email link valid for seven days; the recipient signs in with the invited Microsoft work account to accept. Only owners can grant OWNER. Optional directory and object IDs preserve the legacy explicit-identity flow, which sends no email. `CHAT_ONLY` creates an active membership that can be named in a chat agent's Specific people list but cannot sign in to the dashboard; it sends no email and requires the directory and object IDs. # List my workspaces Source: https://docs.neoagent.io/api-reference/memberships/list-my-workspaces https://api.neoagent.io/public-api/openapi.json get /public-api/me/workspaces Active memberships for the signed-in work or school Microsoft identity. Personal accounts are denied. Ignores X-Client-Id. API keys cannot discover other workspaces. # List workspace members Source: https://docs.neoagent.io/api-reference/memberships/list-workspace-members https://api.neoagent.io/public-api/openapi.json get /public-api/memberships Everyone who holds a membership in this workspace, with their role, status and `last_active_at` — the access-review list. Open to a tenant API key so an MSP can script it, and to signed-in Microsoft workspace admins. A non-admin dashboard user is denied, as is a key acting on behalf of a non-admin. `last_active_at` is when that person's dashboard session last reached Neo, refreshed at most once every ten minutes, so it can sit up to ten minutes behind the real request. It is null when Neo holds no activity for that person: nobody has used the membership since Neo started recording this, or they never sign in at all, which is the case for a Chat only member. Read null on a long-standing membership as unknown, not as dormant. Neo records no sign-in event, so it measures use, not login. `all_workflows_access` is true when that person reaches every agent and workflow in the workspace without a per-agent share; an admin reaches everything through their role and reads false. Administering memberships still requires a signed-in admin. # Preview an email invitation Source: https://docs.neoagent.io/api-reference/memberships/preview-an-email-invitation https://api.neoagent.io/public-api/openapi.json post /public-api/invitations/preview Requires the emailed token and the invited Microsoft work account. Ignores X-Client-Id; no existing workspace membership is required. Does not accept the invitation. API keys are denied. # Resend a pending email invitation Source: https://docs.neoagent.io/api-reference/memberships/resend-a-pending-email-invitation https://api.neoagent.io/public-api/openapi.json post /public-api/memberships/invitations/resend Workspace admins only; owners only for OWNER invitations. Rotates the link and expiry. Previous links stop working. Active and inactive memberships cannot be resent. API keys are denied. # Revoke a workspace membership Source: https://docs.neoagent.io/api-reference/memberships/revoke-a-workspace-membership https://api.neoagent.io/public-api/openapi.json delete /public-api/memberships/{user_id} Disables the member in this workspace. Other workspaces remain unchanged. Cannot remove the last owner. # Create an agent memory Source: https://docs.neoagent.io/api-reference/memories/create-an-agent-memory https://api.neoagent.io/public-api/openapi.json post /public-api/memories Author a manual memory. `CLIENT` memories are scoped to the caller's tenant; `END_CLIENT` memories require `scope_id` (the end-client company id). Set `pinned: true` to create-and-pin in one call — required for standing instructions that must apply on every run (unpinned memories only surface via on-demand recall). When the scope's pin cap is full the memory is still created and the call returns 409 (`memory_pin_limit_exceeded`); curate pins, then `POST /memories/<id>/pin`. Set `restricted_to_agent_ids` to limit the memory to those agents (ids from `GET /agents`); each must be an agent of your tenant that reads on one of `audiences`, or the call returns 400. Content that already exists confirms that memory and keeps its targeting; supersede it to change the targeting. A classic workflow is never an agent, so a restricted memory leaves every classic workflow's Smart Actions. Tenant-admin only: a non-admin dashboard user or on-behalf-of end user gets 403 (`insufficient_scope`). Requires technician approval when reached via `NEO_API_REQUEST`. # Get an agent memory Source: https://docs.neoagent.io/api-reference/memories/get-an-agent-memory https://api.neoagent.io/public-api/openapi.json get /public-api/memories/{memory_id} # List agent memories Source: https://docs.neoagent.io/api-reference/memories/list-agent-memories https://api.neoagent.io/public-api/openapi.json get /public-api/memories The tenant's durable agent memories — the facts and playbooks recall injects into agent runs. Offset-paginated; returns the page plus a total and facet counts for the current filter. # Pin an agent memory Source: https://docs.neoagent.io/api-reference/memories/pin-an-agent-memory https://api.neoagent.io/public-api/openapi.json post /public-api/memories/{memory_id}/pin Pin a memory so it bypasses decay and is always injected. Subject to per-scope pin caps (409 when full). Tenant-admin only (403 `insufficient_scope` otherwise). # Restore an agent memory Source: https://docs.neoagent.io/api-reference/memories/restore-an-agent-memory https://api.neoagent.io/public-api/openapi.json post /public-api/memories/{memory_id}/restore Bring a soft-deleted memory back into recall. A memory pinned when deleted is restored unpinned if the scope's pin cap is now full. Tenant-admin only (403 `insufficient_scope` otherwise). # Soft-delete an agent memory Source: https://docs.neoagent.io/api-reference/memories/soft-delete-an-agent-memory https://api.neoagent.io/public-api/openapi.json delete /public-api/memories/{memory_id} Excludes the memory from recall (restorable). Tenant-admin only (403 `insufficient_scope` otherwise). Always requires technician approval when reached via `NEO_API_REQUEST`. # Soft-delete several agent memories Source: https://docs.neoagent.io/api-reference/memories/soft-delete-several-agent-memories https://api.neoagent.io/public-api/openapi.json post /public-api/memories/bulk-delete Soft-deletes every listed memory id (1-500) in one call. Each memory stays restorable through `POST /memories/<id>/restore`. `deleted_ids` lists what this call deleted; `skipped_ids` lists ids that matched no live memory (unknown, or already deleted). Tenant-admin only (403 `insufficient_scope` otherwise). Always requires technician approval when reached via `NEO_API_REQUEST`, one approval for the whole list. # Supersede an agent memory Source: https://docs.neoagent.io/api-reference/memories/supersede-an-agent-memory https://api.neoagent.io/public-api/openapi.json post /public-api/memories/{memory_id}/supersede Replace a memory's content within its own scope/category, preserving surface targeting unless re-tagged. `restricted_to_agent_ids`: omit to keep the agent restriction, send a list of agent ids to replace it, or `[]` to let every agent read the memory again. The ids are validated as on create. Widening the restriction of a pinned memory returns 409 (`memory_pin_limit_exceeded`) when a newly reached agent has no pin room. Tenant-admin only (403 `insufficient_scope` otherwise). Always requires technician approval when reached via `NEO_API_REQUEST`. # Unpin an agent memory Source: https://docs.neoagent.io/api-reference/memories/unpin-an-agent-memory https://api.neoagent.io/public-api/openapi.json post /public-api/memories/{memory_id}/unpin Remove a pin; the memory resumes normal decay-based ranking. Tenant-admin only (403 `insufficient_scope` otherwise). # Liveness probe Source: https://docs.neoagent.io/api-reference/meta/liveness-probe https://api.neoagent.io/public-api/openapi.json get /public-api/health Returns `{"status": "ok"}`. No authentication required. # OpenAPI 3.1 document Source: https://docs.neoagent.io/api-reference/meta/openapi-31-document https://api.neoagent.io/public-api/openapi.json get /public-api/openapi.json This document. No authentication required. # Callback-processing funnel Source: https://docs.neoagent.io/api-reference/observability/callback-processing-funnel https://api.neoagent.io/public-api/openapi.json get /public-api/observability/callback-funnel End-to-end pipeline metrics for the caller's tenant — webhook receipt → concurrency cap → event processing → workflow execution → PSA API calls. Drives the `investigate-processing-performance` discipline: durations, counts, and ratios only. **Never** returns LLM / provider cost (token spend, $) — customer-facing credits exposure is on the billing endpoints, not here. Default window 24h; max 7d. # Per-agent performance breakdown Source: https://docs.neoagent.io/api-reference/observability/per-agent-performance-breakdown https://api.neoagent.io/public-api/openapi.json get /public-api/observability/workflow-performance Per-agent execution stats once the funnel points at a slow agent — durations (p95 total / actual / overhead), LLM call counts by purpose, PSA call count. **No cost fields.** Optional `agent_id` narrows to one agent. # Assign an organization administrator Source: https://docs.neoagent.io/api-reference/organizations/assign-an-organization-administrator https://api.neoagent.io/public-api/openapi.json put /public-api/organizations/{organization_id}/members Requires a signed-in Microsoft organization administrator. Organization owners manage administrators. API keys cannot administer organizations. Workspace data access requires an explicit membership. Creation uses request_id for idempotency and requires separate billing. # Connect my Microsoft directory Source: https://docs.neoagent.io/api-reference/organizations/connect-my-microsoft-directory https://api.neoagent.io/public-api/openapi.json post /public-api/workspace-directory Workspace owners only. Uses the verified sign-in directory and accepts no caller-supplied directory ID. Cannot replace an existing connection. # Create a subsidiary workspace Source: https://docs.neoagent.io/api-reference/organizations/create-a-subsidiary-workspace https://api.neoagent.io/public-api/openapi.json post /public-api/organizations/{organization_id}/workspaces Requires a signed-in Microsoft organization administrator. Organization owners manage administrators. API keys cannot administer organizations. Workspace data access requires an explicit membership. Creation uses request_id for idempotency and requires separate billing. `name` is the human-friendly workspace name; `client_name` is its unique lowercase id (letters, digits and hyphens), derived from the name when omitted. A taken id returns 409. `owner_emails` (optional, at most 10) gives each address an OWNER invitation to the new workspace, valid for seven days, and queues its email; a person who gets no email is invited again from Users; the creator's own address is skipped. Each invitation's result is in `owner_invitations`: `INVITED` (saved, email queued), `ALREADY_MEMBER` (also what a replay of the same request_id reports, with no second email) or `FAILED` with a `message`. A failed invitation never fails the creation. # Get organization administration details Source: https://docs.neoagent.io/api-reference/organizations/get-organization-administration-details https://api.neoagent.io/public-api/openapi.json get /public-api/organizations/{organization_id} Requires a signed-in Microsoft organization administrator. Organization owners manage administrators. API keys cannot administer organizations. Workspace data access requires an explicit membership. Creation uses request_id for idempotency and requires separate billing. # Get this workspace's organization Source: https://docs.neoagent.io/api-reference/organizations/get-this-workspaces-organization https://api.neoagent.io/public-api/openapi.json get /public-api/organizations/current Returns only the current workspace's parent organization; a signed-in user reads the workspace in X-Client-Id. Does not grant access to sibling workspaces. Organization administration routes accept only this organization's id. # Get workspace Microsoft directory Source: https://docs.neoagent.io/api-reference/organizations/get-workspace-microsoft-directory https://api.neoagent.io/public-api/openapi.json get /public-api/workspace-directory Requires explicit workspace membership. Available during billing setup. # Grant explicit workspace access Source: https://docs.neoagent.io/api-reference/organizations/grant-explicit-workspace-access https://api.neoagent.io/public-api/openapi.json post /public-api/organizations/{organization_id}/workspaces/{client_id}/access Requires a signed-in Microsoft organization administrator. Organization owners manage administrators. API keys cannot administer organizations. Workspace data access requires an explicit membership. Creation uses request_id for idempotency and requires separate billing. # Rename an organization Source: https://docs.neoagent.io/api-reference/organizations/rename-an-organization https://api.neoagent.io/public-api/openapi.json patch /public-api/organizations/{organization_id} Requires a signed-in Microsoft organization administrator. Organization owners manage administrators. API keys cannot administer organizations. Workspace data access requires an explicit membership. Creation uses request_id for idempotency and requires separate billing. # Revoke organization administration Source: https://docs.neoagent.io/api-reference/organizations/revoke-organization-administration https://api.neoagent.io/public-api/openapi.json delete /public-api/organizations/{organization_id}/members Requires a signed-in Microsoft organization administrator. Organization owners manage administrators. API keys cannot administer organizations. Workspace data access requires an explicit membership. Creation uses request_id for idempotency and requires separate billing. # Aggregate chat-agent cost + usage for a date window Source: https://docs.neoagent.io/api-reference/performance/aggregate-chat-agent-cost-+-usage-for-a-date-window https://api.neoagent.io/public-api/openapi.json get /public-api/performance/chat/summary Conversational-agent totals: credits consumed, turns (messages), sessions, and active agents. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Aggregate execution stats for a date window Source: https://docs.neoagent.io/api-reference/performance/aggregate-execution-stats-for-a-date-window https://api.neoagent.io/public-api/openapi.json get /public-api/performance/summary Tenant-scoped totals: executions by status, hours saved, credits consumed. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. `total_tickets_received` counts PSA activity, which is not per-agent, so it is not scoped that way; it is kept for the current and at least the previous calendar month, so for an older `from` it covers only the retained part of the window. `earliest_execution_at` is the date of the first finished execution among those agents. Every execution window (`/performance/summary`, `/performance/workflows`, `/performance/timeline`, `/performance/ticket-coverage` and `/performance/categories`) starts no earlier than 2026-04-06, the day time-saved reporting begins, so credits and hours saved cover the same days; the `/performance/chat/*` endpoints keep the window they are sent: `window_start` is the ISO-8601 timestamp the figures count from, and `window_clamped` is true when `from` was moved up to it. A window that ends on or before 2026-04-06 is a 400. `credits_cost` is what the credits cost at the tenant's price per credit, in the billing currency. `labor_value_saved` prices the hours saved at the tenant's cost per technician hour, or at the typical rate for their region until an admin sets one (`source`). Hours saved are estimates, so their value is one too. `fx` converts `credits_cost` into the currency of `labor_value_saved` when the two differ. # Chat credits / turns over time Source: https://docs.neoagent.io/api-reference/performance/chat-credits-turns-over-time https://api.neoagent.io/public-api/openapi.json get /public-api/performance/chat/timeline Time-bucketed chat credits + turns at day / week / month granularity. Every bucket from the first turn in the window to `to`, or to the current bucket when `to` is later, is returned, so a quiet bucket reads 0 and is never left out. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Execution volume / hours saved over time Source: https://docs.neoagent.io/api-reference/performance/execution-volume-hours-saved-over-time https://api.neoagent.io/public-api/openapi.json get /public-api/performance/timeline Time-bucketed rollup at day / week / month granularity. Every bucket from the first execution in the window to `to`, or to the current bucket when `to` is later, is returned, so a quiet bucket reads 0 and is never left out. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Per-agent chat cost + usage for a date window Source: https://docs.neoagent.io/api-reference/performance/per-agent-chat-cost-+-usage-for-a-date-window https://api.neoagent.io/public-api/openapi.json get /public-api/performance/chat/by-agent One row per chat agent that ran in the window. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Per-agent execution stats for a date window Source: https://docs.neoagent.io/api-reference/performance/per-agent-execution-stats-for-a-date-window https://api.neoagent.io/public-api/openapi.json get /public-api/performance/workflows One row per agent with executions, hours saved or credits in the window. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. `credits_cost`, `labor_value_saved` and `fx` price each row as on `/performance/summary`. # Per-category execution stats Source: https://docs.neoagent.io/api-reference/performance/per-category-execution-stats https://api.neoagent.io/public-api/openapi.json get /public-api/performance/categories Execution quality by classifier category (success rate, fully-resolved counts, hours saved, minutes saved per run, credits, average run time). Credits count only categorized runs, so chat turns and uncategorized runs are absent from these rows. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Per-tool chat usage + cost for a date window Source: https://docs.neoagent.io/api-reference/performance/per-tool-chat-usage-+-cost-for-a-date-window https://api.neoagent.io/public-api/openapi.json get /public-api/performance/chat/tools Which tools the chat agents called, how often, and the credits those calls billed; `is_free` marks FREE-tier plumbing tools. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Per-user chat cost + usage for a date window Source: https://docs.neoagent.io/api-reference/performance/per-user-chat-cost-+-usage-for-a-date-window https://api.neoagent.io/public-api/openapi.json get /public-api/performance/chat/by-user Chat cost + usage attributed per user (technician for MSP agents), per session — 1:1 chats exact, group sessions attributed to the first speaker. Counts only the agents the caller can view, in the current environment: an API key with no acting user or an OWNER/ADMIN sees every agent of the tenant, a USER or VIEWER only the agents they created or were shared. # Tickets received vs. handled by Neo over time Source: https://docs.neoagent.io/api-reference/performance/tickets-received-vs-handled-by-neo-over-time https://api.neoagent.io/public-api/openapi.json get /public-api/performance/ticket-coverage Time-bucketed coverage. `total_tickets` is the distinct tickets with at least one PSA event (for example a create or update) in the bucket. `neo_handled_tickets` is how many of those tickets had a finished Neo execution in the same bucket, so it never exceeds `total_tickets`. PSA activity is kept for the current and at least the previous calendar month: buckets start at that retention start even when `from` is earlier, and every bucket from there to `to`, or to the current bucket when `to` is later, is returned (a bucket with no activity reads 0). `neo_handled_tickets` counts only the agents the caller can view, in the current environment. With `bucket=week` the series starts at the first whole week after the retention start. For execution history older than that, use `/performance/timeline`. # Change a number's after-hours instructions and business hours Source: https://docs.neoagent.io/api-reference/phone-agent/change-a-numbers-after-hours-instructions-and-business-hours https://api.neoagent.io/public-api/openapi.json patch /public-api/phone/numbers/{number} Partial patch of two settings of one number the tenant still holds, given in E.164 (`+15550100000`; the `+` may be left out). A field left out keeps its stored value. `after_hours_instructions` replace the number's custom instructions on calls that start outside business hours, on a non-work day or on a holiday; null or an empty string turns them off. `business_hours.override` sets the number's own work days and one window (`HH:MM`, in the tenant's time zone, not past midnight); null returns to the tenant's business hours from Settings, Monday to Friday. `business_hours.holiday_source` is `COUNTRY` (the default: public holidays of the number's country, England for UK numbers) or `NONE`. Any other field is rejected with 400; change the other settings in the dashboard. Returns the updated number. 404 `phone_number_not_found` for a number the tenant does not hold. # List Phone Agent calls Source: https://docs.neoagent.io/api-reference/phone-agent/list-phone-agent-calls https://api.neoagent.io/public-api/openapi.json get /public-api/phone/calls Recent calls the Phone Agent handled. Each call carries `tickets`, the tickets it created (`relation` is `CREATED_IN_CALL` for the agent's tool during the call or `CREATED_POST_CALL` for the post-call fallback; `url` is the PSA link when one exists), and `transferred_to`/`transferred_at` when the agent handed the caller to another number. Both are filled a minute or two after the call ends; `tickets` is `[]` when the call created none and null when the outcome was never recorded (a live call, or a call from before September 2026). Recording binaries are deliberately not exposed here — those are gated behind dashboard auth and the recording-retention policy. # List Phone Agent numbers Source: https://docs.neoagent.io/api-reference/phone-agent/list-phone-agent-numbers https://api.neoagent.io/public-api/openapi.json get /public-api/phone/numbers Phone numbers wired into the tenant's Phone Agent. `psa_settings` and `agent_settings` are returned as opaque JSON (the inner shapes are tenant-curated and not part of the public contract — edit them in the dashboard). `agent_settings.after_hours_instructions` and `agent_settings.business_hours` are the settings `PATCH /phone/numbers/<number>` changes. `agent_settings.attached_memory_ids` lists the MSP-wide memories attached to the number, in the order the agent reads them on every call, leaving out one that was deleted and any that no longer fits the 4,000-character total. A call follows each memory to its newest edit, so an id here can be an older version of the memory it uses. Attach memories in the dashboard; no public route writes them. # Get an RMM script execution Source: https://docs.neoagent.io/api-reference/rmm-scripts/get-an-rmm-script-execution https://api.neoagent.io/public-api/openapi.json get /public-api/rmm-script-executions/{execution_id} Includes the rendered script content for Neo dynamic scripts. A nightly job deletes a rendered script once it is 30 days old, and `rendered_script` is null after that. # List RMM script executions Source: https://docs.neoagent.io/api-reference/rmm-scripts/list-rmm-script-executions https://api.neoagent.io/public-api/openapi.json get /public-api/rmm-script-executions `rmm_vendor` names which connected RMM each script was dispatched to — a tenant can have several RMMs connected at once; null on legacy executions recorded before vendor stamping. # Cancel a scheduled-work entry Source: https://docs.neoagent.io/api-reference/scheduled-work/cancel-a-scheduled-work-entry https://api.neoagent.io/public-api/openapi.json post /public-api/scheduled-work/{scheduled_work_id}/cancel Cancels a PENDING entry. Already-non-PENDING entries return 409. # Get a scheduled-work entry Source: https://docs.neoagent.io/api-reference/scheduled-work/get-a-scheduled-work-entry https://api.neoagent.io/public-api/openapi.json get /public-api/scheduled-work/{scheduled_work_id} # List scheduled work Source: https://docs.neoagent.io/api-reference/scheduled-work/list-scheduled-work https://api.neoagent.io/public-api/openapi.json get /public-api/scheduled-work Scheduled work entries for the tenant. # Schedule work Source: https://docs.neoagent.io/api-reference/scheduled-work/schedule-work https://api.neoagent.io/public-api/openapi.json post /public-api/scheduled-work Schedules an enabled TRIGGERED agent to run at a future time. `scheduled_for` must be in the future. # Update a scheduled-work entry Source: https://docs.neoagent.io/api-reference/scheduled-work/update-a-scheduled-work-entry https://api.neoagent.io/public-api/openapi.json patch /public-api/scheduled-work/{scheduled_work_id} Reschedule or change instructions. Only PENDING entries can be updated. # Action-type schema catalog Source: https://docs.neoagent.io/api-reference/schemas/action-type-schema-catalog https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/actions # Agent-integration schema catalog Source: https://docs.neoagent.io/api-reference/schemas/agent-integration-schema-catalog https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/agent-integrations The permission matrix per integration. The full catalog is ~300 KB, so scope it: `?view=index` lists every key with its permission-group names (~11 KB), and `?integration=<key>` returns one integration. An unknown key returns 400 `unknown_integration` with the index URL in `error.details`. This catalog is the same for every tenant; what a tenant has connected is `GET /public-api/integrations`, joined on `requires_integration.integration_id`. # Agent structural schema Source: https://docs.neoagent.io/api-reference/schemas/agent-structural-schema https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/agents The autonomy↔trigger↔entity matrix and per-rule list used by the server to validate `POST/PUT /public-api/agents`. Co-located with the validator — every shape rejected by the validator is described here so external writers can validate locally and skip the POST→400→fix loop. Stable `rules[].code` matches the `details.field_errors[].code` returned on 400. # Callback change-option catalog Source: https://docs.neoagent.io/api-reference/schemas/callback-change-option-catalog https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/callback-change-options # Custom-field-condition schema Source: https://docs.neoagent.io/api-reference/schemas/custom-field-condition-schema https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/custom-field-condition # Integrations schema catalog Source: https://docs.neoagent.io/api-reference/schemas/integrations-schema-catalog https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/integrations # Project-ticket-field schema (ConnectWise only) Source: https://docs.neoagent.io/api-reference/schemas/project-ticket-field-schema-connectwise-only https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/project_ticket # Queryable-entity options Source: https://docs.neoagent.io/api-reference/schemas/queryable-entity-options https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/entity-options With no `entity_name`, returns the manifest of queryable names. An unknown name returns 400 `invalid_entity_name` with the manifest URL in `error.details`. # Ticket-field schema Source: https://docs.neoagent.io/api-reference/schemas/ticket-field-schema https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/ticket # Time-entry-field schema Source: https://docs.neoagent.io/api-reference/schemas/time-entry-field-schema https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/time_entry # Tool catalog Source: https://docs.neoagent.io/api-reference/schemas/tool-catalog https://api.neoagent.io/public-api/openapi.json get /public-api/schemas/tools # Get tenant settings Source: https://docs.neoagent.io/api-reference/settings/get-tenant-settings https://api.neoagent.io/public-api/openapi.json get /public-api/settings A public projection of the tenant's settings (the Slack token / app id are omitted). # Get the agent credit spend notice settings Source: https://docs.neoagent.io/api-reference/settings/get-the-agent-credit-spend-notice-settings https://api.neoagent.io/public-api/openapi.json get /public-api/settings/spend-alerts Whether this tenant is emailed when one agent's daily credit spend jumps far past its own normal day, where that notice goes, and the optional per-agent daily credit budget that replaces the default detection. The notice goes to `emails`, plus the account's active owners and admins when `notify_admins` is true. Neo checks each agent's credits since 00:00 UTC every 10 minutes, so the email comes the same day, about 10 minutes after the agent goes over, and at most once per UTC day for each agent. Agents with an enabled credit alert rule are checked by their rule instead. Change these on the dashboard Settings page. # Get the cost of technician time Source: https://docs.neoagent.io/api-reference/settings/get-the-cost-of-technician-time https://api.neoagent.io/public-api/openapi.json get /public-api/settings/value The tenant's fully loaded cost per technician hour, which prices every hours-saved figure (`labor_value_saved` on `/performance/summary`). `source` is SET_BY_USER once an admin entered the tenant's own figure, else DEFAULT_BY_REGION with the typical rate for the tenant's region. The region default is always returned beside it. # Set the cost of technician time Source: https://docs.neoagent.io/api-reference/settings/set-the-cost-of-technician-time https://api.neoagent.io/public-api/openapi.json put /public-api/settings/value Store the tenant's fully loaded cost per technician hour: a technician's gross salary plus employer taxes, benefits and overhead, divided by hours worked. Admins and owners only (an API key with no acting user counts as the tenant). `hourly_cost` must be above 0 and at most 10,000; `currency` one of usd, eur, gbp, cad, aud. Returns the stored rate. # Tenant-settings JSON schema Source: https://docs.neoagent.io/api-reference/settings/tenant-settings-json-schema https://api.neoagent.io/public-api/openapi.json get /public-api/settings/schema The JSON schema of the settings object, for building editors. # Update tenant settings Source: https://docs.neoagent.io/api-reference/settings/update-tenant-settings https://api.neoagent.io/public-api/openapi.json put /public-api/settings Partial patch — only the fields present in the body are changed. Returns the updated settings. `data_residency` and `referral_code` are read-only: they are returned by GET but sending them is rejected. `timezone` must be an IANA zone name Neo supports, such as `America/New_York` or `Europe/London`; a name Neo cannot load is rejected with 400. Sending the timezone you already have stored is always accepted, and sending `null` clears it (Neo then reads your times as UTC). # Get a publicly shared agent Source: https://docs.neoagent.io/api-reference/sharing/get-a-publicly-shared-agent https://api.neoagent.io/public-api/openapi.json get /public-api/shared-agents/{share_token} Read-only public view of an agent/workflow shared via a 'Share Agent' link. No authentication — the opaque share token in the path is the credential. Returns the agent's name, prompt, triggers, filters and enabled tools, sanitized for public viewing (no tenant identity, usage, cost or integration permission detail). Returns 404 if the link is unknown or has been disabled. # Create a skill Source: https://docs.neoagent.io/api-reference/skills/create-a-skill https://api.neoagent.io/public-api/openapi.json post /public-api/skills Create a tenant skill from a full set of files. Must include a SKILL.md file. The slug is chosen here and is immutable after creation because it is the skill's agent lookup key and sandbox directory. If a live skill with the same slug already exists, returns 409 `skill_already_exists` with the existing skill's id in `error.details.existing_skill_id` — PUT/PATCH that id to update it. # Delete a skill Source: https://docs.neoagent.io/api-reference/skills/delete-a-skill https://api.neoagent.io/public-api/openapi.json delete /public-api/skills/{skill_id} Soft-delete the skill (sets deleted_at). File version history is retained. # Edit part of a skill's file Source: https://docs.neoagent.io/api-reference/skills/edit-part-of-a-skills-file https://api.neoagent.io/public-api/openapi.json patch /public-api/skills/{skill_id} Surgical search/replace edits to part of a file (the default for a tweak). Each edit must match exactly once unless replace_all is set; base_hash guards against concurrent writes. # Get a skill Source: https://docs.neoagent.io/api-reference/skills/get-a-skill https://api.neoagent.io/public-api/openapi.json get /public-api/skills/{skill_id} Read one skill whole — its files, each at its latest version. # Get a test run Source: https://docs.neoagent.io/api-reference/skills/get-a-test-run https://api.neoagent.io/public-api/openapi.json get /public-api/skills/{skill_id}/test-runs/{run_id} One recorded test run: the drafts that ran, the outcome, the failure reason, and the stdout/stderr tails. This is what Neo Support reads when asked to fix a skill after a failed run. # Get one version of a skill file Source: https://docs.neoagent.io/api-reference/skills/get-one-version-of-a-skill-file https://api.neoagent.io/public-api/openapi.json get /public-api/skills/{skill_id}/files/{file_path}/versions/{version} One historical version of a file, with its content. # List a skill's recent test runs Source: https://docs.neoagent.io/api-reference/skills/list-a-skills-recent-test-runs https://api.neoagent.io/public-api/openapi.json get /public-api/skills/{skill_id}/test-runs The 20 most recent test runs of the skill, newest first. # List the tenant's skills Source: https://docs.neoagent.io/api-reference/skills/list-the-tenants-skills https://api.neoagent.io/public-api/openapi.json get /public-api/skills The MSP's authored skills (metadata only). Read one whole with GET /skills/{skill_id}. # List the versions of a skill file Source: https://docs.neoagent.io/api-reference/skills/list-the-versions-of-a-skill-file https://api.neoagent.io/public-api/openapi.json get /public-api/skills/{skill_id}/files/{file_path}/versions Every saved version of one file (newest first), without content. `file_path` is the path inside the skill, e.g. `scripts/run.py`. To restore a version, read it with GET .../versions/{version} and PUT its content back — that writes a new version. # Replace whole files / update skill metadata Source: https://docs.neoagent.io/api-reference/skills/replace-whole-files-update-skill-metadata https://api.neoagent.io/public-api/openapi.json put /public-api/skills/{skill_id} Replace whole files (each gets a new version) and/or update the editable display name, description, or source-run provenance. The slug is immutable after creation; sending `slug` is rejected rather than silently treating it as a display-name change. Use PATCH for surgical file edits. # Run a skill script in the sandbox (SSE) Source: https://docs.neoagent.io/api-reference/skills/run-a-skill-script-in-the-sandbox-sse https://api.neoagent.io/public-api/openapi.json post /public-api/skills/{skill_id}/test-runs Run one script of the skill in the tenant's code sandbox and stream its output. The run borrows the integration permissions of `agent_id` in read-only mode: every write to a connected system is refused by the sandbox proxy, and no technician approval is involved. Send unsaved drafts in `files` to run them instead of the saved files; the saved skill is never changed by a run. Response is `text/event-stream` — stream it, don't buffer. Events: `status` `{phase}`, `output` `{stream, data}` as the script prints, and a final `done` `{run_id, outcome, exit_code, failure_reason, duration_ms}`. Closing the stream stops the script. A run is limited to 120 seconds and 500 KB of output, and to 30 runs per hour per user. Read the recorded run back with GET .../test-runs/{run_id}. # Create a technician Source: https://docs.neoagent.io/api-reference/technicians/create-a-technician https://api.neoagent.io/public-api/openapi.json post /public-api/technicians Adds a technician to the roster. Returns 409 `technician_already_exists` if a technician with the same `psa_id` is already on the roster; a technician removed earlier is added back. Always requires technician approval (the roster controls who receives TIL and gets paged). # Create a technician group Source: https://docs.neoagent.io/api-reference/technicians/create-a-technician-group https://api.neoagent.io/public-api/openapi.json post /public-api/technician-groups Names are unique per tenant (409 on a duplicate). `instructions` takes up to 4,000 characters. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Create a technician working-hours schedule Source: https://docs.neoagent.io/api-reference/technicians/create-a-technician-working-hours-schedule https://api.neoagent.io/public-api/openapi.json post /public-api/technician-schedules Windows on one day may not overlap, and only a day's last window may run past midnight. `timezone` is required: an IANA name, or null for each technician's own time zone. Names are unique per tenant (409 on a duplicate). Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Delete a technician group Source: https://docs.neoagent.io/api-reference/technicians/delete-a-technician-group https://api.neoagent.io/public-api/openapi.json delete /public-api/technician-groups/{group_id} A Dispatch Ticket pool that still names the group gets no one from it; `used_by` on the list names those agents the caller may view, and `hidden_agent_count` counts the others. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Delete a technician working-hours schedule Source: https://docs.neoagent.io/api-reference/technicians/delete-a-technician-working-hours-schedule https://api.neoagent.io/public-api/openapi.json delete /public-api/technician-schedules/{schedule_id} Its technicians go back to their PSA working hours. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Get a technician Source: https://docs.neoagent.io/api-reference/technicians/get-a-technician https://api.neoagent.io/public-api/openapi.json get /public-api/technicians/{profile_id} # List each technician's PSA working hours Source: https://docs.neoagent.io/api-reference/technicians/list-each-technicians-psa-working-hours https://api.neoagent.io/public-api/openapi.json get /public-api/technician-schedules/psa-hours For every technician, the weekly hours dispatch reads from the PSA when the technician is on no schedule: the calendar (a ConnectWise calendar, an Autotask internal location, a Halo Work Day), its windows and time zone. `source` says where they come from: `PSA_CALENDAR`, `PSA_DEFAULT_LOCATION` (Autotask resource with no location), `PSA_ACCOUNT_HOURS` (Syncro), `NEO_DEFAULT_HOURS` (the PSA has no calendar for the technician, so the client's default hours, Monday to Friday), `NOT_IN_PSA`, `NOT_SUPPORTED` (ServiceNow) or `UNAVAILABLE`. A technician on a schedule gets the schedule's hours in dispatch instead. Changes made in the PSA can take up to a day to show. # List removed Teams users Source: https://docs.neoagent.io/api-reference/technicians/list-removed-teams-users https://api.neoagent.io/public-api/openapi.json get /public-api/teams-users/removed People an admin removed from Neo's Teams registrations, who can be restored. # List technician groups Source: https://docs.neoagent.io/api-reference/technicians/list-technician-groups https://api.neoagent.io/public-api/openapi.json get /public-api/technician-groups Each group has a name, a one-line description, optional `instructions` for dispatch, its members (`GET /technicians` ids) and the agents whose Dispatch Ticket pool names it. Dispatch shows each technician's groups to the model, and each group's instructions once per run. # List technician working-hours schedules Source: https://docs.neoagent.io/api-reference/technicians/list-technician-working-hours-schedules https://api.neoagent.io/public-api/openapi.json get /public-api/technician-schedules Each schedule is a named set of weekly windows (`MONDAY`..`SUNDAY`, 24-hour `HH:MM`; an end before the start ends the next day) with the technicians on it. Dispatch shows a technician on a schedule its hours in place of their PSA working hours. # List technicians Source: https://docs.neoagent.io/api-reference/technicians/list-technicians https://api.neoagent.io/public-api/openapi.json get /public-api/technicians Every technician on the dashboard's Technicians page, including the ones not ready for dispatch. Dispatch skips a technician with a blank `profile`, or with `update_automatically: true` and `is_ready: false`; `profile_status` says why. # List the companies with technician rules Source: https://docs.neoagent.io/api-reference/technicians/list-the-companies-with-technician-rules https://api.neoagent.io/public-api/openapi.json get /public-api/technicians/companies Every company that a technician has a rule for, with its technicians: `PREFERRED` (the dispatch model sends the company's tickets to them first) or `EXCLUDED` (do not assign), each with an optional note, and whether the technician takes tickets from their preferred companies only. The same rules as `companies` on each technician, grouped by company. # List the Microsoft accounts Neo knows Source: https://docs.neoagent.io/api-reference/technicians/list-the-microsoft-accounts-neo-knows https://api.neoagent.io/public-api/openapi.json get /public-api/technicians/microsoft-accounts Every Microsoft account in the MSP's own tenant that Neo knows: people registered with a Neo app in Teams, and dashboard members. Each carries `teams_installed` (the Neo AI Agent app, the only one that delivers Notify messages and approval cards), `dashboard_member`, and the technician it is linked to, if any. Link a technician with `PATCH /technicians/<id>` and `entra_object_id`. # Put technicians on a working-hours schedule Source: https://docs.neoagent.io/api-reference/technicians/put-technicians-on-a-working-hours-schedule https://api.neoagent.io/public-api/openapi.json put /public-api/technician-schedules/assignments `technician_ids` are `GET /technicians` ids. `schedule_id: null` moves them back to their PSA working hours. Ids that name no technician are returned in `not_found_technician_ids` and change nothing. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Remove a Teams user Source: https://docs.neoagent.io/api-reference/technicians/remove-a-teams-user https://api.neoagent.io/public-api/openapi.json delete /public-api/teams-users/{user_id} Removes a person's registration with Neo's Teams apps, by Microsoft account id. They leave the Notify and approval recipient lists and Neo stops messaging them first; they can still chat with Neo in Teams. Returns 404 `teams_user_not_found` for an id with no live registration. Asks for technician approval unless the Technicians permission group turns approval off. # Replace a technician group Source: https://docs.neoagent.io/api-reference/technicians/replace-a-technician-group https://api.neoagent.io/public-api/openapi.json put /public-api/technician-groups/{group_id} Replaces the name, description and members. `instructions` left out keeps the current ones; null or an empty string clears them. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Replace a technician working-hours schedule Source: https://docs.neoagent.io/api-reference/technicians/replace-a-technician-working-hours-schedule https://api.neoagent.io/public-api/openapi.json put /public-api/technician-schedules/{schedule_id} Replaces the name, windows and time zone. Every technician on the schedule gets the new hours. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Restore a removed Teams user Source: https://docs.neoagent.io/api-reference/technicians/restore-a-removed-teams-user https://api.neoagent.io/public-api/openapi.json post /public-api/teams-users/{user_id}/restore Restores a removed registration, so the person is reachable again at once. Returns 404 `teams_user_not_found` for an id that was never removed. Asks for technician approval unless the Technicians permission group turns approval off. # Set a company's technician rules Source: https://docs.neoagent.io/api-reference/technicians/set-a-companys-technician-rules https://api.neoagent.io/public-api/openapi.json put /public-api/technicians/companies/{psa_company_id} Replaces one company's technician list (`[]` clears it); every other company's rules stay. `company_name` is the PSA name. Returns 400 for a technician id the tenant does not have, a technician new to this company who already has 30 companies, or a save that would leave a technician limited to their preferred companies with none. Asks for technician approval unless the Technicians permission group turns approval off. # Set a technician's groups Source: https://docs.neoagent.io/api-reference/technicians/set-a-technicians-groups https://api.neoagent.io/public-api/openapi.json put /public-api/technician-groups/memberships Replaces the technician's groups with `group_ids`. Ids that name no group are returned in `not_found_group_ids` and change nothing. Via `NEO_API_REQUEST`, needs technician approval unless the Technicians permission group turns it off. # Soft-delete a technician Source: https://docs.neoagent.io/api-reference/technicians/soft-delete-a-technician https://api.neoagent.io/public-api/openapi.json delete /public-api/technicians/{profile_id} Clears the technician profile and marks the row not-ready. Always requires technician approval. # Update a technician Source: https://docs.neoagent.io/api-reference/technicians/update-a-technician https://api.neoagent.io/public-api/openapi.json patch /public-api/technicians/{profile_id} Partial patch — only supplied fields change. `entra_object_id` links the technician to a Microsoft account (an id from `GET /technicians/microsoft-accounts`); an explicit null unlinks it, and no automatic match links it again; `upn` is accepted only with `entra_object_id`. One account belongs to one technician: an account another technician holds returns 409 `microsoft_account_already_linked`. `companies` replaces the technician's whole company list for dispatch (`[]` clears it, at most 30): the dispatch model reads `PREFERRED` companies as go-to-this-technician-first and `EXCLUDED` ones as do-not-assign, and an optional one-line `note` of up to 200 characters qualifies either. Code enforces `only_preferred_companies`, which limits the technician to the preferred companies and needs at least one; round robin, which reads no notes, also skips a technician who excludes the ticket's company. Send `entra_object_id` and the company fields in separate requests; a request with both returns 400. Asks for technician approval unless the Technicians permission group turns approval off. # Get a template Source: https://docs.neoagent.io/api-reference/templates/get-a-template https://api.neoagent.io/public-api/openapi.json get /public-api/templates/{template_id} # Instantiate a template for this tenant Source: https://docs.neoagent.io/api-reference/templates/instantiate-a-template-for-this-tenant https://api.neoagent.io/public-api/openapi.json get /public-api/templates/{template_id}/instantiate The `POST /agents` body to create an agent from this template on the calling tenant. Both endpoints resolve `integrations` for the caller; this one adapts the rest of the payload too: identities from the authoring tenant are removed, and the FIND_ENTITIES filter is unpacked into top-level `ticket_conditions` / `time_entry_conditions`. Edit `create_body` (name, filter, toolbox) and send it verbatim to `POST /agents`. Prefer this over hand-building a body from `GET /templates/<id>`. # List agent/workflow templates Source: https://docs.neoagent.io/api-reference/templates/list-agentworkflow-templates https://api.neoagent.io/public-api/openapi.json get /public-api/templates Neo-curated catalog of starter agents/workflows. Filtered server-side to the tenant's PSA (`supported_psas` membership). Use as a starting point for `POST /agents` — the `actions`, `toolbox`, `agent_settings`, and `integrations` blobs are passthrough-shaped against the `/schemas/agents` contract. `integrations` is resolved for the calling tenant rather than published as authored: read the blob rather than assuming which PSA blocks it carries. # List template categories Source: https://docs.neoagent.io/api-reference/templates/list-template-categories https://api.neoagent.io/public-api/openapi.json get /public-api/templates/categories Distinct `category` values present in the active template catalog. Use to drive a picker sidebar. # Get the caller's tenant Source: https://docs.neoagent.io/api-reference/tenant/get-the-callers-tenant https://api.neoagent.io/public-api/openapi.json get /public-api/clients/me Basic facts about the authenticated tenant (`itsm_type`, region, name) — the anchor for any PSA-shaped follow-up call. # Approval-queue stats Source: https://docs.neoagent.io/api-reference/til-requests/approval-queue-stats https://api.neoagent.io/public-api/openapi.json get /public-api/til-requests/stats Pending count, decisions in the last 7 days, and the median time-to-decision over that window. A non-admin, including the Neo Support agent acting for one, sees their own queue; tenant admins and an API key with no acting person see the whole tenant, optionally confined with `approver`. # Approve or reject multiple TIL requests Source: https://docs.neoagent.io/api-reference/til-requests/approve-or-reject-multiple-til-requests https://api.neoagent.io/public-api/openapi.json post /public-api/til-requests/bulk-decision Applies one decision (approve or reject) to up to 50 technician-in-the-loop requests in the caller's own tenant. Each decision resumes a paused agent, so the operation is best-effort and not atomic: requests are processed sequentially, each is re-checked for a pending status, and results are grouped into `succeeded`, `already_resolved`, and `failed`. Partial success is normal — inspect the three groups rather than relying on a single overall status. A request outside the caller's scope is reported in `failed`. Tenant admins and an API key with no acting person reach every request in the tenant. Anyone else, including the Neo Support agent acting for a technician, reaches only the requests sent to them and those raised in their own chat; any other request answers 404, as a request in another tenant does. # Approve, reject, or request changes on a TIL request Source: https://docs.neoagent.io/api-reference/til-requests/approve-reject-or-request-changes-on-a-til-request https://api.neoagent.io/public-api/openapi.json post /public-api/til-requests/{request_id}/decision Records the technician's decision (409 if it was already resolved). Returns the updated request. `approve` authorizes the action; `reject` stops it; `request_changes` does neither — it records COMMENTED and unlocks no write. For a request raised by an agent run, that run resumes to revise its proposal and raise a fresh request. For a request raised in a chat with a conversational agent, the agent reads the note on the next message in that chat — the dashboard and the Teams bot send that message; a direct API caller must send one. `request_changes` needs a non-empty `note` and is accepted only on agent requests (400 otherwise). A **platform** service account may pass `client_id` to resolve a TIL in another tenant — but only when the acting technician is a recipient of the request, the request belongs to a conversational chat agent, or it belongs to that tenant's Neo Support agent (any other agent → 403); any non-platform caller passing `client_id` is rejected with 403. For proactive Teams cards the trusted relay may instead supply `acting_end_user_tenant_id` with `acting_end_user`: the backend locates the request's workspace and checks the full identity, named recipient, and current workspace eligibility. Non-platform callers cannot use this identity field. When the relay also supplies `acting_conversation_id` and the request was sent to that Teams channel or group chat, anyone in it from the workspace's own directory may decide, named recipient or not, while that conversation is still registered to the workspace. Every other caller decides only within its scope: Tenant admins and an API key with no acting person reach every request in the tenant. Anyone else, including the Neo Support agent acting for a technician, reaches only the requests sent to them and those raised in their own chat; any other request answers 404, as a request in another tenant does. # Get a TIL request Source: https://docs.neoagent.io/api-reference/til-requests/get-a-til-request https://api.neoagent.io/public-api/openapi.json get /public-api/til-requests/{request_id} One request: its agent, approvers and decision. `planned_calls` lists the exact calls the request asks to make, in order, empty when it has none. On an APPROVED request, a write that matches an item runs with no further check, each time it matches; `uses` counts those passes (not calls that succeeded), and is null for a caller who may not view the raising agent. An approval with a note uses no item. Tenant admins and an API key with no acting person reach every request in the tenant. Anyone else, including the Neo Support agent acting for a technician, reaches only the requests sent to them and those raised in their own chat; any other request answers 404, as a request in another tenant does. # List technician-in-the-loop requests Source: https://docs.neoagent.io/api-reference/til-requests/list-technician-in-the-loop-requests https://api.neoagent.io/public-api/openapi.json get /public-api/til-requests Newest first. A non-admin, including the Neo Support agent acting for one, sees only the requests sent to them; tenant admins and an API key with no acting person see the whole tenant. # List the tenant's distinct TIL approvers Source: https://docs.neoagent.io/api-reference/til-requests/list-the-tenants-distinct-til-approvers https://api.neoagent.io/public-api/openapi.json get /public-api/til-requests/approvers # Acknowledge Issue Source: https://docs.neoagent.io/building-automations/actions/ai/acknowledge-issue Generate empathetic, personalized acknowledgment messages for customer tickets <Warning> **This action is deprecated.** It still works, but we recommend building an [Agent](/core/agents) for new automations - an Agent can decide whether an acknowledgement is warranted, write it, and send it, rather than always replying. </Warning> The action analyzes ticket content and generates an acknowledgment message. Add a notification action to send the message. <Info> This action is only available as a **triggered** action in workflows. </Info> ## Quick start <Steps> <Step title="Create triggered workflow"> Set the trigger to "New ticket created" for the companies you want to cover. </Step> <Step title="Add Acknowledge Issue action"> The action will work with default settings, but you can add custom instructions for your company's tone and style. </Step> <Step title="Add notification action"> Use "Notify Ticket's Contact" to send the generated acknowledgment message to the customer. </Step> <Step title="Test and refine"> Check your Executions to see the generated messages and adjust custom instructions if needed. </Step> </Steps> ## How it works When a new ticket arrives, this action analyzes the ticket content and generates an acknowledgment message that: 1. Acknowledges help requests, confirms actions in progress, or promises follow-up for information requests 2. Uses empathetic language like "thank you" instead of robotic "acknowledged" responses 3. Includes customer names when available (i.e. "Hi John,") 4. Ends with appropriate closings like "Best Regards" 5. Incorporates custom instructions to match your company's voice and tone ## Setup **Ticket to process**: The action works with any ticket from your workflow - either new tickets from triggers or tickets found by other actions. **Custom instructions (optional)**: You can add specific guidance like: * "Always mention our 4-hour response commitment" * "Include a link to our customer portal" * "Sign off with our team name" **Company-specific settings**: Use different acknowledgment styles for different clients by pinning a [memory](/core/memory) on that company. Pinned company memories are added to every run of this action — you don't switch them on per action. <Warning> For Autotask users: If you're using notification templates that already include customer greetings, the AI will avoid adding duplicate "Hi \[Name]," greetings to prevent awkward repetition. </Warning> # Analyze Customer Sentiment Source: https://docs.neoagent.io/building-automations/actions/ai/analyze-customer-sentiment Detect customer emotions in ticket communications to prioritize unhappy customers It classifies ticket conversation history as positive, negative, or neutral and provides reasoning for the classification. ## Quick start <Steps> <Step title="Add to your workflow"> Add the action to workflows that process tickets with customer communications. </Step> <Step title="Configure basic settings"> The action works with default settings, but you can add custom instructions for your specific business context. </Step> <Step title="Set up custom fields (optional)"> By default the action writes to fields named "Neo - Customer Sentiment" and "Neo - Customer Sentiment Reasoning". Create these fields in your PSA before you configure the action, or set different field names in the action settings. Both fields must be of type **Text**. </Step> <Step title="Add follow-up actions"> Use "Update Ticket Fields" to save sentiment data and "Notify Internal Team" to alert staff about negative sentiment tickets. </Step> </Steps> ## How it works The action focuses on customer messages to determine the overall sentiment: 1. **Positive** - Appreciation, satisfaction, or optimism 2. **Negative** - Frustration, urgency, dissatisfaction, or complaints 3. **Neutral** - Factual, routine, or emotionally neutral communication The AI provides detailed reasoning for its classification and can optionally save both the sentiment and reasoning to custom fields in your PSA. ## Setup **Tickets to analyze**: Works with any tickets from your workflow - typically all tickets from a specific search or filter. **Custom instructions (optional)**: Add guidance such as: * "Consider urgency keywords like 'ASAP' or 'critical' as negative sentiment" * "Treat thank you messages as positive, even if brief" **Save to PSA (optional)**: You can save sentiment results and reasoning directly to custom fields in your PSA system for tracking and reporting. ## Common use cases <AccordionGroup> <Accordion title="Prioritize unhappy customers"> Automatically escalate tickets with negative sentiment by notifying team leads, increasing ticket priority, adding to "Needs Attention" queues, or assigning to senior technicians. </Accordion> <Accordion title="Track satisfaction trends"> Run sentiment analysis on recently closed tickets to measure customer satisfaction over time and identify service improvement opportunities. </Accordion> <Accordion title="Proactive outreach"> Monitor neutral sentiment on long-running tickets for proactive customer check-ins. </Accordion> <Accordion title="Service quality monitoring"> Analyze sentiment patterns across different service types, technicians, or time periods to identify areas for improvement. </Accordion> </AccordionGroup> # Analyze Technician Work Source: https://docs.neoagent.io/building-automations/actions/ai/analyze-technician-work Ensure technicians provide complete documentation and follow your standards <Warning> **This action is deprecated.** It still works, but we recommend building an [Agent](/core/agents) for new automations. An Agent can judge note completeness against your standards and act on the result in one step. </Warning> <Info> This action is only available as a **triggered** action in workflows. </Info> ## Quick start <Steps> <Step title="Create triggered workflow"> Set the trigger to "Technician adds note to ticket" for the teams you want to monitor. </Step> <Step title="Define your criteria"> Specify what constitutes complete documentation, like: "Technician must include work performed, current status, next steps, and timeline." </Step> <Step title="Add follow-up actions"> Use "Add Ticket Note" to document analysis results and "Notify Internal Team" to alert managers when standards aren't met. Add "Notify Ticket's Owner (Assigned Technician)" to send the reasoning back to the technician who wrote the note, for coaching. </Step> <Step title="Test and refine"> Review Executions to see how the AI interprets your criteria and adjust as needed. </Step> </Steps> ## How it works When a technician updates a ticket, this action: 1. Analyzes ticket notes against criteria you define 2. Determines compliance: whether the technician's work meets your standards 3. Provides detailed reasoning: explains what's missing or confirms completeness 4. Generates notifications: alerts relevant parties when standards aren't met If criteria are met, the action logs success but doesn't generate MSP notifications. If criteria aren't met, it creates detailed messages explaining what's missing. ## Setup **Ticket to analyze**: The action works with any ticket from your workflow trigger when a technician adds a note. **Criteria (optional)**: Define the standards or requirements for technician work that the AI will check against. For example: "Technician must detail the problem, steps taken, resolution outcome, and next steps with timeframes." # Build Message Source: https://docs.neoagent.io/building-automations/actions/ai/build-message Create custom messages that reference specific ticket details and sound natural Add Build Message after a workflow trigger or action that provides ticket data. Select Customer Facing for client communications or Internal for team messages. ## Quick start <Steps> <Step title="Add the action"> Add "Build Message" to any workflow where you have ticket data available. </Step> <Step title="Write clear instructions"> Be specific about what you want. For example: * "Create a friendly update for the customer about their ticket status" * "Write a brief internal summary of what was done on this ticket" * "Generate a polite message asking for more information" </Step> <Step title="Choose message type"> Select "Customer Facing" for client communications or "Internal" for team messages. </Step> <Step title="Add notification action"> Use the generated message with actions like: * "Notify Ticket's Contact" for customer messages * "Add Ticket Note" for internal documentation * "Notify Internal Team" for team alerts </Step> </Steps> ## Setup **Ticket to reference**: The action works with any ticket from your workflow trigger or previous actions. **Message instructions**: Provide clear instructions about what kind of message you want. Examples: * "Create a friendly status update for the customer about their ticket progress" * "Write a brief internal summary of what was accomplished on this ticket" * "Generate a polite message asking the customer for more information" **Message type**: Specify the intended audience: * **Customer Facing**: Messages that will be sent to clients * **Internal**: Messages for your team or internal documentation <Note> The message type decides which downstream action can read the output. "Notify Ticket's Contact" reads only **Customer Facing** messages; "Notify Internal Team" and "Add Ticket Note" read only **Internal** messages. If you send an **Internal** message to "Notify Ticket's Contact", or a **Customer Facing** message to an internal action, nothing is sent. </Note> ## Common use cases <AccordionGroup> <Accordion title="Customer status updates"> Create progress updates that reference specific work performed, including ticket number, current status, and work completed. </Accordion> <Accordion title="Information requests"> Generate requests for additional details that reference the original issue and state what information is needed. </Accordion> <Accordion title="Internal summaries"> Create summaries for team communication that include actions taken, outstanding issues, and next steps. </Accordion> <Accordion title="Follow-up communications"> Create follow-up messages based on ticket status, such as a summary of what was fixed or a request for confirmation. </Accordion> </AccordionGroup> # Build New Ticket Source: https://docs.neoagent.io/building-automations/actions/ai/build-new-ticket Intelligently determine if a new ticket should be created and prepare all the necessary details <Warning> **This action is deprecated.** It still works, and it remains the only way to supply ticket details to [Create New Ticket](/building-automations/actions/write-to-psa/create-new-ticket) - always pair the two. For new automations we recommend an [Agent](/core/agents) instead, which can decide a ticket is needed and create it in one step with no separate "prepare then create" handoff. If you use this action, make sure a **Create New Ticket** action follows it. On its own it only prepares ticket data and creates nothing. </Warning> The Build New Ticket action analyzes a reference ticket and your custom instructions to decide whether a new ticket should be created. If creation is warranted, it prepares the data for the new ticket. <Info> This action is available only as a **Triggered** action in a workflow. </Info> ## Quick start <Steps> <Step title="Add the action"> Add "Build New Ticket" to a triggered workflow where you want to conditionally create new tickets. </Step> <Step title="Set reference ticket"> Choose the ticket that will serve as the reference for building the new ticket (typically the trigger ticket). </Step> <Step title="Write clear instructions"> Define your logic for when and how to create new tickets. Be specific about: * Conditions for creating the ticket (e.g., "if this is a reopened issue") * How to populate fields (title, board, status, priority, description) * Whether to use details from the reference ticket </Step> <Step title="Add Create New Ticket action"> Always follow with the "Create New Ticket" action to actually create the ticket in your PSA using the prepared data. </Step> </Steps> ## How it works This action examines the reference ticket and applies your custom instructions to decide whether to prepare a new ticket. It reviews the ticket's content, metadata, and context, then uses your logic to determine the title, board, status, priority, and description when creation is warranted. It explains why a ticket was or was not built and outputs ticket information for the Create New Ticket action. The new ticket's description automatically includes a reference to the original ticket for tracking. ## Setup **Reference ticket**: The ticket that serves as the basis for analysis, usually your trigger ticket. **Instructions**: Guidance for when and how to create new tickets. Include: * Specific conditions that warrant ticket creation * How to populate each field (title, board, status, priority, description) * Whether to inherit details from the reference ticket or use new values * Any time-sensitive logic using the current date, time, and weekday (for example "if it's Friday afternoon, set priority to High") * You can name the Board, Status, and Priority to use, by name or by ID. Neo gives the AI the active boards, statuses, and priorities from your PSA. ## Common use cases <AccordionGroup> <Accordion title="Automatically reopening tickets"> When customers reply to closed ticket emails, automatically create a new ticket with the same details but marked as reopened. Instructions: "Create a new ticket if the reference ticket is identified as reopening an issue for a closed ticket. Use the same details as the reference ticket and append '\[Re-opened Ticket]' to the title." </Accordion> <Accordion title="Splitting complex requests"> Break down complex onboarding requests into separate tickets for workstation setup and software licensing. Instructions: "Create a new ticket if the reference ticket is related to onboarding and mentions that the customer needs a new workstation. Use the same details but change the title to 'New Workstation for \[customer\_name]'." </Accordion> <Accordion title="Creating on-site visit tickets"> When diagnostics reveal remote resolution isn't possible, automatically create a field service ticket. Instructions: "Create a new ticket if the reference ticket indicates an issue that cannot be resolved remotely and requires an on-site visit. Mark as High Priority, assign to 'Field Services' board with 'Scheduled' status." </Accordion> <Accordion title="Follow-up maintenance tickets"> After resolving certain types of issues, create follow-up tickets for preventive maintenance. Instructions: "Create a follow-up maintenance ticket if the reference ticket involved hardware replacement or critical system repair. Schedule it for 30 days out with 'Preventive Maintenance' title." </Accordion> </AccordionGroup> # Chase Customer Source: https://docs.neoagent.io/building-automations/actions/ai/chase-customer Automate follow-ups with customers and close unresponsive tickets In scheduled workflows, this action follows up on tickets awaiting a response and can close tickets after chase attempts are exhausted. <Info> This action only works with **scheduled workflows**. </Info> ## Quick start <Steps> <Step title="Create scheduled workflow"> Set up a scheduled workflow (this action only works with scheduled workflows). </Step> <Step title="Filter appropriate tickets"> Use filters to select tickets awaiting customer response, such as: * Status = "Waiting on Customer" * Last updated > 2 days ago * Assigned technician is not empty </Step> <Step title="Configure chase settings"> Set the number of chase attempts (start with 1-2) and add custom instructions for message tone. </Step> <Step title="Add notification action"> Add "Notify Ticket's Contact" to actually send the chase messages to customers. </Step> <Step title="Test and refine"> Run the workflow on a few test tickets and adjust your custom instructions based on the results. </Step> </Steps> ## How it works 1. Counts how many times each customer has been contacted. 2. Creates follow-ups that reference specific work completed. 3. Adjusts tone as chase attempts increase. 4. Can automatically close tickets when maximum attempts are reached. 5. Allows custom instructions to control when tickets are closed. ## Setup **Tickets to process**: Works with tickets awaiting customer response, typically from a search filtering for tickets waiting on customers. **Maximum attempts**: Set how many times to chase each customer before taking final action (like closing the ticket). **Custom instructions (optional)**: Provide specific guidance on message tone, timing, and closure behavior. For example: "Be very polite and mention we're eager to confirm whether the solution worked. Wait 48 hours after final notice before closing tickets." **Update ticket status after each chase attempt (optional)**: Set a status to apply after every normal chase (not the final one). Useful when the PSA is driving the loop - e.g., flip the ticket back to `Waiting Customer` so the PSA's SLA rule re-flags it later. The status only applies when chase attempts have **not** been exceeded. **Update ticket status after exceeding chase attempts (optional)**: Set a status to apply once Neo's reached the maximum chase attempts (typically your escalation status). Applied only when the final attempt is reached - earlier attempts use the per-attempt status if configured. **Track chase attempt count in a PSA custom field (optional)**: Have Neo store the chase counter in a PSA user-defined field (UDF) on the ticket. Neo reads the counter before each chase, decides whether the max is exceeded, and writes the incremented value back via the next Update Ticket Fields action. Use this when the LLM-inferred count from conversation history is unreliable (e.g., chases are logged as time entries the model under-counts, or the customer never replies so "since their last message" is ambiguous). * The UDF must already exist in the PSA on the Ticket entity, type **Number** (integer). Default name: `Neo Chase Count`. * Requires an **Update Ticket Fields** action immediately after Chase Customer so the new counter value gets persisted. * The counter does not auto-reset on customer replies - reset it manually in the PSA if you want a ticket to go through another full chase cycle. <Warning> Always test your chase workflow with non-critical tickets first to ensure messages are appropriate and timing works as expected before applying to all customer communications. </Warning> # Check if it is a Recurring Issue Source: https://docs.neoagent.io/building-automations/actions/ai/check-recurring-issue Identify when new tickets are part of ongoing problems affecting multiple users It compares a new ticket with tickets from the configured history window and determines whether they are related. ## How it works When a new ticket arrives, this action: 1. **Searches recent history** - looks back through tickets from the specified timeframe 2. **Compares similarities** - analyzes ticket content, affected users, and company context 3. **Identifies patterns** - determines if the new ticket matches recent issues 4. **Provides reasoning** - explains why tickets are considered related or unique The action can detect recurring issues across different scenarios: same company/same user, same company/different users, or similar technical problems across multiple companies. ## Setup **Ticket to analyze**: The action works with new tickets from your workflow trigger to check for recurring patterns. **Comparison scope**: Choose how broadly to search for similar tickets: * **Same user only**: Only compare with tickets from the same user at the same company * **Company-wide**: Compare with all tickets from the same company * **All companies**: Compare across all companies (useful for widespread technical issues) <Warning> Be careful with the `all_companies` comparison scope as it can consume more credits and may identify false positives across unrelated organizations. Start with company-specific scopes and expand gradually. </Warning> **Search parameters**: * Set how many days of ticket history to search (10 days by default) * Choose maximum number of recent tickets to analyze (10 by default - higher numbers provide more thorough analysis but consume more credits) Neo compares the tickets in one call and splits a fixed token budget across them, so a long conversation or a long configuration list on any one ticket is trimmed to fit. That budget holds at most 49 tickets, so when the search finds more than 49 candidates, Neo analyzes the most recently updated 49. It names the number it compared in its reasoning when that number is below the number found, and it reports a recurring issue. When it compared every ticket found, the reasoning carries no such count, and a negative result shows only `No reoccurring issue detected`. When your PSA reports a similar ticket as deleted while the run is in flight, Neo leaves that ticket out of the comparison, counts it out of the number in its reasoning, and continues with the rest. If every ticket it read has gone by then, the run reports no recurring issue. Not every PSA reports a mid-run deletion, so a ticket deleted moments earlier can still be in the comparison. **Tuning by issue type**: * Infrastructure outages: 3-5 day lookback, company-wide scope, higher comparison limits * User behavior patterns: 30-60 day lookback, same-user scope * Vendor or product issues: 10-14 day lookback, cross-company scope Use 7 days for urgent issues and 30 days when you look for patterns. After testing, raise the maximum tickets to compare to 15-20 if you need more thorough analysis. **Custom instructions (optional)**: Provide specific guidance on how to identify recurring issues in your environment. For example: "Consider backup jobs failing at the same step within a week as recurring issues, even if error messages vary slightly." **Auto-tagging (optional)**: Automatically add a tag to tickets identified as recurring issues for easy filtering and reporting. ## Quick start <Steps> <Step title="Add to intake workflow"> Add this action right after ticket creation to catch recurring issues immediately. </Step> <Step title="Configure comparison scope"> Choose how broadly to look for similar tickets: * Same user only: `same_company_same_contact` * Company-wide: `same_company_all_contacts` * Across all clients: `all_companies` </Step> <Step title="Set search parameters"> Start with conservative settings: 10 days back, 10 tickets maximum. </Step> <Step title="Enable auto-tagging (optional)"> Turn on `add_tag_if_recurring` to automatically tag repeat issues. </Step> <Step title="Add follow-up actions"> Use the analysis results with a follow-up action: * "Assign Ticket to Technician" - route the ticket to the engineer who handled the original issue * "Notify Internal Team" - alert that technician or the team lead about the related tickets * "Add Ticket Note" - cross-reference the related tickets and document the pattern * "Update Ticket Fields" - apply consistent tags for reporting and filtering </Step> <Step title="Test and refine"> Review results in Executions and adjust settings based on your environment. </Step> </Steps> ## Example scenarios ### Printer outage detection ``` Comparison scope: same_company_all_contacts Days to look back: 3 Custom instructions: "Consider printer-related tickets from the same office location within 72 hours as recurring issues, even if different users report them." ``` ### User training identification ``` Comparison scope: same_company_same_contact Days to look back: 30 Custom instructions: "Look for users repeatedly having password reset issues, email setup problems, or basic software questions as training opportunities." ``` ### Vendor issue tracking ``` Comparison scope: all_companies Days to look back: 7 Custom instructions: "Identify widespread issues with CloudBackup 360, SecureShield AV, or VoIP systems that might indicate vendor-wide problems requiring escalation." ``` # Data Analysis Source: https://docs.neoagent.io/building-automations/actions/ai/data-analysis Run custom analyses on your PSA data with AI-generated or pre-built Python scripts Choose a pre-built analysis script or have Neo's AI generate one from your description. The action runs the script on PSA data such as tickets or time entries. ## Quick start <Steps> <Step title="Gather your data"> Use "Find Entities" to collect the data you want to analyze (like tickets from a specific client or time period). </Step> <Step title="Describe your analysis"> Clearly describe what insights you want. For example: "Create a table showing ticket volume by category for the past month." </Step> <Step title="Choose your approach"> Either use "USE AI" to generate a script, select a pre-built template, or write your own Python code. </Step> <Step title="Configure output"> Set up column names if you want a data table, and enable CSV export if you plan to email the results. To email results, enable CSV export and pair this action with "Notify Internal Team" using email delivery, so the CSV is attached. </Step> </Steps> ## How it works This action processes data from previous workflow actions through a custom analysis: 1. **Gathers data**: Takes data from previous workflow actions (like "Find Entities") 2. **Prepares for analysis**: Makes data accessible to Python scripts with helper functions 3. **Executes analysis**: Runs your chosen script (AI-generated, template, or custom) 4. **Produces results**: Creates text summaries and optional data tables 5. **Prepares exports**: Formats data tables as CSV files for email delivery if enabled ## Setup **Analysis description**: Describe what you want to analyze. This is crucial for AI-generated scripts and serves as documentation for custom scripts. **Python code**: The script that will be executed. Can be AI-generated, from a template, or written by you. Complex scripts can run slowly. Keep the code efficient. **Report columns (optional)**: Specify column names if your script produces a data table for CSV export. **CSV export (optional)**: Enable if you want data tables available as CSV files for email delivery. ## Example workflow **Monthly client report** 1. **Trigger:** Scheduled workflow (monthly) 2. **Find Entities** - Gather all tickets for a specific client from the past month 3. **Data Analysis** - Generate a report with a ticket summary and resolution metrics 4. **Notify Internal Team** - Email the report with the CSV attachment to the account manager # Executive Summary Source: https://docs.neoagent.io/building-automations/actions/ai/executive-summary Generate high-level executive summaries for stakeholders and leadership <Warning> **This action is deprecated.** It still works and is not going away without notice, but we recommend building an [Agent](/core/agents) for new reporting automations. An Agent decides what to look at, can pull in RMM, documentation and PSA data alongside the tickets, and writes the report in the format and tone you ask for — instead of producing one fixed summary shape. </Warning> The Executive Summary action creates concise, business-focused summaries of ticket data and service delivery metrics. <Info> This action runs in **scheduled** workflows. </Info> ## Quick start <Steps> <Step title="Add to reporting workflow"> Add the action to a scheduled workflow that gathers ticket data for executive reporting. </Step> <Step title="Configure reporting period"> Set up filters to collect tickets from your desired time period (weekly, monthly, quarterly). </Step> <Step title="Define focus areas"> Use custom instructions to specify what aspects to highlight: service quality, response times, recurring issues, etc. </Step> <Step title="Add delivery action"> Use "Notify Internal Team" to email the summary to executives or "Add Ticket Note" to save for review. </Step> </Steps> ## How it works This action analyzes ticket data to create executive-level insights: 1. **Analyzes ticket patterns** - Reviews ticket volume, types, and resolution trends 2. **Identifies key metrics** - Highlights important KPIs like response times and customer satisfaction 3. **Summarizes business impact** - Translates technical issues into business language 4. **Provides recommendations** - Suggests actionable next steps based on findings 5. **Formats for executives** - Creates clear, concise summaries appropriate for leadership consumption ## Setup **Data to analyze**: Works with tickets from your workflow, typically from a "Find Entities" action that gathers tickets for a specific time period. **Custom instructions (optional)**: Guide the summary focus. For example: "Highlight service quality trends, major incidents, and customer satisfaction metrics for the past month." **Report format (optional)**: Specify whether you want detailed analysis or high-level overview format. ## Common use cases <AccordionGroup> <Accordion title="Monthly service reports"> Generate monthly summaries of service delivery performance, highlighting trends, issues, and improvements for executive review. </Accordion> <Accordion title="Incident impact analysis"> Create business-focused summaries of major incidents, including customer impact, resolution time, and lessons learned. </Accordion> <Accordion title="Customer satisfaction reporting"> Analyze ticket sentiment and resolution quality to provide executives with customer satisfaction insights and improvement opportunities. </Accordion> <Accordion title="Resource utilization insights"> Summarize technician workload, efficiency metrics, and resource allocation recommendations for strategic planning. </Accordion> </AccordionGroup> ## Example workflows <AccordionGroup> <Accordion title="Monthly Executive Report"> 1. **Trigger:** Scheduled workflow (monthly) 2. **Find Entities** - Gather all tickets from past month 3. **Executive Summary** - Generate business-focused summary with trends and insights 4. **Notify Internal Team** - Email summary to executive team </Accordion> <Accordion title="Customer Satisfaction Report"> 1. **Trigger:** Scheduled workflow (weekly) 2. **Find Entities** - Get recently closed tickets 3. **Executive Summary** - Focus on customer satisfaction and service quality 4. **Notify Internal Team** - Send to service managers and executives </Accordion> </AccordionGroup> # Find Relevant Configuration Source: https://docs.neoagent.io/building-automations/actions/ai/find-relevant-configuration Intelligently identify and suggest the most relevant configuration item for PSA tickets <Warning> **This action is deprecated.** It still works, but we recommend building an [Agent](/core/agents) for new automations. An Agent matches configuration items more accurately because it can search your RMM and documentation as it reasons, instead of scoring a fixed candidate list. </Warning> The action checks configurations attached to the ticket, linked to its contact, or mentioned in ticket content. It selects the most relevant configuration item or explains why none were suitable. <Info> This action is available only as a **triggered** action in workflows. </Info> ## Quick start <Steps> <Step title="Add to ticket workflow"> Add the action to workflows triggered by new tickets to automatically link relevant devices or assets. </Step> <Step title="Configure search sources"> Enable searching by ticket contact, last login device, and ticket content for comprehensive configuration discovery. </Step> <Step title="Add custom instructions (optional)"> Provide guidance for specific issue types, like prioritizing printers for print issues or servers for application problems. </Step> <Step title="Add update action"> Use "Update Ticket Fields" to automatically attach the found configuration to the ticket. </Step> </Steps> ## How it works 1. **Builds a candidate list** - Checks configurations already attached, linked to contact, or mentioned in ticket content 2. **Applies AI analysis** - Uses AI to evaluate how well each candidate matches the ticket context 3. **Selects the best match** - Chooses the single most relevant configuration item 4. **Provides reasoning** - Explains why the configuration was selected or why none were suitable ## Setup **Search sources**: Choose which sources Neo should use to find candidate configurations: * Search for configurations linked to the ticket's contact in the PSA * Search for configurations associated with the contact's last login device * Search for configurations mentioned in the ticket's content Match quality depends on your PSA configuration data: correct contact associations, descriptive configuration names, and up-to-date contact links. **Custom instructions (optional)**: Provide specific guidance to help the AI select the most relevant configuration. This can tailor the selection to specific types of issues, common device names, or other contextual clues. ## What you get The action prepares ticket field updates, typically including the configuration item Neo identified as most relevant. It also creates internal messages explaining which configuration was selected and why, or noting if no relevant configuration was found, and a summary for Executions. # Find RMM Script to Fix Issue Source: https://docs.neoagent.io/building-automations/actions/ai/find-rmm-script-to-fix-issue Automatically find and execute RMM scripts to resolve ticket problems <Warning> **This action is deprecated.** It still works and is not going away without notice, but we recommend building an [Agent](/core/agents) for new Workflows. Give the Agent the RMM script tools and it reads the ticket, picks the script, chooses the device, runs it and reads the result in one run - and it can try a different script when the first one does not fix the issue. This action stops at a suggestion unless you turn on **Execute the suggested script**, and it then follows a fixed execute-then-verify loop with a preset attempt count. </Warning> It reads ticket descriptions, notes, and details to find scripts in your RMM system. You can configure it to suggest scripts or execute them. ## Quick start <Steps> <Step title="Add to ticket workflow"> Add the action to workflows triggered by new tickets or specific issue types that can be resolved with scripts. </Step> <Step title="Configure execution settings"> Choose whether Neo Agent should only suggest scripts or actually execute them, and set up approval requirements if needed. </Step> <Step title="Set verification method"> Choose how to verify if scripts worked: ticket status monitoring, job completion, or log analysis (Datto RMM only). </Step> <Step title="Add custom instructions"> Provide guidance on script preferences, safety rules, and which scripts to use for specific problems. </Step> </Steps> ## How it works 1. Analyzes the problem: Reads ticket description, notes, and details to understand what needs fixing 2. Searches script library: Finds scripts in your RMM system that could solve this type of problem 3. Selects best match: Chooses the most appropriate script based on problem analysis and your preferences 4. Identifies target device: Determines which device to run the script on from ticket information 5. Executes and verifies: Optionally runs the script and checks if it resolved the issue ## Setup **Script execution**: Choose whether Neo Agent should only suggest scripts or actually execute them. **Approval process**: Require human approval before script execution (recommended when starting). **Verification method**: Choose how to determine if scripts worked: * **Ticket Status**: Wait for monitoring systems to close tickets automatically * **Job Completion**: Consider script successful when RMM job completes * **Log Analysis**: Use AI to analyze execution logs for true success (Datto RMM only) Use Ticket Status for monitored systems, Job Completion for simple maintenance scripts, and Log Analysis for complex scripts that need deeper verification (Datto RMM only). **Custom instructions**: Provide specific guidance about script preferences, safety rules, which scripts to use for different problems, and which scripts to avoid in specific situations. **Retry settings**: Configure how many scripts to try and wait times between attempts. <Note> Begin with script suggestions only and review Neo's choices, then enable automatic execution for simple cases. Test on non-critical systems first. You can turn off approvals for routine fixes later, but keep them for high-risk scripts. </Note> # Find Similar Tickets Source: https://docs.neoagent.io/building-automations/actions/ai/find-similar-tickets Find tickets that are similar to the input ticket based on specified criteria The action can find open tickets for the same company or contact, or tickets with similar content from the same company. ## Quick start <Steps> <Step title="Add to ticket workflow"> Add the action to workflows triggered by new tickets or when you need to find related historical context. </Step> <Step title="Choose similarity type"> Select whether to find open tickets for the same company, same contact, or tickets with similar content. </Step> <Step title="Set search parameters"> Configure how many tickets to find, how far back to look, and relevancy thresholds for content similarity. </Step> <Step title="Add follow-up actions"> Use "Add Ticket Note" to document similar tickets found or conditional logic based on results. </Step> </Steps> ## How it works The action: 1. Reviews the input ticket's content, company, and contact information. 2. Uses a search strategy based on the selected similarity type. 3. Filters results by date range, board/queue, excluded statuses, and relevancy thresholds. 4. Excludes the input ticket and deduplicates results. 5. Creates summaries of matching tickets with links and context. ## Setup **Similarity type**: Choose the type of tickets to find: * Open tickets for the same company * Open tickets for the same contact * Tickets with similar content from the same company **Search settings**: * Set how many similar tickets to find (up to 10 by default) * Choose how far back to look (90 days by default) * For content similarity, adjust the relevancy threshold (0.40 by default - higher means stricter matching) For rapidly changing environments use shorter periods (7-30 days). For complex issues, longer periods (90-180 days) can help. **Filtering (optional)**: * Limit results to specific PSA boards or queues * Focus on particular ticket types or categories **Never include tickets in these statuses** (optional): Pick the statuses that mean the work is finished in your service desk. Neo drops a ticket in one of these statuses from the results, so it is never returned as similar. Set this whenever a status of your own means "finished" but your PSA still reports the ticket as open. On Autotask that is the normal case: only **New**, **Complete** and **Waiting Customer** are built-in statuses, so a status you created — **Resolved**, **Awaiting Sign-off** — carries no Complete Date and passes the open-ticket test. The statuses come from your own PSA, and matching ignores capitals. Leave the setting empty and nothing changes. ## Example workflow **Duplicate prevention** 1. **Trigger:** New ticket created 2. **Find Similar Tickets** - Look for open tickets from the same contact in the past 7 days 3. **Add Ticket Note** - Document any similar tickets found # Find Ticket to Merge With Source: https://docs.neoagent.io/building-automations/actions/ai/find-ticket-to-merge-with Automatically detect duplicate or related tickets that should be combined It searches existing tickets when a workflow processes an incoming ticket. <Info> This action is available only as a **triggered** action in workflows. </Info> <Warning> **This action detects duplicates. It does not merge them.** Nothing is merged in your PSA unless you add the [Merge Ticket](/building-automations/actions/write-to-psa/merge-ticket) action after it. Detect and report on its own is a supported setup — many MSPs use it to flag duplicates for a technician — so Neo does not stop you saving a workflow without the merge action. When a duplicate is found and no Merge Ticket action follows, the run message in **Executions** says so. Merge Ticket is not available on every PSA. It works on ConnectWise, Autotask, Halo and ServiceNow. On Syncro this action detects the duplicate and a technician merges the two tickets in the PSA, so the run message says that instead of naming an action you cannot add. </Warning> ## Quick start <Steps> <Step title="Create triggered workflow"> Set this to trigger when new tickets are created, so it can catch duplicates right away. </Step> <Step title="Choose search scope"> Decide whether to look for duplicates from the same contact (individual duplicates) or same company (company-wide issues). Start with same contact only, then expand to same company when you trust the matches. </Step> <Step title="Set time window"> Start with looking back 30-60 days for potential matches. Going too far back might find irrelevant old tickets. Match the window to the goal: about 7 days for same-contact duplicates, and 1 day for company-wide outage consolidation. </Step> <Step title="Add merge action"> Follow this with the "Merge Ticket" action to actually combine the tickets when matches are found. Skip this step on Syncro, where Merge Ticket is not available, and on a detect-only workflow where you want a technician to decide. </Step> </Steps> ## How it works 1. **Analyzes new ticket** - Reviews content, contact, and company information 2. **Searches for candidates** - Looks through recent tickets based on your scope settings 3. **Evaluates matches** - Uses AI to determine if tickets should actually be merged. By default, it flags a duplicate only when both tickets report the same underlying issue or request **and** share the same expected outcome, so finishing the destination ticket finishes both 4. **Generates customer messages** - Writes a message for the end user about the consolidation, used only when a Merge Ticket action follows. On a detect-only workflow no such message is produced, because no merge happens. 5. **Provides merge recommendations** - Offers detailed reasoning for why tickets should be combined ## What counts as a duplicate By default, Neo recommends a merge only when both of these hold: * **Same underlying issue or request** — they report the same problem, ask for the same work, or one is a reply to or a second report of the other. * **Same expected outcome** — completing the destination ticket also completes the source ticket. If any work the source ticket asks for would still be undone, Neo does not recommend a merge. A shared company, contact, end user, device or asset is a reason for Neo to **compare** two tickets. On its own it is not a reason to treat them as duplicates. One laptop can carry a patching alert, a hardware fault and a leaver request at the same time, and each is separate work. In the same way, when an alert names a user as device metadata — the last logged-in or assigned user of a machine — that name identifies the machine, and it does not make the alert part of that person's request. When the user is the subject of the alert, such as a Microsoft 365 sign-in or mailbox alert, the two rules above still decide. You do not need custom instructions to get this behaviour — it is how the action works by default. Use custom instructions for what is specific to your environment, such as which of your alert types are duplicates of each other. Custom instructions take precedence over these defaults, so an instruction that permits a broader merge widens what Neo recommends for merging. ## Setup **Search scope**: Choose whether to look for duplicates from the same contact (individual customer duplicates) or the same company (company-wide issues). Both scopes consider only **open** tickets as merge candidates, where "open" is what your PSA itself reports: | PSA | A ticket counts as open when | | - | - | | Autotask | its **Complete Date** is empty. Autotask fills that date only on its built-in **Complete** status. | | ConnectWise | its status does not carry the board's **Closed Status** flag. | | Halo | Halo does not report it as closed. | | ServiceNow | the incident is **Active**. | | Syncro | its **Resolved At** date is empty. | **Statuses to exclude from the candidate search**: Pick the statuses that mean the work is finished in your service desk. Neo drops a candidate in one of these statuses before it compares anything, so the search never returns a ticket in that status. The check runs when Neo builds the candidate list. A ticket moved into one of these statuses after that still merges, because the later **Merge Ticket** action does not re-read the destination's status. Set this whenever a status of your own means "finished" but your PSA still reports the ticket as open. On Autotask that is the normal case: only **New**, **Complete** and **Waiting Customer** are built-in statuses, so a status you created — **Resolved**, **Awaiting Sign-off**, **Closed Pending Review** — carries no Complete Date and passes the open-ticket test. Leave the setting empty and nothing changes. The statuses come from your own PSA, and matching ignores capitals. Whenever the list is set, the run message in **Executions** names the statuses it left out, so a technician reading "no candidates" can see which filter was in force. **Time window**: Set how many days back to search for potential duplicates. Start with 30-60 days. The time window filters candidates by their creation date, not by whether they are open. **Search limits**: Control how many tickets to consider as potential duplicates (20 by default, 40 at most) to ensure good performance. Neo compares the candidates in one call and splits a fixed token budget across them, so a long conversation or a long configuration list on any one ticket is trimmed to fit. That budget holds at most 49 tickets, so when the search finds more than 49 candidates, Neo compares the most recently updated 49 and says so in the run message in **Executions**, naming the number it compared. When your PSA reports a candidate as deleted while the run is in flight, Neo leaves that candidate out of the comparison, counts it out of the number in the run message, and continues with the rest. If every candidate it read has gone by then, the run reports that no merge is needed. Not every PSA reports a mid-run deletion, so a candidate deleted moments earlier can still be in the comparison. Rarely, the AI names a ticket that was not one of the candidates it compared. Neo cannot tell which ticket was meant, and a wrong merge would close work nobody has done, so it reports no merge and says so in the run message in **Executions**. The rest of the workflow then runs as normal. **Custom instructions (optional)**: Provide specific guidance about your environment and merge preferences. **Sequential processing**: When several similar tickets arrive within minutes, enable "Process Entities Sequentially" to prevent conflicting merge attempts. **Alert handling (optional)**: For RMM alerts, enable automatic closure of resolved tickets when merging with resolution tickets. Use custom instructions to describe how your resolution tickets look. # Identify Repeated Issues Source: https://docs.neoagent.io/building-automations/actions/ai/identify-repeated-issues Analyze tickets to identify patterns of repeated issues and recurring problems <Info> This action is available only as a **scheduled** action in workflows. </Info> ## Quick start <Steps> <Step title="Set up data collection"> Use "Find Entities" in a scheduled workflow to gather tickets from your desired time period and scope. </Step> <Step title="Add the analysis action"> Add "Identify Repeated Issues" to analyze the collected tickets for patterns. </Step> <Step title="Configure follow-up"> Use "Notify Internal Team" to send reports to your problem management team or service desk manager. </Step> <Step title="Schedule appropriately"> Run weekly or monthly to balance timeliness with system performance and meaningful pattern detection. </Step> </Steps> ## How it works The action identifies patterns as follows: 1. **Groups by company** - Organizes tickets by company for focused analysis 2. **Applies AI clustering** - Uses HDBSCAN algorithm to group similar tickets based on content 3. **Analyzes clusters** - Only considers groups with 3+ tickets to filter out coincidental groupings 4. **Identifies genuine issues** - Uses AI to determine if clusters represent real recurring problems 5. **Generates reports** - Creates comprehensive reports with reasoning, summaries, and affected tickets ## Setup **Report format**: The action generates a single consolidated message containing the analysis for all companies in your ticket set. If no recurring patterns are found, the action returns a message that says no issues were found. # Overview Source: https://docs.neoagent.io/building-automations/actions/ai/intro AI-powered workflow actions — ticket triage, sentiment analysis, dispatch suggestion, ticket QA, customer messaging, duplicate detection, and L1 resolution. Index of the Smart Actions category. AI actions can work alongside your technicians or operate completely autonomously. ## What AI actions can do **Ticket Analysis & Triage** * Automatically categorize new tickets and set appropriate priorities * Analyze customer sentiment to identify frustrated customers * Suggest the best technician for each ticket based on skills and availability **Quality Assurance** * Review completed tickets and time entries for completeness * Ensure technicians follow your documentation standards * Identify tickets that need escalation or additional attention **Customer Communication** * Generate professional acknowledgment messages and status updates * Create personalized responses based on ticket context * Translate messages to different languages automatically **Pattern Recognition** * Find duplicate tickets and suggest merges * Identify recurring issues across your client base * Locate similar historical tickets for faster resolution **Automation & Workflows** * Execute scripts to fix common problems automatically * Build comprehensive L1 support that handles routine issues * Create detailed summaries and reports for stakeholders ## How they work AI actions analyze your existing PSA data to understand patterns and context. They can process ticket descriptions, notes, time entries, and historical data. Most actions provide detailed reasoning for their suggestions. ## Rolling out any AI action The same rollout loop applies to every action in this section, so it is written once here: 1. **Start with the defaults.** Custom instructions are optional on every action; run without them first so you can see the baseline behavior before you shape it. 2. **Read the runs, not the config.** Each run's [Executions](/product/executions) entry shows the actual output and the reasoning behind it. That is where you find out *why* an action chose what it chose. 3. **Then add custom instructions**, one rule at a time, and re-check a few runs after each change. An instruction fixes the case you wrote it for and can shift others. 4. **Analysis actions produce content; a follow-up action applies it.** An action that builds a message or suggests field values changes nothing by itself — pair it with the action that sends or writes (for example "Notify Ticket's Contact" or "Update Ticket Fields"). Each action page's Quick start names its pair. # L1 Engineer Source: https://docs.neoagent.io/building-automations/actions/ai/l1-engineer Automate Level 1 support ticket resolution with script execution or user communication <Warning> **This action is deprecated.** It still works and is not going away without notice, but we recommend building an [Agent](/core/agents) for new automations. An Agent decides for itself which scripts to run and how to talk to the user, rather than following a fixed L1 recipe. </Warning> The action can take ownership of tickets, track time spent, and update ticket status as it works. Configure it to run scripts to fix problems or have conversations with users to gather information and provide solutions. ## Quick start <Steps> <Step title="Choose your approach"> Decide whether Neo Agent should run scripts to fix problems automatically or have conversations with users to gather information and provide guidance. </Step> <Step title="Configure ticket management"> Set up whether Neo Agent should take ownership of tickets, track time spent, and update ticket status as it works. </Step> <Step title="Set approval requirements"> Require human approval before Neo Agent takes action (recommended when starting out). </Step> <Step title="Add custom instructions"> Provide specific guidance on how to handle different types of problems or use company-specific rules. </Step> </Steps> ## How it works The L1 Engineer action can: 1. **Run scripts** - Find and run appropriate RMM scripts to fix issues automatically. 2. **Communicate with users** - Gather details, acknowledge issues, or guide users through solutions. 3. **Manage tickets** - Assign tickets to Neo Agent and track time spent on resolution. 4. **Update status** - Update ticket status based on progress (Neo is Working, Needs Human Help, Resolved). 5. **Request approval** - Request human approval before taking action. The communication path produces a customer message; pair the action with "Notify Ticket's Contact" to send it. ## Setup **Script settings**: When using the script approach, choose the number of attempts and the verification methods. **Communication options**: When using the communication approach, enable acknowledgments, information gathering, and user guidance. **Time tracking**: Configure custom time tracking instructions to match your billing standards. **Company-specific rules**: Pin a [memory](/core/memory) on a company to give this action rules that apply only to that client — an approval requirement, a maintenance window, a device naming convention. Pinned company memories are added to every run; there is no per-action switch. ## Common use cases <AccordionGroup> <Accordion title="Automatic script fixes"> Handle common problems that can be fixed with scripts (like restarting services). Neo Agent finds and runs the right script, then checks if the issue is resolved. </Accordion> <Accordion title="Interactive problem solving"> Handle issues that need more information or user guidance. Neo Agent asks questions, provides troubleshooting steps, and guides users through solutions. </Accordion> <Accordion title="Acknowledge and escalate"> Handle complex issues that need human attention. Neo Agent acknowledges the ticket and marks it for escalation to your technical team. </Accordion> <Accordion title="Intelligent time tracking"> Use custom time tracking rules to log billable time based on work performed, not execution duration. </Accordion> </AccordionGroup> # Onboard/Offboard M365 User Source: https://docs.neoagent.io/building-automations/actions/ai/onboard-offboard-m365-user Automate Microsoft 365 user lifecycle management with comprehensive onboarding and offboarding <Warning> **This action is deprecated and no longer functional.** Build an [Agent](/core/agents) with the Microsoft 365 tools instead. It covers the full onboarding/offboarding lifecycle and is the only supported path today. The page below is kept for reference only. </Warning> This action sets up new users in Microsoft 365 or removes departing users. It creates accounts, assigns licenses, manages mailboxes, and updates your PSA records. <Info> This action is available only as a **triggered** action in workflows. </Info> ## Quick start <Steps> <Step title="Choose process type"> Select whether you're onboarding a new user or offboarding a departing user. </Step> <Step title="Configure approval settings"> Set up human approval via Teams before making changes. </Step> <Step title="Select process steps"> Choose which steps to enable: account creation, license management, group membership, mailbox handling, etc. </Step> <Step title="Add custom instructions"> Provide specific guidance for unique scenarios or company-specific requirements. </Step> </Steps> ## How it works This action manages user lifecycle processes: 1. **Analyzes the request** - Reviews ticket content to understand onboarding/offboarding requirements 2. **Creates execution plan** - Develops step-by-step plan based on your configuration 3. **Requests approval** - Sends approval request to designated approvers if enabled 4. **Executes M365 changes** - Creates/removes accounts, manages licenses, handles groups 5. **Manages security** - Blocks access, handles device wipes, manages mailbox conversion 6. **Updates records** - Creates/deactivates PSA contacts and updates ticket information ## Setup **Process type**: Choose what you want to accomplish: * **Onboard a User**: Set up a new employee with M365 access * **Offboard a User**: Remove departing employee and secure their data **Approval settings**: Have designated people review and approve requests before execution. Select who gets approval requests in Teams. **License management**: Choose how to handle Microsoft licenses: * **Direct Microsoft**: Manage licenses directly through Microsoft * **Pax8**: Use your Pax8 account for license management * **Microsoft Partner Center**: Use Partner Center for licensing **Password handling (onboarding)**: Choose how new passwords are shared: * **Secure Link**: Create a one-time password link via Password Pusher * **Direct Message**: Include password directly in messages * **No Sharing**: Don't share passwords automatically **Process steps**: Control which steps happen during onboarding or offboarding. **Custom instructions (optional)**: Provide specific instructions for unique scenarios or company-specific requirements. <Tip> For companies where users are created in on-prem Active Directory and synced to Microsoft 365, or maintained in both on-prem AD and Entra ID without a sync, follow the [Hybrid AD User Onboarding recipe](/recipes/hybrid-ad-user-onboarding) before running the agent live. </Tip> # Suggest Resolution Source: https://docs.neoagent.io/building-automations/actions/ai/suggest-resolution AI-powered analysis to provide detailed diagnosis and step-by-step resolution plans It looks up similar past tickets and relevant help articles while analyzing a ticket. <Info> This action is only available for **triggered** workflows. </Info> ## Quick start <Steps> <Step title="Add the action to your workflow"> Add the "Suggest Resolution" action to a workflow, usually after a "Ticket Created" trigger. </Step> <Step title="Let it analyze automatically"> The action will automatically analyze the ticket and look for related information. </Step> <Step title="Add custom instructions (optional)"> Add custom instructions to guide the analysis. For example: "For printer issues, always check the print spooler first." </Step> <Step title="Follow up with ticket note"> Follow up with an "Add Ticket Note" action to save the suggested resolution as an internal note on the ticket. Or use "Notify Ticket's Owner" to alert the assigned technician that suggestions are ready. </Step> </Steps> ## How it works This action analyzes ticket information to provide comprehensive resolution guidance: 1. **Analyzes ticket content** - Reviews ticket description, notes, and context 2. **Searches similar tickets** - Looks up past tickets with similar issues and successful resolutions 3. **Reviews documentation** - Checks relevant help articles and knowledge base entries 4. **Generates action plan** - Creates step-by-step resolution suggestions based on findings 5. **Provides reasoning** - Explains why specific steps are recommended, with references to the past tickets and documentation that informed them ## Setup **Ticket to analyze**: Works with any ticket from your workflow trigger or previous actions. **Custom instructions (optional)**: Guide the analysis with specific procedures or preferences. For example: "For printer issues, always check the print spooler first" or "For login issues, include Caps Lock check." Suggestion quality depends on your help articles and past ticket notes. If suggestions are wrong, improve those sources as well as the custom instructions. # Ticket Dispatch (Suggest Technician) Source: https://docs.neoagent.io/building-automations/actions/ai/ticket-dispatch-suggest-technician Intelligently recommend which technician should handle a ticket Neo recommends a technician using availability, skills, current workload, and previous work for the client. <Info> This action can **suggest** a technician. Add the **Assign Ticket to Technician** action afterward to make the assignment in your PSA. **Update Ticket Fields** writes the same suggestion, so either one assigns the ticket. If you leave them both out on purpose, the workflow still works as a suggestion-only dispatcher. Its dispatch result in the Executions message then starts with **"No change was written to the PSA"**, naming the missing action, so nobody reads the suggestion as a completed assignment. The ticket note says the same, when an **Add Ticket Note** action follows Ticket Dispatch to post it. </Info> <Warning> **Triggered workflows only.** Ticket Dispatch is not available in scheduled workflows. A triggered workflow dispatches one ticket per run, so the technician's time slot stays reserved for the whole decision, and the calendar entry is written before the next ticket is decided. A scheduled workflow decides every ticket in its batch first and writes them afterwards, so a long batch can book two tickets into the same slot for one technician. To dispatch on a schedule, use two workflows: a scheduled workflow that finds the tickets and hands each one to a triggered dispatcher with the [Trigger Another Workflow](/building-automations/actions/ai/trigger-another-workflow) action. Scheduled workflows that already use Ticket Dispatch keep running. They cannot be saved again until the action is replaced. While one is still running, any run that books two overlapping entries for the same technician says so in its Executions message, naming both tickets and their times. </Warning> ## Quick start <Steps> <Step title="Choose your trigger"> Add to workflows triggered by "Ticket Created" or when tickets move between boards/statuses. </Step> <Step title="Select your technician pool"> Choose how Neo gets the pool of technicians: manually select them (Dashboard Pool), pull from the ticket's company team, or use the ticket's board team (ConnectWise only). </Step> <Step title="Enable smart features"> Turn on calendar checking and workload balancing (both are on by default). </Step> <Step title="Add assignment action"> Follow this action with "Assign Ticket to Technician" to actually make the assignment. </Step> </Steps> ## How it works Neo considers: 1. **Ticket requirements** - Ticket content, priority, and complexity 2. **Technician availability** - Calendars, working hours, and current status 3. **Expertise** - Similar past tickets and skill areas 4. **Workload** - Current ticket assignments and capacity 5. **Client relationships** - Technicians who have worked with the client before ## Setup ### Technician pool Choose where Neo gets the technicians to consider for dispatch using the **Technician Pool Source** dropdown: <Frame> <img alt="Technician Pool Settings showing the pool source dropdown" /> </Frame> <Frame> <img alt="Technician Pool Source dropdown expanded showing Dashboard Pool, Company Team, and Board Team options" /> </Frame> <Tabs> <Tab title="Dashboard Pool"> **Dashboard Pool** lets you manually select a fixed set of technicians directly in the workflow configuration. This is the default option. Use this when you have a specific team or group of technicians you always want Neo to choose from, regardless of the ticket's company or board. After selecting **Choose technicians and groups**, use the **Technicians and groups** picker below it to add single technicians, [technician groups](/product/technician-groups), or both. The list under the picker shows every technician in the pool. A group's current members join the pool on every run, and dispatch reads the group's [instructions](/product/technician-groups#group-instructions) once. A technician limited to their [preferred companies](/product/technician-companies) leaves the pool for a ticket from any other company, whatever the pool source. </Tab> <Tab title="Company Team"> **Company Team** dynamically fetches technicians from the team assigned to the ticket's company in your PSA. Neo looks up the technicians assigned to that company's account team and considers only those technicians for dispatch. <Info> Make sure your companies have a team assigned in your PSA. If a company has no team configured, Neo won't have any technicians to choose from. </Info> </Tab> <Tab title="Board Team (ConnectWise only)"> **Board Team** builds the technician pool from the team already assigned to the ticket in ConnectWise. 1. In ConnectWise, a board can have **many teams** (e.g., "1st Line Support", "Networking", "Server Team") 2. Each ticket on that board can only have **one team** assigned to it 3. When dispatch runs, Neo reads the ticket's team and pulls that team's technicians into the pool **How does the ticket get a team?** You have two options: * **Manually** - A dispatcher or technician sets the team on the ticket in ConnectWise before the workflow runs. * **Automatically with Triage** - Use the **Ticket Triage** action before dispatch. Triage analyzes the ticket content and assigns the correct team based on your instructions (e.g., "if the ticket is about server issues, assign to the Server Team"). Dispatch then uses the technicians from that team. </Tab> </Tabs> ### Other settings **Smart features**: Enable calendar checking, workload balancing, and expertise matching. **Custom instructions**: Provide specific guidance for your team's needs and preferences. **Scheduling options**: Enable automatic calendar booking to reserve time for assigned work. **Public holidays**: When you set a **holiday source**, Neo reads each technician's holiday list and blocks a holiday by default, the same way it treats time off. A proposed slot that lands on a holiday is rejected, whether or not the technician already has entries on the day: the AI path is sent back for a different day, and Round Robin moves on to the next technician. An urgent ticket does not lift the block. Your **custom instructions** do: say that your technicians work public holidays, or name the dates or the kinds of ticket they cover, and Neo books the slot. On Autotask with the holiday source set to **PSA Holidays**, a technician whose Autotask calendar gives them holiday hours — they work holidays on a reduced schedule — is not blocked. **US Holidays** gives every technician the same list and reads no calendar, so that exception does not apply there; use a custom instruction if your team works some of those days. With the holiday source set to **None**, Neo does not read holidays and does not apply this block. **Today's earlier entries**: By default Neo reads each calendar from the current time onward, so an entry that ended earlier today is not in it. Turn on **Should Neo see today's earlier calendar entries?** when your instructions judge a technician's whole day, such as a cap on booked hours or *"more than five hours of visits means out all day"*. Neo then reads the calendar from the start of the day and marks each finished entry as ended. A finished entry counts toward the day's total and never blocks a new slot. With [Microsoft Teams Shifts](/integrations/teams/workforce-availability) on, Neo also reads the shifts that ended earlier today and marks them as ended, so an instruction such as *"unavailable once their last shift of the day has ended"* can apply. Neo still skips entries marked complete in Autotask and done in ConnectWise. Round Robin does not use this setting. **Round Robin mode (optional)**: Use fair rotation instead of AI optimization for equal distribution. When Round Robin also books calendar time, it reads each technician's calendar across the same **days in the future** window the AI path uses, and honors the same holiday source. So instructions that allow a booking on the next business day are checked against that day's real calendar. Round Robin still asks first whether the technician works today: a technician whose weekly hours are marked not working today is skipped, and no day inside the window is offered for them. **Exclusion rules**: Skip a ticket when it matches a condition you set. The rule **This ticket already has a scheduled entry (service call)** checks the **ticket being dispatched**, not the technician's calendar. It stops Neo from re-scheduling a ticket that is already booked. It does **not** stop two different tickets from being scheduled on the same technician — Neo prevents that same-slot double book on its own, on both the AI and Round Robin paths. That cover is two layers: a reservation between simultaneous Neo runs, and a live re-read of the technician's calendar before Neo settles on the slot. The re-read runs only when the workflow has an Assign Ticket action that books the slot. The second layer looks for a booking made outside Neo, by a technician or by one of your own automations, while Neo was deciding that ticket. When it finds one, Neo picks another slot or technician, and Round Robin moves to the next technician. An entry Neo already saw in the calendar when it chose the slot does not count, so an overlap your instructions allow still goes ahead. The re-read looks at the scheduled work your PSA books against the technician, which on Autotask means service calls. On ConnectWise, an entry that spans several days counts only for the hours it books on each day, the same as in the calendar Neo reads — unless ConnectWise returns the series with no per-day detail rows, or a full page that may be truncated, when Neo treats the whole span as overlapping rather than clearing it. Four rules are checked again after Neo picks a technician, because a dispatch decision takes minutes and the ticket can change in that time. **The ticket is already assigned** skips a ticket a technician claimed while Neo was deciding. **The ticket was resolved or closed by someone else** skips a ticket somebody resolved or closed in that window, so Neo does not reopen it, book a session on it or email the contact about one. **The ticket was merged into another ticket** skips a ticket that was merged away in the same window, so nobody is assigned to a ticket that has been folded into another one. **The ticket was moved to a different status, board/queue or team** skips a ticket somebody re-routed in that window — the case where a technician takes a ticket back out of your dispatch queue by hand, without closing or claiming it. Each rule costs an extra read of the ticket in your PSA, and only when you turn it on. The rules are checked in that order and stop at the first one that fires, so a ticket a technician claimed costs one read even with all four on. The merged rule is available on ConnectWise, Autotask and Halo, the PSAs that report a merge on the ticket itself, so the toggle does not appear on ServiceNow or Syncro. The closed and re-routed rules are available on every PSA. The closed rule compares the ticket against how it looked when Neo selected it, so a workflow that deliberately dispatches resolved or closed tickets is unaffected. On a triggered workflow, Neo selects the ticket when it checks your filter, so a close seconds after that check counts as a change during the decision — for example, from an automation that closes alert tickets soon after they are created. The rule also covers the wait for a [human approval](#human-in-the-loop-approvals): a question or proposal records whether the ticket was open when Neo selected it, and the run that continues it after your answer compares against that record rather than against the ticket as it was after the wait. The re-routed rule does not cover the approval wait, because an answer often moves the ticket itself. The closed rule answers whether the ticket is resolved or closed, which is not the same as your filter's list of statuses: if you exclude a status your PSA does not count as closed — a billing or quoting status, for example — a move to it during the decision is caught by the re-routed rule below rather than this one. The rule also stands down when an earlier action in the same workflow already wrote to the ticket, because Neo then cannot tell its own change from somebody else's. The re-routed rule is the general form of that, and it is the one to turn on if your technicians take tickets out of the dispatch queue by changing the status or moving the ticket to another team. It compares three things against how they looked when Neo selected the ticket: the status, the board or queue, and — on ConnectWise and Halo, where the team is a field of its own — the team. Any of the three moving is a skip. It compares against the snapshot rather than against a list of statuses, so it catches a move to any status you did not expect, including one your PSA does not count as closed, and it leaves a ticket that has not moved alone whatever state it is in. A rename in your PSA is not a re-route. Like the closed rule, it stands down when an earlier action in the same workflow already wrote to the ticket. Because it is the broadest of the four, it is checked last: a ticket that was also claimed, closed or merged is reported under the rule that names the change precisely. ### ConnectWise resource entries In ConnectWise, a ticket **resource** is a schedule entry, so what lands on the **Schedule** tab depends on whether the owner changes: * **Neo assigns a different technician** - ConnectWise adds an open resource entry with no start or end time for the new owner. Any earlier entry stays on the ticket and is no longer marked as the owner's. * **Neo assigns the technician who already owns the ticket** - ConnectWise does nothing. If that technician's only entry is marked **done**, the ticket is left with no open resource entry. This affects tickets that get re-dispatched. | Setting | What it does | When to use it | | - | - | - | | **Also add the assigned technician as an open ConnectWise resource?** | Makes sure the assigned technician has an **open** resource entry with **no start or end time**, adding one only when they don't already have one | Your techs work from the ticket's resource list and you don't book calendar time | | **Should Neo book timed calendar time for the ticket?** (under calendar settings) | Books a **timed** entry in the technician's calendar for the slot Neo picked | You want the work reserved on a calendar | The open-resource setting is off by default and ConnectWise-only. Neo checks the ticket after setting the owner and adds an entry **only if that technician has no open one already**. It never duplicates the entry ConnectWise just created, and re-dispatching the same ticket does not stack entries. When it adds one, it adds a **new** entry; a previous entry marked done stays as it is. It is skipped when Neo is already booking a timed entry for that technician, because that already puts them on the ticket as a resource. Assigning more than one technician (**Add additional resources to tickets?**) has always given the additional technicians an open resource entry; this setting extends the same guarantee to the primary technician. <Note> Custom instructions cannot create resource entries. Those are created by these settings, not by the AI. Wording like *"ensure an open resource entry exists"* in your instructions has no effect. </Note> ### Teams availability (presence & shifts) With the [Microsoft Teams — Technician Mapping](/integrations/teams/workforce-availability) integration connected **and technicians mapped to their Microsoft accounts** (the integration's auto-map does this - see the [setup guide](/integrations/teams/workforce-availability#set-it-up)), the **Teams availability** toggle makes dispatch aware of each technician's live Microsoft Teams presence and, optionally, their Teams Shifts rota: * **Skip technicians who are on a break** (on by default) - Technicians who are Away, Offline, or out of office in Teams are not assigned work starting now. Busy, In a call, Presenting, Do not disturb, and Be right back still count as working. The check is time-scoped: a schedule entry booked further in the future is not blocked by someone being on a break right now. * **Teams holding the shift rota** - If your service desk runs its schedule in the Teams **Shifts** app, list the team(s) here. Neo prefers technicians whose shift covers the proposed assignment time and deprioritizes mapped technicians with no shift in the planning window. Neo also reads each shift's **label** (an on-site client name, or an absence marker like *Annual Leave*) and, from the same team(s), each technician's **time off** with its reason. An absence reason (*Annual Leave*, *Sickness Absence*, *Bank Holiday*) excludes them outright even if their PSA calendar looks clear. A reason that records where they are working (*London Office*, *Working from Home*, *On Call*) is read as context. If Teams cannot be reached or technicians are not mapped, dispatch falls back to its normal PSA-based logic and the run output says why. Round Robin honors the on-break skip too (shifts apply to AI dispatch only). Custom instructions override the defaults - e.g. *"Treat Do not disturb as unavailable"* or *"Ignore Teams presence for P1 tickets"*. If presence is not being picked up as expected, see the integration page's [troubleshooting section](/integrations/teams/workforce-availability#troubleshooting). ### Human in the loop (approvals) The **Human in the loop** step decides when Neo must ask a person before a dispatch is applied. Requests arrive as Teams cards and on the dashboard's [Approvals page](/core/technician-in-the-loop#approvals-in-the-dashboard); answering in either place resolves both. Pick one of three modes: | Mode | What Neo does | | - | - | | **Never** (default) | Dispatches autonomously. | | **Always ask first** | Decides, then waits - a person approves every assignment before it is applied. | | **Ask only when unsure** | Dispatches routine tickets itself and asks only on a genuine dilemma: it can't meet the SLA, it would need to double-book someone, your instructions conflict for this ticket, or no technician is eligible. A ticket your custom instructions say to leave unassigned is left unassigned with no question (see "Tickets nobody should take" below). | Then pick who receives the card and can answer: * **Approvers** - people. Each one gets the card in their own Teams chat. The list shows the people in your connected directory who use the Neo Agent app in Teams. Someone who is missing opens the Neo Agent app in Teams and sends it one message, then appears in the list. * **Teams channels & chats** - Neo posts one card in each, and anyone in the channel or chat can answer. Use this when a team of dispatchers shares the work. See [Approvals in a Teams channel or chat](/core/technician-in-the-loop#approvals-in-a-teams-channel-or-chat). Pick at least one person or channel. Choose **who approves the dispatch**: | Setting | Who gets the card and can approve | | - | - | | **Configured approvers** (default) | Everyone on the approver list, and every channel and chat you picked, receives the card and any of them can approve; the first answer wins. | | **Proposed technician only** | Only the technician Neo proposes receives the card in Teams, and only that technician can approve their own assignment there. Your channels and chats get no card. | | **Proposed technician plus configured approvers** | The technician Neo proposes receives the card and can approve their own assignment, and your configured approvers can still approve any dispatch. Use this when leads need to answer on a technician's behalf. | Both proposed-technician settings need Neo to find the technician's Microsoft Teams user. Neo first matches on the Entra mapping from the [Microsoft Teams — Technician Mapping](/integrations/teams/intro) integration. For a technician who has no such mapping, Neo matches their name against the people registered with the Neo bot, and the name must be exactly the same. Neo sends the card to the configured approvers, channels and chats instead - so a ticket is never left stranded - when the technician has no match, when two registered people share the name, or when the technician is mapped to a Microsoft account that never registered with the Neo bot. "Ask only when unsure" questions have no proposed technician, so they always go to the configured approvers. These settings control the Teams card. On the dashboard's Approvals page, an admin can still answer any pending request for the tenant. **While a request is waiting**, the ticket is parked: later runs skip it (free) and the execution shows **Paused**. It stays parked until someone answers, so keep an eye on the Approvals page's pending count. **Answering an "Always" proposal** - the card shows the technician, the time slot, and any existing calendar entries Neo will move to make room: * **Assign to \<technician>** - Neo applies exactly what the card shows, with no new decision and no new availability check, so what you approved is what happens. The [exclusion rules](#other-settings) still apply, checked against the ticket as it is when Neo resumes after your answer. The button carries the proposed technician's name, so you can answer without reading the rest of the card. * **Offer to someone else** - Neo re-decides and offers the ticket to the next available technician. The person Neo had proposed is taken out of the pool, and the next card names everyone who has already declined. A text box is offered here and is **optional**: fill it in (e.g. *"afternoon only, or try Alex Carter"*) and Neo follows your note while still excluding the decliners; leave it empty and Neo simply picks the next technician. Neo keeps advancing on each further decline until someone approves. When every technician in the pool has declined, the ticket parks once with a message that names who declined and says the pool is exhausted - assign it by hand or add technicians to the pool. An exclusion lasts only while the ticket is unchanged. If the ticket is then updated in your PSA, that is a new situation: Neo decides again from the full pool, so someone who declined earlier can be proposed once more. * **Don't assign** - Neo stops dispatching this ticket and leaves it for manual assignment. An owner already on the ticket stays. Use it when the ticket should not be routed at all - you are taking it yourself, or it needs a decision before anyone works it. Unlike the other two answers, this one does **not** expire when the ticket changes. A decline says "not right now", so a PSA update is fair reason to ask again; this says "not at all", and a new note on the ticket is no reason to overrule it. To hand the ticket back to Neo, assign it in your PSA. <Note> The exclusion applies to the **technician Neo proposed**, not to whoever pressed the button. With **Proposed technician plus configured approvers**, a lead who declines on a technician's behalf is still asked about the next proposal for that same ticket. </Note> <Note> The dashboard's Approvals page offers the same three answers on a dispatch proposal, so an admin working the inbox is not limited to approve-or-stop. Answering many requests at once still offers only approve and reject, and a bulk reject means **Don't assign** - passing a ticket to the next technician is a decision about that one ticket. </Note> **Answering a "When unsure" question** - the card asks which technician should take the ticket and offers 2-4 assignments: * **Pick a technician and Submit answer** - Neo decides again with your pick as the answer, and assigns that technician. * **✏️ Guide Neo to make another assignment decision** - Type your own instruction (it overrides any selected option); Neo decides again following it. Your instruction wins even over the workflow's standing rules - including working hours - so be as specific as you like. * **Submit with nothing selected** - Neo decides with its best judgment. * **Don't assign** - Neo stops dispatching this ticket and leaves it for manual assignment. An owner already on the ticket stays. Like the same answer on an "Always" proposal, it does **not** expire when the ticket changes, so Neo will not come back with the question on the next PSA update. Assign the ticket in your PSA to hand it back to Neo. <Note> After you answer, Neo decides one more time, and that decision does not ask again: it assigns a technician, or leaves the ticket unassigned if your answer says so. A later run on the same ticket is a new decision and can ask a new question. If a ticket should not be dispatched at all - it is spam, closed, merged, or you are handling it yourself - press **Don't assign**. </Note> <Note> **Credits**: a dispatch that asks costs the same one credit as a dispatch that doesn't. The run that decides (or asks the question) bills one credit per ticket; waiting is free, and applying your answer - including the re-decision after a note - is free. See [Billing](/product/billing-and-credits#ticket-dispatch). </Note> <Tip> **Tickets nobody should take.** If your custom instructions say to leave a kind of ticket unassigned (for example *"Spam, recruitment emails and backup reports that show success: do not assign a technician"*), "When unsure" follows them and asks nothing. Neo quotes the instruction it followed on the run page. The rule must be in your instructions: when Neo only finds that nobody is free or eligible, it still asks. Write the rule as a sentence that names the kind of ticket: Neo quotes at least 15 characters of it, so a rule as short as *"Spam: no tech"* still gets a question. </Tip> <Tip> **A technician's own rule and a rule for everyone.** With AI dispatch and **Include AI profile** on, a technician's own custom instructions (on their [profile](/product/technician-profiles)) decide for that technician when they differ from a dispatch instruction that covers every technician, such as *"pick the lowest workload"*. Neo follows the technician's rule for them, the general rule for everyone else, and asks nothing. Two instructions that both name the same technician can still be a real conflict, and "When unsure" asks about those. </Tip> <Tip> "When unsure" only asks when no lawful decision exists. If your instructions leave Neo an escape - e.g. *"assign backup tickets to Casey"* plus *"don't schedule Casey on weekends"* on a Saturday - Neo will book Casey for Monday rather than ask. If tickets that feel like dilemmas aren't producing questions, tighten the time bounds in your instructions (*"...scheduled the same day the ticket arrives"*). </Tip> ### Writing effective custom instructions Use clear, specific custom instructions: <Tip> **Key principles for good custom instructions:** * Always use full names (first and last) for technicians * Write dates in full format (e.g., "2nd October 2025" instead of "02/10/25") * Be specific about clients, ticket types, or conditions that trigger the rule * Identify exact technicians, skill tags, or team names for routing </Tip> #### Examples: Good vs. Bad | ❌ Bad | 🤔 Why It's Problematic | ✅ Better Approach | | - | - | - | | "Jordan is off 02/10/25-11/10/25" | Ambiguous date format (US vs. UK) and missing last name make it hard for Neo to identify the right person | "Jordan Kim is on PTO from 2nd October 2025 to 11th October 2025 - exclude from assignment suggestions during that period" | | "Send security issues to Priya" | Too vague-which clients? What severity level? No context for when this applies | "Critical network outages for Apex Fabrication must go to Priya Shah or Mateo Alvarez" | | "Don't assign waiting tickets" | Unclear what "waiting" means-could be a status, board, or custom field | "When calculating workload, ignore tickets in the 'Waiting on Customer' status so team members are not penalized for stalled work" | #### Reserving time on a technician's day Some rules reserve space on the calendar instead of ruling a technician out - a lunch gap that can fall anywhere in a window, travel time between onsite visits, a morning kept clear, a cap on booked hours. Neo treats these as hard constraints and judges the day as the booking would **leave** it, using the arithmetic your rule states: the gap either side of a slot for a spacing rule, the day's booked total for a cap, and whether a qualifying stretch survives for a rule that protects free time somewhere inside a window. Name the window, the amount to keep free, and who the rule covers: * *"For Dana Ruiz and Sam Okafor, keep at least one continuous unbooked 30-minute gap between 11:30 and 14:30 on every working day."* * *"Leave an hour between onsite visits for travel."* * *"Cap each technician at 6 booked hours a day."* A rule that names technicians applies to those technicians only. When no slot on a day can satisfy the rule, Neo books a later day or another technician rather than taking the reserved time. ## What you get <Tip> **Running this action on high-volume workflows?** See [Parallel Dispatch](/building-automations/managing-workflows/parallel-dispatch) - Neo Agent automatically prevents double-bookings when multiple dispatches run at the same time, so you can drop the **Process Entities Sequentially** safety knob and recover full burst throughput. </Tip> ## Best practices <AccordionGroup> <Accordion title="Enable smart scheduling"> You can control the name of the booked entry through your custom instructions - for example, *"Name every schedule entry 'NEO - \[client] - \[short summary]'"*. If you don't specify a naming convention, the entry is named after the ticket title (the default). **HaloPSA appointment types:** Neo can set the appointment *type* on the entries it books (e.g. Firm vs Tentative, Remote vs Onsite) from your own Halo appointment types. Two ways to control it, and they work together: * **Default appointment type** - A dropdown in the calendar settings, populated from your Halo appointment types. Neo puts this type on every entry it books unless a per-ticket rule overrides it. * **Per-ticket, from custom instructions** - Tell Neo which type to use per situation, for example *"Use 'Firm - Remote' for strictly scheduled remote tickets and 'Tentative - Remote' for work that just needs to happen sometime today; use the Onsite equivalents for on-site visits."* Neo matches the name to your tenant's appointment types. If a ticket matches no rule and no default is set, the entry keeps Halo's own default type. **HaloPSA appointment body:** Tell Neo what the appointment body should contain and it writes that text into the appointment's note - for example *"Put the caller's name, phone number and a one-line summary in the appointment body."* If you sync your Halo appointments to Outlook or Teams, this is what technicians see in the calendar event. Say nothing about the body and the appointment is created without one, as before. </Accordion> <Accordion title="Prevent re-processing assigned tickets"> To prevent Neo from re-processing tickets that already have an owner, add a Filter Ticket condition to your Dispatch workflow: <Tabs> <Tab title="ConnectWise Manage"> Add a filter condition: **`owner.id` is null** </Tab> <Tab title="Autotask"> Add a filter condition: **`assignedResourceID` is null** </Tab> </Tabs> This ensures Neo will never re-process tickets that already have an assigned technician, even if the workflow triggers late. </Accordion> </AccordionGroup> ## Frequently asked questions <AccordionGroup> <Accordion title="How does Neo calculate technician workload?"> Neo calculates workload based on settings you configure under "Consider technician Workload" in dispatch settings: * **Time period**: Choose how many days back Neo should look (e.g., last 7 days), up to 90. Set it to 0 to count today only, from midnight in your timezone * **Activity criteria**: Select what counts as activity: * Ticket last update (any change to the ticket) * Last ticket time entry (logged work time) * Last ticket note (comments or updates) * All open tickets (no time window) — open tickets count however long ago they were touched Neo lists each technician's workload as one row per ticket: the ticket number, status, board or queue, the hours when your criteria uses hours, and the title, followed by the totals. Neo counts open tickets that had the selected activity within your chosen time period, whatever their board. Two kinds are never counted: tickets your PSA reports as closed, and tickets whose status name contains **Complete** (for example `Completed - Portal` or `Work Complete~`), which many boards leave open for a survey or billing step. Every other status counts. If you want to filter by specific status, board, or any other field, you can customize this in custom instructions. For example, "When calculating workload, exclude tickets on the 'Waiting for Customer' board/status." Workload measures who is busy now, so the time period is capped at 90 days: a ticket nobody has touched for longer is not current work, and counting it means the technician with the most dormant tickets looks the busiest. Pick **All open tickets** when you want open tickets counted regardless of age. Neo reads no notes and no time entries for the count, and the ticket search carries no date, so it returns your whole open backlog instead of a recent slice. Neo's ticket search reads a fixed number of pages, so a very large open backlog can reach that limit and the tickets past it are not counted. The limit applies to every workload setting, and removing the time window is what makes a backlog most likely to reach it. * **Exclude child (bundled) tickets**: When on, Neo does not count a technician's child tickets toward their workload. Turn this on when related tickets are bundled under a parent ticket, so a technician is not counted once per bundled ticket. Available for ConnectWise, Halo, ServiceNow, and Syncro (Autotask has no parent-ticket concept). Each workload row shows its parent ticket when it has one, so you can reference the relationship in custom instructions too. Start with a 7-day lookback period using "Ticket last update". </Accordion> <Accordion title="How does Neo spread tickets evenly across the team?"> Turn on **"Should Neo balance assignments using this workflow's history?"** under "Consider technician Workload". Neo then counts how many tickets this workflow has already given each technician and prefers the one with the fewest. **What the counts cover.** Only the tickets this workflow dispatched. A ticket a dispatcher assigned by hand in your PSA, or one another workflow assigned, is not counted. If you want your rule to mean every assignment, say so in your custom instructions and expect Neo to work from its own figures. **Assignment history window.** Set it to `0` for today only, counted from midnight in your timezone. Set any higher number and Neo gets two counts to compare instead of one: today's, and the wider window. A rule with two tiers needs both, so a window of `7` is what makes an instruction like this work: ``` Route to the engineer with the fewest tickets assigned today. If two are within 2 of each other, prefer the one with fewest over the last 7 days. ``` With the window at `0`, the second line has no data behind it and Neo cannot apply it. **Where it ranks.** Assignment history is its own step, ahead of workload and expertise. Neo names the technician with the fewest assignments and compares each candidate against that figure. If your custom instructions state a different order, Neo follows yours instead — for example "current workload is only a balancing factor and should not outweigh assignment history". Availability still comes first. A technician on zero assignments who is on lunch, off shift, or inside an appointment is not selected on count alone. </Accordion> <Accordion title="How do I set up technician work schedules for dispatch?"> Neo automatically reads technician working hours from your PSA system. To set them in Neo instead, with breaks, night shifts and time zones, put technicians on a schedule on the [**Technicians** → **Schedules**](https://dashboard.neoagent.io/profiles?view=schedules) tab: a schedule replaces the PSA hours for that technician. See [Technician working hours](/product/technician-working-hours). To keep the hours in your PSA, the setup depends on which PSA you're using: <Tabs> <Tab title="ConnectWise Manage"> **Setup in ConnectWise Manage:** 1. Create different calendar templates for each work schedule (e.g., "7AM-4PM Schedule", "8:30AM-5PM Schedule", "9AM-6PM Schedule") 2. Assign the appropriate calendar to each technician in their member profile 3. Neo will automatically use these calendars when checking availability **For your example schedules:** * Create a "7AM-4PM" calendar and assign it to your 2 help desk technicians * Create an "8:30AM-5PM" calendar for your 2 technicians with that schedule * Create a "9AM-6PM" calendar for your 1 technician with that schedule </Tab> <Tab title="Autotask"> **Setup in Autotask:** Neo reads working hours from your Autotask calendar. **Important:** Neo cannot see Outlook events-it only sees the Autotask calendar. Working hours are defined under Internal Locations in Autotask. 1. In Autotask, go to **Admin** > **Organization Settings and Users** > **Your Organization** > **Internal Locations** > **Select your Organization** > **Hours** 2. Configure your organization's standard working hours 3. Neo will use these business hours when checking technician availability **For technicians with different working hours:** If you have technicians with different schedules from your standard internal location hours, you have two options: **Option 1: Create separate internal locations (most robust)** 1. Create another internal location in Autotask with different working hours 2. Assign that internal location to the technician 3. Neo will automatically detect and respect each technician's assigned location hours **Option 2: Use custom instructions (most simple)** Add specific instructions to your Neo workflow's custom instructions. For example: "Henry's working hours are from 8:30 AM to 5:30 PM - do not assign any tickets to him outside these hours." "When dispatching tickets before 8:30 AM, prefer technicians on the 7AM-4PM schedule. For tickets after 5 PM, prefer technicians on the 9AM-6PM schedule." </Tab> <Tab title="Halo PSA"> **Setup in Halo PSA:** Neo reads working hours directly from each agent's profile in Halo. Each agent can have their own timezone and work schedule configured individually. 1. In Halo, go to **Configuration** > **Teams & Agents** > **Agents** 2. Select the agent you want to configure 3. In the **Details** tab, configure the following fields: * **Time Zone**: Set the agent's timezone (e.g., "(UTC-05:00) Eastern Time (US & Canada)") * **Work Hours**: Select the appropriate working hours template (e.g., "Default Working Hours" or a custom schedule) <Frame> <img alt="Halo agent profile showing Time Zone and Work Hours configuration" /> </Frame> **For technicians with different schedules:** Since Halo allows per-agent configuration, edit each agent's profile to set their specific timezone and work hours. Neo will respect each agent's individual schedule when making dispatch suggestions. </Tab> </Tabs> </Accordion> <Accordion title="Why was a ticket left unassigned after a busy morning?"> During a burst, Neo limits how many tickets one technician can be handed in a short window (three per rolling five minutes). When that limit is reached, Neo re-picks a different technician - one your custom instructions still allow - for the tickets over the cap. This burst limit is a **soft** cap, not a hard failure: if no other technician fits under it, Neo still makes the assignment rather than leaving the ticket unassigned, and Executions records that it fell back. That holds both when Neo keeps re-picking the same rate-limited technician and when it finds no substitute your rules allow — either way the technician the cap blocked gets the ticket, because they already satisfied your rules. Neo won't route around a rule you declared (for example *"Escalation Team → do NOT downgrade to lower teams"* or *"Security Incidents → only the Security Squad"*) to get past the limit. A ticket is left unassigned when no technician is admissible in the first place — everyone is off, out of hours, or excluded by your rules. Executions then shows "No technician recommendation found" along with the reason. With **Human in the loop** set to **Ask only when unsure**, Neo asks an approver instead, and the ticket waits for the answer. It asks when it found nobody to assign, and when every technician it re-picked is at the limit. When your rules allow only the rate-limited technician, Neo assigns them and asks nothing. The one exception is a ticket your custom instructions say to leave unassigned: Neo leaves it unassigned with no question, and Executions shows "Left unassigned by your custom instructions" with the instruction it followed. See [Parallel Dispatch](/building-automations/managing-workflows/parallel-dispatch#per-technician-burst-limit) for the full behavior. </Accordion> <Accordion title="Why was a ticket booked after its SLA deadline?"> For a ticket that is not urgent, the SLA deadline is a soft limit. Neo first looks for a slot that ends before the deadline. When the technician has no free time before it, Neo books the first free slot after the deadline rather than leaving the ticket unassigned, and Executions records that it fell back. With **Human in the loop** set to **Ask only when unsure**, Neo asks an approver about that late slot instead. An urgent ticket (one whose priority is in **Which priorities can jump the queue?**) is never booked after its SLA deadline; see the next question. </Accordion> <Accordion title="Why was an urgent ticket left unassigned overnight or at the weekend?"> An urgent ticket must start within 24 hours and finish inside its SLA deadline, whichever comes first. When the ticket arrives outside working hours, the earliest free slot can be the next business morning, which is past that limit. No technician can take it, so Neo leaves it unassigned. Neo finishes the run and records why the ticket was not assigned, naming the ticket, the technician it tried, the slot it found and the limit that rejected it. That reason is in the run's entry in Executions. To have it sent to you as well, add a [Notify internal team](/building-automations/actions/notify/notify-internal-team) action after Ticket Dispatch. To change this: * Narrow **Which priorities can jump the queue?** so fewer tickets carry the 24-hour limit. * Set **Human in the loop** to **When unsure**, which asks a technician to decide instead of leaving the ticket unassigned. * Add out-of-hours cover to the technician schedules Neo reads. </Accordion> <Accordion title="Which technician gets an urgent ticket?"> An urgent ticket is one whose priority is in **Which priorities can jump the queue?**. 1. Your **custom instructions** decide first. A rule such as *"Never assign a technician who is in an appointment"* applies to urgent tickets too. To treat urgent tickets differently, say so in the instruction, for example *"High and Critical tickets may go to a technician whose appointment title contains Office Hours."* 2. Time off, sick days and vacations always rule a technician out. So does a public holiday, unless your custom instructions allow holiday work. 3. Without guidance in your custom instructions, Neo picks a technician who is free soon: free now, or in an entry that ends within 60 minutes. When the ticket's SLA respond-by time is less than 60 minutes away, the entry must end before that time. When Neo books a time, the booking starts when that entry ends. A technician whose entries keep them busy for longer than that counts as away. 4. When every technician on shift is away, Neo picks the one who is free first today, and can double-book over a Tentative entry to do so. It does not hold an urgent ticket for the next business day while a technician is on shift. </Accordion> <Accordion title="How do I assign multiple technicians?"> You can configure Neo to suggest multiple technicians for a single ticket using the "Number of technicians to suggest" setting. **To set up multiple technician suggestions:** 1. Open the **Configure Message Settings** section in your Ticket Dispatch action 2. Find the **Number of technicians to suggest** field 3. Increase this number to however many technicians you want suggested (e.g., 10) <Frame> <img alt="Number of technicians to suggest setting" /> </Frame> **How multiple technicians are assigned:** When you use the "Assign Ticket to Technician" action after getting multiple suggestions, the PSA will assign them differently based on your system: <Tabs> <Tab title="ConnectWise Manage"> * **First technician**: Assigned as the ticket Owner (primary resource) * **Additional technicians**: Added as Resources (secondary resources) </Tab> <Tab title="Autotask"> * **First technician**: Assigned as the Primary Resource * **Additional technicians**: Added as Secondary Resources </Tab> <Tab title="HaloPSA"> * **First technician**: Assigned as the ticket Owner * **Additional technicians**: Added to Halo's standard **Additional Agents** field, and to **Other Attendees** on the appointment when the dispatch also books one </Tab> </Tabs> The Halo field uses agent objects with `id` and `name` values. Neo merges new agents with the agents already on the ticket, so a dispatch does not remove a technician added by hand. **Halo appointments and additional technicians:** a Halo appointment belongs to one agent, so Neo books it for the first technician. When the dispatch also picks additional technicians, Neo puts their email addresses in the appointment's **Other Attendees** field, taken from each agent's email in Halo. You do not need a custom instruction for this — it happens whenever a dispatch produces both a booking and an additional technician. An additional technician with no email address on their Halo agent record is left off the attendee list; the Additional Agents field on the ticket still names them. <Note> Other Attendees records who shares the appointment. Whether Halo then emails those people or copies the appointment onto their own calendar depends on your Halo notification settings, not on Neo. </Note> </Accordion> </AccordionGroup> # Ticket Escalation Source: https://docs.neoagent.io/building-automations/actions/ai/ticket-escalation Evaluate tickets against predefined criteria to determine if they need escalation <Note> Looking for how your **branded Chat Agent** hands a ticket to a technician, or which status it moves the ticket to? That's a different feature - see [handing a ticket to a technician](/agents/tools/end-user/overview#handing-a-ticket-to-a-technician). This page is about the workflow action that escalates tickets on a timer or against criteria. </Note> ## Quick start <Steps> <Step title="Add to monitoring workflow"> Add the action to workflows that check tickets for escalation conditions, either time-based or criteria-based. </Step> <Step title="Choose escalation method"> Select time-based escalation (for SLA monitoring) or custom criteria escalation (for content-based decisions). </Step> <Step title="Configure escalation actions"> Set up what happens when escalation occurs: remove owner, change status, or continue workflow. </Step> <Step title="Add follow-up actions"> Use "Notify Internal Team" for alerts and "Update Ticket Fields" to apply status changes. </Step> </Steps> ## Setup **Ticket to evaluate**: The action works with any ticket from your workflow that you want to check for escalation. **Escalation method**: Choose how to determine if escalation is needed: * **Time-based**: Escalates if the monitored fields remain unchanged for a defined period. Choose what to watch: status, owner, and/or board/queue. Or select **Any Ticket Update** to watch the ticket's last-updated time in the PSA so any change cancels the escalation. Depending on the PSA, some notes or time entries may not move that timestamp * **Custom criteria**: Uses AI and your specific instructions to decide on escalation **Custom instructions (optional)**: When using custom criteria, provide detailed instructions for the AI to evaluate the ticket. **Escalation actions (optional)**: * Remove the current technician from the ticket when escalated * Set a new status when the ticket is escalated. Any status name you provide must match an existing, valid status in your PSA * Control whether the workflow continues only if escalation occurs **Time settings (optional)**: For time-based escalation, set how many minutes to wait before escalating (up to 60 minutes). Pick a timeout that matches your SLAs and capacity; very short timeouts cause unnecessary escalations. # Ticket QA Source: https://docs.neoagent.io/building-automations/actions/ai/ticket-qa Review completed tickets and give them a quality score based on your standards <Warning> **This action is deprecated.** It still works. For new automations, we recommend building an [Agent](/core/agents). An Agent can read the ticket, apply your quality standards, and write the score back in one step. </Warning> Ticket QA is available only as a **triggered** action in workflows. ## Quick start <Steps> <Step title="Add to closure workflow"> Add the action to workflows triggered when tickets are marked as resolved or closed. </Step> <Step title="Define scoring criteria"> Set up your quality standards including what aspects to evaluate and your scoring scale (1-5, 1-100, etc.). </Step> <Step title="Configure storage (optional)"> Set up custom fields in your PSA to store quality scores and detailed explanations. </Step> <Step title="Add follow-up actions"> Use "Update Ticket Fields" to save scores and "Notify Internal Team" to alert about low-quality tickets. </Step> </Steps> ## How it works 1. Reviews ticket content - Examines notes, resolution details, and communication history 2. Applies your criteria - Evaluates aspects like resolution clarity, response time, and professionalism 3. Assigns scores - Provides numerical quality score based on your scale 4. Documents reasoning - Explains why the score was given and what could be improved 5. Stores results - Can save scores and explanations in custom PSA fields ## Setup **Scoring criteria**: Define what makes a good ticket resolution, including aspects to evaluate, scoring scale, and weight for each criterion. **Storage options**: Choose whether to save scores and explanations to custom fields in your PSA. **Review scope**: Decide whether to include Neo Agent's automated actions in the quality review. **Custom field names**: Specify which PSA fields to use for storing quality scores and explanations. The custom fields you choose must be set up as text fields in your PSA, and the names must match exactly. # Ticket Summary Source: https://docs.neoagent.io/building-automations/actions/ai/ticket-summary Generate concise summaries of PSA tickets Choose either a resolution-focused summary or a general overview of a ticket's history and content. <Info> This action is available only as a triggered action in workflows. </Info> ## Quick start <Steps> <Step title="Add to ticket workflow"> Add the action to workflows triggered by ticket status changes, typically when tickets are closed or resolved. </Step> <Step title="Choose summary type"> Select "Resolution" for closure documentation or "General Summary" for ticket overviews. </Step> <Step title="Add follow-up action"> Use "Update Ticket Fields" (Autotask) or "Add Ticket Note" (ConnectWise) to save the summary. </Step> <Step title="Test and verify"> Check Executions to ensure summaries meet your documentation standards. </Step> </Steps> ## How it works The action generates summaries based on your selected type: 1. **Analyzes ticket content** - Reviews all ticket information, notes, and time entries 2. **Retrieves pre-computed data** - Uses AI-generated issue descriptions and resolution steps 3. **Formats appropriately** - Creates resolution-focused or general overview summaries 4. **Prepares outputs** - Generates messages for notes and field updates for PSA systems ## Setup **Summary type**: Choose between: * **Resolution** (default): Focuses on how the issue was fixed, ideal for populating resolution fields * **General Summary**: Provides a broader overview of the ticket's history and key points ## Common use cases <AccordionGroup> <Accordion title="Populate resolution fields (Autotask)"> Automatically populate Autotask resolution fields when tickets are closed with concise summaries of how issues were fixed. </Accordion> <Accordion title="Add resolution notes (ConnectWise)"> Create formal resolution notes for ConnectWise tickets upon closure since ConnectWise doesn't have dedicated resolution fields. </Accordion> <Accordion title="Complex ticket overviews"> Provide quick understanding of tickets with extensive history when assigned to new technicians or for management review. </Accordion> </AccordionGroup> # Ticket Triage Source: https://docs.neoagent.io/building-automations/actions/ai/ticket-triage Automatically analyze incoming tickets and fill in important details Ticket Triage can move tickets to the right queue or board. It also analyzes incoming tickets and fills in important details like priority, type, company, and contact information. ## Quick start <Steps> <Step title="Add to new ticket workflow"> Add the action to workflows triggered by "New ticket created" to automatically categorize incoming tickets. </Step> <Step title="Choose fields to fill"> Use the **Add field to triage** button and pick the fields you want completed - priority, type, company, contact, custom fields, and so on. The picker stays open, so you can add several in a row, and it only lists the fields your PSA supports. </Step> <Step title="Add custom instructions (optional)"> Open a card's **Advanced settings** and turn on **Use your own instructions** to give Neo specific guidance for that field. Under the box, **Adjust with Neo** opens the Neo Support chat for that one field. Say what the field should do and Neo drafts or changes the instructions, shows you the before and after, and applies it once you confirm. It writes that field alone and leaves the other cards untouched. Save the workflow first: Neo reads the saved version, so the button waits while you have unsaved edits. </Step> <Step title="Add update action"> Follow with "Update Ticket Fields" to actually apply the suggested changes to your tickets. </Step> </Steps> <Info> Ticket Triage decides the field values; a later action writes them to your PSA. That action is **Update Ticket Fields**, or — for an Autotask tag — **Add Ticket Tag** in its default mode (its *add tag to all tickets* mode writes a fixed tag and applies nothing the triage decided). Leave the writer out and the workflow still reports what it decided. When the run decided at least one change, its result in the Executions message starts with **"No change was written to the PSA"**, naming the missing action. A run that changed nothing — every field left on its current value — has nothing to apply, so it gets no such line. The ticket note says the same, when an **Add Ticket Note** action follows Ticket Triage to post it. </Info> ## Configuring the fields Each field you add becomes its own card. The card names the field and says in one line what Neo does with it, so a whole triage setup reads top to bottom without opening anything. * **Adding a field**: use the **Add field to triage** button. A field you already added drops out of the list, so you cannot triage the same one twice. * **Nothing to fill in**: most fields work straight away on Neo's defaults. Priority, Status, Type and the rest ask you nothing when you add them. * **A custom field asks for two things**: its name in your PSA, and where its options come from. Those sit directly on the card, because Neo cannot triage the field without them. If you pick **Fixed List**, type at least one option — an empty list gives Neo nothing to choose, so the workflow will not enable until you fill it in or pick a different source. * **Tuning a field**: everything optional lives under the card's **Advanced settings**. You get only the settings that field actually has - the ones for other fields are not shown. * **Reading a saved setup**: each card shows a small tag for every setting you changed, for example *Custom instructions* or *Limit the options: 3*. * **Changing a field**: remove the card and add a new one for the field you want instead. * **After triage**: moving the ticket to a board or queue is a separate step at the bottom, not one of the fields. ## How it works The action: 1. **Analyzes ticket content** - Reviews title, description, conversation history, and related information. Screenshots are read with a vision model and `.eml` and `.pdf` attachments are read as text, so a custom instruction can use what is in them (see [Reading Images](/core/reading-images) and [Reading Email and PDF Attachments](/core/reading-email-attachments)) 2. **Identifies key details** - Extracts company, contact, and issue type information 3. **Applies smart categorization** - Uses patterns from past tickets and your custom instructions 4. **Sets appropriate priority** - Determines urgency based on impact and affected users 5. **Suggests field updates** - Provides recommendations for all configured fields The action processes fields in order: basic information such as company and contact first, then categorization, then priority. ### Contacts that share a name Some companies keep several contacts with the same name, for example one "General User" for each site. When Neo matches the contact by name and several contacts share that name, Neo chooses in this order: 1. The ticket's current contact, if Neo's name search returns it as one of them. The search returns at most 100 contacts. 2. On Halo, the one contact at the ticket's site. 3. On Halo, if the ticket's site has none of them, the one contact at the client's main site. This rule covers an alert that arrives on a catch-all client and that Neo then moves to the right client: the ticket's site still belongs to the catch-all client. On Halo, if none of these rules gives exactly one contact, Neo does not pick one of them, and the triage reasoning says how many contacts share the name. Neo uses rules 2 and 3 only when its name search returns fewer than 100 contacts, because a longer search can leave out contacts with the same name. On ConnectWise, Autotask, ServiceNow and Syncro, contacts have no site that Neo compares. If rule 1 does not apply, Neo takes the first match, and the triage reasoning says how many contacts share the name. To always get one specific contact, give it a unique name in your PSA and use that name in the contact field's custom instructions. ### Autotask contract options include exclusions When triaging the **contract** field on Autotask, each contract option also tells Neo which work types that contract does **not** cover, so it can separate covered work from billable work instead of falling back to the company default: ``` Not covered by this contract (billable outside it): BAS, Monitoring Work excluded from this contract should be billed to the contract 'Facturabel' instead. ``` This lets you write instructions like *"never pick a contract whose exclusion list contains the ticket's work type"*. Neo reads this from your contracts' **exclusion sets** and any **per-contract exclusions** you have configured in Autotask, and covers both at once. Nothing appears for a contract that has no exclusions configured, including one that points at an exclusion set you have left empty. In that case, Autotask itself holds no exclusion data for Neo to use. If a contract's exclusions are missing from triage, check that its exclusion set actually lists work types in Autotask. ### Autotask list custom fields Each option of an Autotask list UDF has a **Display Value** and a **Stored Value**. Autotask accepts a value on a ticket only when it matches a **Stored Value**. With **Fixed List**, Neo writes the option exactly as you typed it on the card. So type each option's Stored Value, or give each list option in Autotask the same Stored Value as its Display Value. If Autotask rejects the value and the same ticket update writes other fields, Neo still writes those fields and skips only the rejected value, so the workflows that run after triage still start. Tags and secondary resources go through their own Autotask endpoints rather than the ticket update, so a triage that sets only a tag and a rejected list field leaves nothing in the update to write, and it stops. Neo also sends an Inbox message and an email that name the field and the rejected value. ### Syncro fields you can triage On Syncro, the field picker offers: | Field | What Neo sets it from | | - | - | | **Subject** | Rewrites the ticket title from its content | | **Problem Type** | Picks from your Syncro problem types | | **Status** | Your Syncro status list | | **Priority** | Your Syncro priorities | | **Company** | Matched from the ticket content | | **Contact** | Matched from the ticket content | | **Ticket Type** | Your Syncro ticket types | | **Due Date** | Set from the ticket's urgency and content | | **Tags** | Adds a tag you describe in the instructions | | **Custom Field** | Your ticket-type custom fields | Neo only picks from the problem types your Syncro account already has. Add one in Syncro and triage can use it straight away: it reads the list from Syncro rather than waiting for a sync. <Note> Syncro itself accepts any text in Problem Type, so it will not reject a value that is not on your list. Neo restricts itself to your list, which is what keeps the field consistent enough to report on. </Note> #### Syncro tags Syncro has no fixed tag list, so tell Neo what to apply in the field's custom instructions. This is the same as tags on Autotask. A tag card sets **Where the options come from** to **Free Text** for you, which is what sends Neo to your instructions. Switch it to **Fixed List** and type the tags if you would rather Neo chose from a set list. Leave the list empty and the workflow will not enable, because an empty list gives Neo nothing to choose. Triaging a tag **adds** it. The ticket's existing tags are left alone, and re-running the workflow will not add a duplicate. Turning on **Let Neo clear this field** lets Neo clear the tags instead, which removes **all** of them. Syncro's API has no way to remove just one. <Tip> **Triage Ticket Type before Custom Field in the same workflow.** Neo already orders it that way: the type decides which custom fields a ticket can hold, so settling it first is what makes custom-field triage useful. </Tip> #### Syncro custom fields Custom fields in Syncro belong to a **ticket type**, so a ticket can only hold the fields its type defines. Enter **Custom field name** on the card exactly as it appears in Syncro. Capitalisation does not have to match, but the name does. If the name matches no field on that ticket's type, the workflow stops with an error listing the fields the ticket does have. That is deliberate: Syncro accepts an unrecognised field name without complaint and saves nothing, so a silent success would be worse. Updating one custom field leaves the ticket's others untouched. ## Setup **Company rules (optional)**: pin a [memory](/core/memory) on a company to give this action rules that apply only to that client. Pinned company memories are added to every run; there is nothing to switch on. ## Common use cases <AccordionGroup> <Accordion title="Clean up descriptions without summarizing"> For the **Description** field (Autotask), the **Summarize description** toggle is on by default. Neo rewrites the body into a brief 2-5 sentence summary. Turn it **off** to use the field for targeted cleanup only: combine it with custom instructions to strip email-security banners, hyperlinks, or signatures while keeping the original wording and length intact. With the toggle off and no custom instructions, Neo leaves the description unchanged. </Accordion> <Accordion title="Set due dates from your own rules"> Write your due-date rules in the **Due Date** field's custom instructions, in plain language. Neo reads them and computes the date. Rules you can write: * **Lead times per priority**: "Priority 1 = due in 1 day, Priority 2 = due in 3 days, Priority 3 = due in 5 days, Priority 4 = due in 14 days". * **Business days or business hours**: "16 business hours", "14 business days from the ticket creation date". Business hours count only the open hours you set in Settings. Business days step over your non-working days and keep the time of day the starting point had. Both read the weekday in your Settings timezone. * **A date the ticket states**: "If the client provides a due date, use it" — or an offset from it: "set the due date to the day before the stated deadline". * **A clock time**: "next business day at 8am". * **From the current due date**: "move the due date forward 1 day". * **Weekend rule**: "if the due date falls on a Saturday or Sunday, move it to the following Monday". * **Guards**: "only when the status is Waiting Kit", "do not change the due date for spam". Neo never invents the date arithmetic: your rule picks the starting point and the offset, and the date is computed in code from them. The same rule, the same starting point, and the same business hours and timezone in Settings always give the same date. Two starting points move on their own. A rule that counts from the current time re-triages to a later date, because the current time has moved. A deadline the ticket states in words — "by next Friday", "the 2nd" — is read out of the ticket text against the date of the run, so a re-triage on another day can read it as another date; a deadline written as a calendar date does not move. </Accordion> <Accordion title="Keep due dates off weekends"> Add one sentence to the **Due Date** custom instructions: "if the due date falls on a Saturday or Sunday, move it to the following Monday". This covers every due date — your own rules, the default priority lead times, and a stated weekend deadline alike. Neo judges the weekday in your Settings timezone and keeps the time of day. It works as your only due-date instruction too; the earlier **Move weekend due dates to the following Monday** toggle is retired in favor of the written rule. </Accordion> <Accordion title="Fix catch-all tickets"> Find the real company and contact for tickets logged against a generic "Unknown" company, from email signatures and ticket content. </Accordion> <Accordion title="Post-resolution categorization"> Set the final service category or billing type from the work actually done, on tickets that are marked resolved. </Accordion> </AccordionGroup> ## Default priority instructions The following instructions are used by default when determining ticket priority. You can override them in Ticket Triage action settings. ``` ## How to determine Priority - Priority is determined by urgency and impact - Urgency is how quickly the issue needs to be resolved - Impact is how many people are affected by the issue #### Definitions: - **Urgency - Low**: One user or a small group of users is affected - **Urgency - Medium**: Departments or large groups of users are affected - **Urgency - High**: The whole company is affected - **Impact - Low**: More of an irritation than a stoppage - **Impact - Medium**: Business is degraded, but there is a reasonable workaround. - **Impact - High**: Critical - Major business processes are stopped, there is no reasonable workaround #### Priority Matrix: | | High Urgency | Medium Urgency | Low Urgency | |---------------|--------------|----------------|--------------| | High Impact | PRIORITY 1 | PRIORITY 2 | PRIORITY 2 | | Medium Impact | PRIORITY 2 | PRIORITY 3 | PRIORITY 3 | | Low Impact | PRIORITY 3 | PRIORITY 3 | PRIORITY 4 | ### Additional Instructions - "Priority 1 - Emergency Response" is rather rare and extreme. Choose it ONLY if the issue is absolutely critical - "Priority 4 - Scheduled Maintanence" is rather rare and extreme. Choose it ONLY if the issue is absolutely not important - Usually you will choose "Priority 3 - Normal Response" or "Priority 2 - Quick Response" - Choose "Priority 3 - Normal Response" for quote requests - If you are not sure what to choose or there is not enough information to determine urgency, impact or priority - go with "Priority 3 - Normal Response" - If it appears that the ticket is a question, you should assume it's a "Priority 4" ### Acceptance criteria 1. Determine urgency 2. Determine impact 3. Use the Priority Matrix and Additional Instructions to pick Priority based on Urgency and Impact 4. Follow custom instructions to amend the priority choice 5. Explain your reasoning, urgency choice, impact choice, priority choice in "justification" section of your response ``` ## Frequently asked questions <AccordionGroup> <Accordion title="What does 'Keep current value' mean in the triage note?"> For every field it triages, Neo makes one of three decisions, and the triage note on the ticket reports each one: * **Match found**: Neo picked a value and updated the field. The note shows the predicted value and the reasoning. * **Verified - left unchanged**: Neo examined the field and actively confirmed the existing value matches the ticket. Nothing was written, on purpose: the field was already right. * **No update applied - left unchanged**: Neo could not make a decision for this field (for example, no options were available for the ticket's company), so it left it untouched. Every outcome is followed by the reasoning behind it, so a field left unchanged tells you *why*. The most common reason is one of your own custom instructions on that field. If a field consistently comes back unchanged when you expected an update, the reasoning line will name the rule that caused it. A run where many fields come back "verified" is a healthy sign: it means the ticket arrived mostly correct, not that triage stopped working. If a field has **no value at all**, Neo never reports it as "verified": it either picks the best matching option or states that none of the available options fit. </Accordion> <Accordion title="Why did Neo change the ticket contract when I don't have contract updates enabled?"> This happens in Autotask when a ticket's contract belongs to a different company than the ticket. Autotask rejects the whole update until the two match, so Neo replaces or clears the contract to let the rest of its updates land. Two situations lead there. **Neo changes the company during triage.** Here's what's happening behind the scenes: 1. **The ticket already has a contract** attached from the original company 2. **Neo identifies the correct company** during triage and attempts to update it 3. **Autotask prevents the company change** because the existing contract belongs to the old company, not the new one 4. **Neo removes the old contract** to allow the company change to proceed 5. **Neo applies the default contract** for the newly assigned company 6. **If that company has no default contract**, or Autotask rejects it too, Neo leaves the contract empty and applies the rest of its updates **A technician changes the company in Autotask while Neo is working on the ticket.** Neo is not touching the company field here: its update fails because the contract still on the ticket belongs to the previous company. Neo re-reads the ticket to get its current company, then applies steps 5 and 6 above. This is an Autotask system limitation, not a Neo configuration issue. When a ticket has a contract attached, Autotask requires that any company change must use a contract associated with the new company. <Info> To avoid the first situation, you can exclude the Company field from your Ticket Triage action configuration. However, this means tickets with incorrect company assignments won't be automatically corrected. The second situation starts with a company change made in Autotask, so no Ticket Triage setting prevents it. </Info> </Accordion> </AccordionGroup> # Time Entry QA Source: https://docs.neoagent.io/building-automations/actions/ai/time-entry-qa Analyze time entries against defined criteria and provide quality assurance scores Use this action in a triggered workflow to evaluate one or more time entries against custom instructions. It assigns each entry a numerical score and provides reasoning based on the criteria. <Info> This action is available only as a **Triggered** action in a workflow. Let us know if you'd like to use it as a Scheduled one. </Info> ## What It Does * Evaluates one or more time entries based on custom instructions you provide. * Assigns a numerical score to each time entry. * Generates detailed reasoning explaining how the score was determined based on the provided instructions. * Optionally stores the QA score in a specified custom field in your PSA for the corresponding time entry. * Provides feedback messages for internal review and dashboard visibility. ## How It Works The "Time Entry QA" action processes time entries as follows: ### Input Data The action receives the time entry or entries to analyze and instructions that define the QA criteria. ### QA Process For each time entry, an AI agent evaluates its content, such as notes and summary, against the configured `instructions`. The instructions define what to look for and how to score the time entry. ### Scoring and Reasoning The AI agent assigns a numerical `score` to the time entry and provides textual `reasoning` explaining how the entry met or failed to meet the specified criteria. ### Output Structure The action outputs QA results, including messages for internal MSP use containing the score and reasoning, messages for the Neo Dashboard, and field updates when configured to save the score in a custom field. ## Setup **Time entry to analyze**: The action works with any time entry from your workflow trigger, typically the time entry that was just created or updated. **Quality criteria**: Define your QA standards by providing detailed instructions on how to score time entries. Specify what makes a good time entry, what to check, and your scoring scale, such as 1-5 or 0-100. A default set of instructions is provided. Tailor it to your own standards and terminology. **Save results (optional)**: Choose whether to save the QA score in a custom field in your PSA system, and specify which field to use. ## Use Cases ### Automated Time Entry Audits Set up a workflow that triggers when a time entry is created or updated. The "Time Entry QA" action can assess the entry against your standards, such as completeness of notes, correct work type, and billable status. ### Enforce Billing Accuracy Use the `instructions` to define criteria for entries that contain sufficient detail for client billing, such as clear descriptions of work performed and time spent. ### Technician Feedback and Training Use QA scores and reasoning to provide feedback to technicians on their time entries. If the score is saved to a custom field, you can build PSA reports or dashboards to track QA metrics. ## Best Practices * If you store the score in a custom field (`store_score_in_custom_field`), ensure that a text-based custom field with the exact `score_custom_field_name` exists in your PSA for time entries. * Follow this action with a "Notify Internal Team" or "Add Ticket Note" action to communicate QA results or flag entries below a score threshold. # Time Entry Triage Source: https://docs.neoagent.io/building-automations/actions/ai/time-entry-triage Review time entries for completeness and accuracy It detects missing notes, incorrect work types, billing compliance issues, and policy exceptions in time entries. <Info> This action is available for both **triggered** and **scheduled** workflows. </Info> ## Quick start <Steps> <Step title="Add to time entry workflow"> Add the action to workflows that process time entries, either when created or during review periods. </Step> <Step title="Define review criteria"> Set up criteria for what constitutes complete and accurate time entries based on your billing standards. </Step> <Step title="Configure follow-up actions"> Use "Update Time Entry Fields" to apply corrections and "Notify Internal Team" to alert about issues. </Step> <Step title="Test and monitor"> Review results in Executions and adjust criteria based on your team's time tracking patterns. </Step> </Steps> ## How it works The action reviews time entries: 1. Checks notes, work types, billable status, and duration. 2. Validates that required information is present. 3. Checks entries against your billing and policy standards. 4. Flags missing notes, incorrect categories, or policy violations. 5. Provides recommendations for improving entries. ## Setup **Time entries to review**: Works with time entries from your workflow trigger or previous actions. **Fields to triage**: The fields you can pick depend on your PSA, because each PSA names and models them differently — ConnectWise time entries carry an agreement, Autotask time entries carry a contract. The builder only lists the fields your own PSA has, so choose from the dropdown rather than copying a field name from another PSA's setup. **Review criteria**: Define standards for complete time entries, including required note details, appropriate work types, and billing compliance rules. **Custom instructions (optional)**: Provide specific guidance for your billing standards and time tracking policies. ## Common use cases <AccordionGroup> <Accordion title="Billing compliance review"> Check time entries for billing accuracy before approval, including documentation and work type classification. </Accordion> <Accordion title="Missing notes detection"> Identify time entries with incomplete or missing notes. </Accordion> <Accordion title="Work type validation"> Verify that time entries use correct work types and service categories for reporting and billing. </Accordion> <Accordion title="Policy exception flagging"> Detect time entries that violate company policies, such as excessive hours or inappropriate billing categories. </Accordion> </AccordionGroup> ## Example workflows <AccordionGroup> <Accordion title="Weekly billing compliance check"> 1. **Trigger:** Scheduled workflow (weekly) 2. **Find Entities** — get all time entries from the past week 3. **Time Entry Triage** — review for billing compliance 4. **Notify Internal Team** — alert managers about flagged entries </Accordion> </AccordionGroup> # Trigger Another Workflow Source: https://docs.neoagent.io/building-automations/actions/ai/trigger-another-workflow Initiate a separate, pre-configured Neo Agent workflow from within your current workflow Use this action in a Scheduled workflow to start a Triggered workflow once for each ticket in a list. <Info> This action is available only as an action within a **Scheduled** workflow. It is used to trigger other **Triggered** workflows which will then process individual entities. </Info> ## What It Does The action takes a list of PSA tickets and a target workflow ID as input. For each ticket in the list, it initiates an individual execution of the specified target workflow, making that target workflow behave as if it were triggered for that single ticket. ## How It Works ### Input Data Within a Scheduled workflow, this action typically receives a list of PSA tickets from a preceding "Find Entities" action. It also requires the ID of the target workflow you intend to trigger for each of these tickets, and an option to bypass that target workflow's own ticket filter conditions. ### Workflow Initiation For each ticket in the provided list, Neo Agent retrieves the definition of the target workflow using its ID. ### Event-Driven Trigger for Each Entity Neo Agent starts an independent instance of the target workflow for each ticket. The `bypass_filter_ticket_conditions` setting determines if the target workflow's initial filters are ignored for these individual ticket processing instances. ### Output The action outputs a confirmation message indicating how many tickets the target workflow was triggered for. This message is available for subsequent actions or for logging purposes within the parent Scheduled workflow. ## Setup **Target workflow**: Select which Neo Agent workflow you want to trigger for each ticket. You can find the workflow ID in the URL when editing the target workflow or on the main Workflows page. **Filter bypass (optional)**: Choose whether to ignore the target workflow's ticket filter conditions: * **Enabled (default)**: The target workflow runs for all tickets passed from this action, regardless of its own filters * **Disabled**: The target workflow applies its own filters to each ticket before running ## Use Cases ### Automated Ticket Dispatching A Scheduled workflow uses "Find Entities" to identify all newly created, unassigned tickets. The "Trigger Another Workflow" action then initiates a dedicated "Dispatch Workflow" for each of these tickets. This target "Dispatch Workflow" processes one ticket at a time and can contain actions like "Ticket Dispatch (Suggest Technician)" followed by "Assign Ticket to Technician". ### Conditional Escalation Workflow A Scheduled workflow finds tickets meeting certain criteria (e.g., overdue, high negative sentiment). The "Trigger Another Workflow" action then initiates a specialized "High Priority Escalation Workflow" for each of these specific tickets. The escalation workflow then handles the individual ticket's escalation logic. ### Modular Issue Resolution A Scheduled workflow with an "Identify Repeated Issues" action detects a common problem across multiple tickets. It uses "Trigger Another Workflow" to start a specific "Automated Fix Workflow for Problem X" for each of the identified tickets. ## Best Practices * **Ensure the target workflow is ready:** Before you use this action, confirm the target workflow is configured, tested, and enabled in Neo Agent. * **Understand `bypass_filter_ticket_conditions`:** Carefully consider this setting. If the parent Scheduled workflow already precisely filters the tickets, setting `bypass_filter_ticket_conditions` to `True` is usually appropriate. If the target workflow has specific entry criteria that must *always* be met even for these individually triggered instances, set it to `False`. * **Monitor Both Workflows:** When troubleshooting, check Executions for both the parent Scheduled workflow and the individual instances of the target workflow that were triggered. * **Consider Sequential Processing in Parent Workflow:** If the "Find Entities" action in your Scheduled workflow might return a very large number of tickets, and the triggered target workflows perform resource-intensive tasks, you might still want to enable "Process Entities Sequentially" in the *trigger settings* of the parent *Scheduled* workflow. This controls how the parent workflow iterates through its found entities before invoking the "Trigger Another Workflow" action for each. <Warning> Avoid circular triggers. Use labels or status markers to prevent loops. </Warning> # Overview Source: https://docs.neoagent.io/building-automations/actions/notify/intro Send notifications from a workflow via Email, Slack, Teams, or SMS — for end users (ticket contact) or internal teams. ## Channels * Email * Slack * Teams * SMS ## Sending only in certain cases Custom instructions on a notify action can be conditional. Write the condition in plain language and Neo sends nothing when it is not met: * `Only notify for P1 and P2 tickets. For P3 and below, send no notification.` * `Do not send a message if a technician was assigned.` When the condition is not met, no message is delivered and no notification is recorded. The action itself still runs and still reports a result, so you will see it as skipped rather than failed. On **Notify Internal Team**, the run's output says the notification was skipped because the custom instruction's condition was not met, and an instruction with no condition always sends. Instructions that set the format, choose the fields, or describe what an earlier action did (`After assigning the ticket, send one Slack message`) are not conditions. Neo decides once for each message, before it writes anyone's copy, so every recipient of the action gets the same send-or-skip decision. <Note> State the condition as something the notification's own content can settle, such as the ticket priority or whether an assignment was applied. Neo judges the condition from the messages the earlier actions produced and the [ticket facts below](#ticket-facts-a-custom-instruction-can-use), so a condition that depends on a value neither mentions cannot be evaluated reliably. The ticket's description is not one of those facts. To notify only when the client asked for something urgently or by a set time, have your triage write that into a field, such as the due date or the priority, and word the condition on that field: `Only notify when the ticket is due within 4 hours.` </Note> A conditional instruction is a filter on the message, not on the workflow. Every earlier action still runs, and the ticket is still processed. To stop the work itself, use the ticket conditions on the action that finds the tickets. ## Ticket facts a custom instruction can use This section covers the actions that notify your own people: **Notify Internal Team**, **Notify Ticket's Owner** and **Notify Ticket's Resource**. **Notify Ticket's Contact** writes to the end user through a different path and does not receive these details. Neo gives the notification the details of the ticket the message is about, so your instruction can ask for them by name: company, contact, board or queue, status, owner, priority, type, subtype and item, the created, closed and due dates, and the SLA targets. That is normally the ticket that triggered the workflow. When an earlier action produced a message about a different ticket, the details follow that one, so they match the ticket named in the message heading. When an earlier action in the same run assigned the ticket or updated its fields, Neo reads the ticket again before the notification, so the details show the values that action wrote. It also gives Neo how long the ticket has held its **current status**, so you can ask for that directly: * `State how long the ticket has been in its current status.` The figure is counted in business hours, using the business hours set for your account, not wall-clock time. A ticket that changed status at 16:45 on Friday reads as a few minutes on Monday morning, not a whole weekend. <Note> Neo leaves the line out rather than guess, so write the instruction so the message still reads correctly without it. The figure is left out when the notification is not about one identifiable ticket, which is the usual case for a scheduled run covering many of them; when your PSA is not ConnectWise, Autotask or Halo, which are the three whose audit trail Neo can read; and when the audit trail records no status change for the ticket in the last 30 days, which also covers a PSA that is not answering. </Note> On ConnectWise and Autotask the same figure is also available when you choose which tickets to act on: add the **Minutes spent in current Status** ticket condition on the action that finds the tickets. Halo has the figure in the message but not as a condition. Note that a workflow triggered by a status change sees a value near zero, because the status has only just changed. # Notify internal team Source: https://docs.neoagent.io/building-automations/actions/notify/notify-internal-team Send updates to internal channels for coordination This action sends notifications to internal team members through Microsoft Teams, Slack, or email. ## How it works ### Message collection The action takes messages from previous workflow steps, such as analysis results, summaries, or alerts, and prepares them for delivery. ### Context addition If the workflow was triggered by a ticket, it automatically adds ticket details: ID, title, and company. ### Attachment preparation For email notifications, it can convert data tables from previous actions, such as reports, into CSV files. ### Notification delivery Based on your chosen channel, it sends the information to the specified team members, channels, or email addresses. ### Optional feedback If enabled, it includes a feedback link so recipients can provide input on the automated process. ## Setup **Message source**: Takes messages from previous actions like Ticket Triage, Data Analysis, or Build Message. **Communication channel**: Choose how to notify your team: * **Teams** - Send to specific users or Teams channels * **Slack** - Send to Slack channels or direct messages * **Email** - Send traditional email with optional attachments **Recipients**: Specify who receives the notifications: * **Teams Users**: Select team members who have the Neo AI Agent Teams app installed * **Teams Channels & chats**: Post to a Teams channel or group chat the Neo app is in. Pick it from the list (channels show as *Team / Channel*, group chats show their name). You can mix channels, chats, and individual users in one action. See [Post to a Teams channel or chat](/integrations/teams/intro#post-to-a-teams-channel-or-chat) * **Slack Channels**: Specify Slack channel IDs for notifications * **Email Addresses**: Add email addresses for recipients **Data attachments (optional)**: For email, attach CSV files with detailed data from previous actions. **Feedback requests (optional)**: Add feedback links to gather input on automated processes. The action shows which notifications were sent successfully and details about any failed notifications and why they failed. <Note> Recipients here are fixed when you build the workflow — every run notifies the same people and the same channels. To have the destination depend on the ticket (for example, message whichever technician the ticket is assigned to in that technician's own chat), build an [agent](/core/workflows-vs-agents) with the [Send Teams Message tool](/agents/tools/communication/send-teams-message) instead, which chooses the recipient per run. </Note> ## Use cases ### Report analysis results **When:** After a Data Analysis action creates a report **Setup:** 1. Data Analysis - Generates a detailed report or table 2. Notify Internal Team - Sends the report to managers via email with CSV attachment ### Alert on critical issues **When:** High-priority or unassigned tickets are detected **Setup:** 1. Filter Tickets - Find tickets meeting specific criteria 2. Build Message - Create alert summary 3. Notify Internal Team - Send immediate Teams alert to support managers ### Workflow completion updates **When:** Complex automated workflows complete (successfully or with issues) **Setup:** 1. Any complex workflow (like L1 Engineer attempts) 2. Notify Internal Team - Inform L2 support team about results ### Quality assurance alerts **When:** Ticket QA scores fall below acceptable levels **Setup:** 1. Ticket QA - Reviews completed tickets 2. Conditional logic - Check if scores are below threshold 3. Notify Internal Team - Alert quality managers ### Executive summaries **When:** Scheduled reports need to go to leadership **Setup:** 1. An [Agent](/core/agents) - Analyzes tickets from the past period and writes the report 2. Notify Internal Team - Email the report to executives ## Best practices ### Monitor success Check Executions to ensure notifications are being delivered successfully and identify any delivery issues. ## Communication channels ### Microsoft Teams * Recipients must have the Neo AI Agent Teams app installed * Works with both direct messages and channel notifications * Supports rich formatting and interactive elements ### Slack * Requires proper Slack channel ID configuration * Works with your existing Slack workspace * Integrates with Slack's notification preferences ### Email * Works with any email address or distribution list * Supports CSV attachments for detailed data * Professional formatting for formal communications **Email subject:** By default, Neo sends a standard subject line. To customize it, turn on **Customize email subject** and edit the template using these variables, which fill in per ticket: `{workflow_id}`, `{workflow_name}`, `{ticket_number}`, `{ticket_title}`, `{company}`. To send the email with no subject line, turn on **Suppress email subject**. # Notify ticket contact Source: https://docs.neoagent.io/building-automations/actions/notify/notify-ticket-contact Send updates to the end user on the ticket This action sends messages to customers who submitted tickets. <Info> This action is available for both **Triggered** and **Scheduled** workflows. </Info> ## How it works ### Message collection The action sends messages prepared by other actions, such as L1 Engineer responses or Build Message content. ### Translation (optional) If you've enabled a different language, the messages are translated automatically. ### Delivery method Based on your settings, the action either: * **Adds a Ticket Note:** Creates a customer-facing note that your PSA emails out * **Creates a Time Entry:** Makes a time entry with the message that gets emailed ### Delay (optional) The action can wait a random amount of time before sending. ### PSA integration The action uses your PSA's built-in email system to send messages. ## Setup **Message source**: Takes messages from previous actions like L1 Engineer, Build Message, or Acknowledge Issue. **Delivery method**: Choose to add a ticket note or create a time entry with the message. Use Ticket Notes for most customer communications. Use Time Entries when you need to track billable communication time. **Add delays (optional)**: Add a random wait time between 10-20 minutes. **Translation (optional)**: Use custom instructions to send the message in another language, for example "Send the message in French". Any language the model supports works; the four names here are only examples. **Skip closed tickets**: Don't send messages for tickets that are already resolved. This setting is on by default; leave it on unless you must reply on closed tickets. For each ticket, the action reports the result in the [Executions](/product/executions): the message that was sent, or a warning that explains why the ticket was skipped. ## Use cases ### Automatic first response **When:** New ticket is created **Setup:** 1. L1 Engineer analyzes the ticket and creates a response 2. Notify Ticket's Contact sends the response to the customer **Result:** Customers get immediate acknowledgment and next steps ### Follow-up reminders **When:** Tickets are waiting for customer response for several days **Setup:** 1. Chase Customer action creates a polite follow-up message 2. Notify Ticket's Contact sends the reminder **Result:** Customers get gentle reminders without manual effort ### Resolution confirmation **When:** Technician completes work on a ticket **Setup:** 1. Build Message creates a "work completed" message 2. Notify Ticket's Contact asks customer to confirm resolution **Result:** Customers know work is done and can verify everything works ### Multilingual support **When:** Serving customers who speak different languages **Setup:** 1. Build Message creates response in English 2. Notify Ticket's Contact translates to customer's language **Result:** Customers receive communications in their preferred language ## PSA-specific notes ### ConnectWise * Uses automatic email flags to trigger customer notifications * Works with your existing ConnectWise email templates * Integrates with ConnectWise's built-in notification system * Ensure email notifications are enabled for customer notes. ### Autotask * Can use UDF workflows for advanced email control * Supports Autotask's time entry notification system * Works with Autotask's contact management features * Set up the UDF workflow if using that option. ### HaloPSA * Select the correct **Outcome** in the action settings to trigger an email to the end user. HaloPSA uses outcomes to determine whether a ticket note generates an outbound email. Without the right outcome selected, the note will be added to the ticket but no email will be sent. * The available outcomes are loaded from your HaloPSA configuration. Check your HaloPSA admin settings to see which outcome is configured to send customer emails. * A **Respond Automatically** Outcome also logs the ticket's first response and marks the response SLA as met — see [End-User Communication](/integrations/psa/end-user-communication#by-psa) for how that works. # Notify ticket owner Source: https://docs.neoagent.io/building-automations/actions/notify/notify-ticket-owner Update the assigned owner with key changes This action sends notifications to the assigned owner of a ticket via Microsoft Teams or email. ## How it works ### Input data The action receives a list of tickets, messages to be sent (typically from previous actions), and configuration for the notification channel, CSV attachment, and feedback request. ### Owner identification The system uses the TicketOwnerProvider to determine the assigned owner of each ticket. This provider fetches the owner's details from your PSA. For Microsoft Teams notifications, it attempts to map the PSA user to a Neo Agent user. For email, it uses the owner's email address from the PSA. ### Message assembly If the workflow is triggered by a single ticket, the owner receives a notification pertinent to that ticket. The ticket ID, title, and company are automatically prepended to the notification header for context. ### Notification dispatch Based on the selected notification channel: * **Microsoft Teams:** Sends messages to the ticket owner. For this to work, the owner must have the Neo AI Agent Teams App installed and have interacted with it. * **Email:** Sends emails to the ticket owner's email address. If a data table is provided, it will be converted to a CSV file and included as an attachment. ### Feedback request (optional) If enabled, a standardized feedback request link is appended to the messages, allowing the ticket owner to provide feedback on the workflow or the information received. After running, you'll see a summary of notification attempts including which owners were successfully notified and any failed attempts. The action doesn't consume any credits. In a Triggered workflow, when the ticket has no owner, or the owner cannot be reached on the selected channel, the summary names that channel, for example "No notification was sent: no Email recipient was found for ticket ...". ## Setup **Tickets to process**: The action works with tickets from your workflow that have assigned owners. **Message content**: Takes messages from previous actions to send to the ticket owner. **Data attachments (optional)**: Include data tables as CSV attachments (primarily used with email notifications). **Notification method**: Choose between Teams messages (default) or email notifications. **Feedback requests (optional)**: Include a feedback link in notifications. ## Use cases ### Alert owner on high-priority ticket assignment **Setup:** 1. Ticket Dispatch (Suggest Technician) - Suggests an owner 2. Assign Ticket to Technician - Assigns the ticket in PSA 3. Notify Ticket's Owner - Informs the newly assigned owner about the high-priority ticket ### Inform owner of automated actions **Setup:** 1. L1 Engineer - Attempts to resolve a ticket or gather more info 2. Notify Ticket's Owner - If L1 Engineer took some actions but couldn't fully resolve, notify the owner with a summary of what was done and what still needs attention ### Notify owner of customer reply on an awaiting ticket **Trigger:** When a customer replies to a ticket that is in "Awaiting Customer" status **Setup:** 1. Build Message - Craft a message like "Customer has replied to ticket \[Ticket ID]" 2. Notify Ticket's Owner - Send the alert to the ticket owner ### Notify owner of new ticket assignment **Scenario:** When a new ticket is assigned to a technician (either manually or by an action like Assign Ticket to Technician or Ticket Dispatch), send them a notification. **Steps:** 1. Workflow Trigger: Ticket Owner Changed OR after "Assign Ticket to Technician" / "Ticket Dispatch" action # Notify ticket resource Source: https://docs.neoagent.io/building-automations/actions/notify/notify-ticket-resource Send notifications to assigned resources on tickets This action sends notifications to the assigned resource(s) and owner of a PSA ticket. <Info> This action is available for both **Triggered** and **Scheduled** workflows. </Info> ## How it works ### Input data The action receives a list of tickets to process and a list of messages containing the content for the notification. It also uses configuration settings like the notification channel. ### User identification For each ticket, the action identifies the assigned resource(s) and the owner: * **ConnectWise**: It retrieves the ticket owner, any explicitly assigned resources on the ticket, and resources associated through the ticket's agreement. * **Autotask**: It retrieves the primary resource (owner) and any secondary resources assigned to the ticket. Neo Agent then maps these PSA resources to their corresponding Neo user profiles to determine the notification recipients and their contact details for the selected channel. For **Teams** delivery, a resource is matched by name against the people who have the Neo Teams app installed. Resources without the app are skipped for Teams. They can still be reached via the **Email** channel, which uses the resource's PSA email address directly. ### Message preparation * **Triggered Workflows**: The messages from previous actions are combined into a single notification for the identified users for that ticket. * **Scheduled Workflows**: If the action receives a data table from a preceding "Data Analysis" action, notifications can be tailored. The system processes this dataframe, and for each user who is a resource/owner of a ticket in the dataframe, it compiles a message based on the data rows relevant to them. If feedback is enabled, a link to provide feedback on the workflow action is appended to the message. When custom instructions are enabled, the message is rewritten per recipient, and any greeting or direct address names the recipient of that copy. A co-resource never receives a message greeting the assignee. ### Notification dispatch Based on the selected notification channel: * **Teams**: A message is sent to each identified user via the Neo AI Agent Teams app. * **Email**: An email is sent to each identified user. If a data table was provided and processed (typically in Scheduled workflows), the relevant portion of the dataframe might be included as a CSV attachment in the email. The action logs all notification attempts and their outcomes (success or failure) in Executions. In a Triggered workflow, when the action finds no recipient for the ticket, Executions shows a line that names the selected channel, for example "No notification was sent: no Teams recipient was found for ticket ...". This happens when the ticket has no assigned resource, or, on Teams, when no assigned resource has the Neo Teams app. ## Configuration <ParamField type="array"> The list of PSA tickets for which resources and owners should be notified * In **Triggered** workflows, this is typically the single ticket that triggered the workflow * In **Scheduled** workflows, this can be a list of tickets found by a preceding "Find Entities" action </ParamField> <ParamField type="array"> A list of WorkflowMessages objects containing the messages to be sent to the ticket's resource(s) and owner. This is typically provided by the output of a preceding action like "Build Message" or an AI analysis action. </ParamField> <ParamField type="enum"> Determines how the notification is delivered to the users * `TEAMS` (default) * `EMAIL` </ParamField> <ParamField type="boolean"> If set to True, a link will be appended to the notification message, allowing the recipient to provide feedback on this workflow action (default: False) </ParamField> ## Output <ResponseField name="credits_consumed" type="number"> The number of Neo Agent credits consumed by this action. Notifying ticket resources does not consume any credits (default: 0). </ResponseField> ## Use cases ### Notify technician of new ticket assignment **Trigger:** Ticket Updated (e.g., owner assigned by "Dispatch Ticket" or "Assign Ticket" action) **Setup:** 1. Build Message - Creates a message like "You have been assigned ticket \[TicketNumber] - \[TicketSummary]" 2. Notify Ticket's Resource - Sends the assignment notification to the new owner via Teams If your dispatch process adds a team of co-resources to each ticket and you want only the assigned engineer pinged, use the **Notify Ticket's Owner** action instead. This action messages every resource on the ticket. ### Alert resource about escalated ticket **Workflow:** Triggered when a ticket is escalated (e.g., by "Ticket Escalation" action) **Setup:** 1. Build Message - "Ticket \[TicketNumber] has been escalated and requires your attention. Reason: \[EscalationReason]." 2. Notify Ticket's Resource - Sends to the (potentially new) owner or relevant escalation team resource ### Send summary after automated resolution attempt **Workflow:** Triggered after an L1 Engineer action attempts a fix **Setup:** 1. L1 Engineer - Attempts automated resolution 2. Build Message - Generates a summary of actions taken and the outcome for internal review 3. Notify Ticket's Resource - Sends the summary to the ticket owner or a technical lead ### Weekly summary of owned open tickets **Workflow (Scheduled):** Runs weekly **Setup:** 1. Filter Tickets - Finds all open tickets 2. Data Analysis - Groups tickets by owner and prepares a summary 3. Notify Ticket's Resource (using data table from Data Analysis) - Sends each owner a summary of their open tickets ### Notify resource about data analysis results **Scenario:** After running a Data Analysis action on a set of tickets (e.g., to identify trends in ticket topics for a specific company), notify a designated resource (like an account manager) with the summary or the resulting data frame. **Setup:** 1. Filter Tickets action to gather tickets for a specific company over the last month 2. Data Analysis action to analyze ticket subjects and descriptions 3. Notify Ticket's Resource - Send analysis results to relevant team members # Overview Source: https://docs.neoagent.io/building-automations/actions/overview How workflow actions fit together — Smart Actions (AI analysis & triage), Write-to-PSA (field updates, notes, assignments), and Notify (Email/Slack/Teams/SMS). Composing them safely from simple to complex. Actions are the fundamental building blocks of automations in Neo Agent. They represent specific operations or tasks that are executed as part of a workflow. Each action is designed to perform a distinct function, from analyzing data with AI to updating your PSA or notifying users. By combining different actions, you can create powerful and customized automations to streamline your IT service management processes. ## What actions are Actions are the steps your workflows execute. They analyze data, update your PSA, notify people, and coordinate follow-ups. Each action is purpose-built for MSP workflows and designed to be reliable, auditable, and fast. <Frame> <img alt="High-level diagram of how actions execute within a workflow" /> </Frame> ## Core capabilities <AccordionGroup> <Accordion title="Smart Actions: Understanding and Analysis"> * **Understand and Categorize:** Automatically triage tickets by setting fields like type, sub-type, priority based on content * **Analyze and Summarize:** Generate concise summaries of complex tickets and analyze technician performance * **Detect Patterns:** Identify recurring issues, analyze customer sentiment, and check for specific patterns * **Recommend and Suggest:** Propose the best technician, suggest RMM scripts, or find relevant configurations </Accordion> <Accordion title="Write to PSA Actions: Data Management"> * **Field Updates:** Safely modify ticket fields, priorities, statuses, and custom fields * **Note Management:** Add detailed notes, time entries, and documentation * **Ticket Operations:** Create new tickets, merge duplicates, and manage ticket relationships * **Resource Assignment:** Assign technicians and update ownership information </Accordion> <Accordion title="Notify Users Actions: Communication"> * **Internal Notifications:** Keep teams informed via Microsoft Teams, Slack, or email * **Customer Updates:** Send progress updates and resolution confirmations to end users * **Escalation Alerts:** Notify managers and senior technicians of critical issues * **Feedback Collection:** Request input and gather insights from team members </Accordion> </AccordionGroup> ## Adjust with Neo Most actions take instructions that tell Neo how to do the work. Some show the box straight away; on others another setting reveals it first. Under the box, **Adjust with Neo** opens the Neo Support chat for that one box. Say what the action should do and Neo drafts or changes the instructions, shows you the before and after, and applies it once you confirm. It writes that one setting and leaves the action's other settings untouched. Save the workflow first: Neo reads the saved version, so the button waits while you have unsaved edits. ## Getting started <CardGroup> <Card title="Explore Smart Actions" icon="brain" href="/building-automations/actions/ai/intro"> Learn about AI-powered actions that can analyze tickets, suggest resolutions, and automate complex reasoning tasks. </Card> <Card title="Discover PSA Actions" icon="database" href="/building-automations/actions/write-to-psa/intro"> Understand how to safely update your PSA system with automated field changes, notes, and ticket operations. </Card> <Card title="Set Up Notifications" icon="bell" href="/building-automations/actions/notify/intro"> Configure automated notifications to keep your team and customers informed about important updates. </Card> </CardGroup> Each action is robust, auditable, and designed specifically for the needs of MSPs. Start with simple workflows and gradually add complexity as you become more familiar with the capabilities. # Add Ticket Note Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/add-ticket-note Add notes to tickets in your PSA system to document workflow activity and track progress Messages from previous workflow actions can be added to a ticket as a note. Choose a note type and, for internal notes, optionally include a feedback request link. ## How it works The action takes messages from previous workflow actions, such as analysis results, summaries, or status updates, and prepares them as notes. Choose whether to create an internal, discussion, resolution, or custom note: * **Internal:** Visible only to your technicians — never delivered to the end user * **Discussion:** For collaborative notes * **Resolution:** For documenting solutions * **Custom:** For specific PSA note types you define For how each PSA separates client-facing notes from internal ones, see [End-User Communication](/integrations/psa/end-user-communication#how-neo-reaches-the-end-user). Internal notes include the workflow that created the note, when it was created, and an optional feedback request link. The action then adds the note to the appropriate ticket in your PSA system with the selected visibility settings. ## Setup **Note type**: Choose internal (visible only to your technicians, never sent to the end user), discussion (collaborative), resolution (documenting solutions), or custom types from your PSA. **Message source**: Takes messages from previous actions like Ticket Triage, Smart Actions, or Build Message. **Custom formatting (optional)**: Tell Neo how to format the notes: change language, adjust length, or modify structure. Custom formatting applies to the message only. On an internal note, Neo adds the line that names the workflow (`Agent: [id] name`) after it reformats the message, so that line appears unchanged on every internal note. When feedback requests are on, Neo adds the feedback link after the rewrite too. <Warning> This action needs a message from an earlier action. It reformats what an earlier action wrote; it cannot write the note text itself. Custom formatting changes the wording of an existing message, so it is not a way to describe a note from scratch. If no earlier action produces a message, the workflow still completes successfully and no note is added. Executions shows the line "No note written: no earlier action produced a message". Some actions write to the PSA without producing a message - Update Ticket Fields is one - so a workflow such as Find Tickets → Update Ticket Fields → Add Ticket Note writes no note. Add a **Build Message** action before Add Ticket Note and put the note wording in its instructions. </Warning> **Feedback requests (optional)**: Add links asking team members for feedback on automated processes. ## Common use cases <Accordion title="Document Smart Actions"> When: After AI actions like Ticket Triage or Customer Sentiment Analysis The action records the AI's findings and decisions as internal notes so team members can see what the AI analyzed and why it made certain decisions. </Accordion> <Accordion title="Track Workflow Progress"> When: During complex multi-step workflows The action adds notes at key stages to document progress and create an audit trail of what automated processes have done. </Accordion> <Accordion title="Log Analysis Results"> When: After actions that analyze data or identify patterns The action records analysis findings as internal documentation for future reference. </Accordion> <Accordion title="Create Resolution Records"> When: After successful automated fixes or resolutions The action documents what was done to resolve the issue, creating a record of solutions for similar future problems. </Accordion> ## Best practices Choose the note type that matches its audience. Be careful with note types that might be visible to customers through portals or email notifications. For new automated workflows, enable feedback requests on internal notes to gather input from your team. Use Build Message to format complex information into readable notes. Use custom instructions to tailor notes for different situations: * **Different Languages:** "Write the note in Spanish" for multilingual teams * **Brief Updates:** "Keep it under 100 words and focus on key points" * **Detailed Analysis:** "Provide a detailed breakdown with bullet points" * **Professional Tone:** "Use formal business language for executive summaries" ## Example workflows <Accordion title="AI Analysis Documentation"> 1. **Ticket Triage** - Analyzes new tickets and sets priority/category 2. **Add Ticket Note** - Documents the analysis results as an internal note 3. **Result:** Team can see why the AI made specific categorization decisions </Accordion> <Accordion title="Quality Assurance Tracking"> 1. **Ticket QA** - Reviews completed tickets and assigns quality scores 2. **Add Ticket Note** - Records the QA score and feedback as an internal note 3. **Result:** Quality metrics are preserved on each ticket for review </Accordion> <Accordion title="Workflow Progress Logging"> 1. **Smart Action** - Attempts to resolve an issue automatically 2. **Add Ticket Note** - Documents what was tried and the results 3. **Result:** Clear record of automated resolution attempts for technician follow-up </Accordion> ## PSA-specific features ### ConnectWise * Supports all standard ConnectWise note types * Integrates with ConnectWise's note visibility settings * Works with ConnectWise workflow context ### Autotask * Supports custom Autotask note types * Allows specific publish settings control * Works with Autotask's note categorization system # Add Ticket Tag Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/add-ticket-tag Automatically tag tickets based on smart action results or apply tags to all workflow tickets This action adds tags to tickets in your Autotask system. You can tag tickets conditionally based on smart action results, such as marking reoccurring issues, or apply tags to all tickets in a workflow unconditionally. <Info> This action is available only for **Autotask**. </Info> ## How it works ### Conditional Tagging Mode (Default) When smart actions like "Check Recurring Issue" identify tickets that meet specific criteria, they automatically generate field updates that include tagging instructions. The Add Ticket Tag action picks up these instructions and applies the appropriate tags. When a Ticket Triage tag card decides to leave a ticket's tags as they are, the action skips that ticket. This action only adds tags. When the card decides to clear the tag, the action leaves the ticket's tags in place and says so in the Executions message. ### Unconditional Tagging Mode When you enable "Add tag to ALL tickets," the action applies your specified tag to every ticket in the workflow, regardless of previous action results. Whenever Neo resolves a tag label, in either mode, it matches the label in Autotask case-insensitively and ignores leading and trailing spaces. Autotask limits a ticket to 30 tags. When a ticket is already at that limit, Neo skips the tag and continues; the ticket keeps its existing 30 tags and no error is raised. <Warning> Neo does not reject unknown tag labels. If the label you configure doesn't already exist in Autotask, Neo **creates it**. A typo (e.g. `Recuring Issue`) becomes a brand-new tag rather than an error. To avoid cluttering Autotask with unintended tags, create the exact tag you want in Autotask first, then reference that label. Note that in conditional mode Neo never invents the tag *name*. The label always comes from the fixed **Tag name** you configure on the smart action (e.g. "Check Recurring Issue"); the AI only decides which tickets qualify. </Warning> ## Configuration options Conditional tagging, the default, fits most cases: only the tickets a smart action qualified get the tag. Use **Add tag to ALL tickets** when you want every ticket the workflow touches labeled, for example by source or as auto-processed. ### Add Tag to ALL Tickets Enable this option to tag every ticket in the workflow unconditionally, regardless of previous action results. ### Tag Name **Required when "Add tag to ALL tickets" is enabled.** The exact label of the tag as it appears in Autotask. ### Smart Action Integration The action automatically picks up tagging instructions from smart actions like "Check Recurring Issue" that determine which tickets should be tagged based on their analysis. Test with limited ticket sets to verify tagging works as expected. ## What you'll get * **Executions:** Confirmation messages showing which tickets were tagged successfully * **Tagged Tickets:** Your specified tags applied to the appropriate tickets in Autotask * **Zero Credits:** This action doesn't consume any credits ## Common use cases ### Conditional Tagging Based on Smart Actions <Accordion title="Mark Reoccurring Issues"> **When:** Using "Check Recurring Issue" action to analyze ticket patterns **What it does:** Automatically tags tickets identified as reoccurring issues **Result:** Tickets with recurring patterns get tagged for special handling or escalation </Accordion> <Accordion title="Flag High-Risk Tickets"> **When:** Using sentiment analysis or triage actions that identify problematic tickets **What it does:** Tags tickets that meet specific risk criteria **Result:** Problem tickets are automatically flagged for priority attention </Accordion> ### Unconditional Tagging for Workflow Organization <Accordion title="Mark All Tickets from Specific Sources"> **When:** Processing tickets from a particular integration or channel **What it does:** Applies a source tag to every ticket in the workflow **Result:** Easy filtering and reporting by ticket source </Accordion> <Accordion title="Track Workflow Processing"> **When:** Running any automated workflow on tickets **What it does:** Tags all processed tickets with "Auto-Processed" or similar **Result:** Clear visibility into which tickets have been through automation </Accordion> # Assign Ticket to Technician Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/assign-ticket-to-technician Assign tickets to specific technicians with status updates, calendar integration, and notifications <Note> **In a technician chat ("assign this to me"):** When a Chat Agent runs this tool, the technician is identified as `"me"`: Neo assigns the ticket to whoever is asking, resolved from their signed-in identity (their Microsoft account in a [custom internal bot](/integrations/teams/internal-bot), or their dashboard login on the web). The agent never has to know or guess their PSA resource ID. This requires the technician to be mapped to their Microsoft account via [Microsoft Teams — Technician Mapping](/integrations/teams/workforce-availability). An unmapped person gets a clear message asking their Neo admin to set it up. </Note> <Info> This action is available as both a **Triggered** and **Scheduled** action in a workflow. </Info> ## How it works ### Step 1: Collect Assignment Information The action receives tickets and suggested technicians, usually from a previous Ticket Dispatch action. ### Step 2: Update Ticket Ownership For each ticket, it updates the owner/primary resource field in your PSA to assign it to the suggested technician. <Note> **ConnectWise:** A ticket resource *is* a schedule entry, and setting the owner only adds one when the owner **changes**. Re-assigning the technician who already owns the ticket changes nothing on the **Schedule** tab. If their only entry is marked done, the ticket keeps no open resource entry. To guarantee the assigned technician always has an open one, turn on **"Also add the assigned technician as an open ConnectWise resource?"** in the [Ticket Dispatch](/building-automations/actions/ai/ticket-dispatch-suggest-technician#connectwise-resource-entries) action. </Note> ### Step 3: Status Management (Optional) If enabled, it changes the ticket status to reflect the assignment, such as from "New" to "Assigned". ### Step 4: Calendar Integration (Optional) If scheduling information is provided, it can: * Create new calendar appointments for the technician * Reschedule existing movable appointments to make room (ConnectWise Tentative entries; Autotask by the entry's status and the ticket's priority) ### Step 5: Notification (Optional) If enabled, it sends an email to the newly assigned technician informing them about their new ticket. ## Setup **Assignment source**: Takes recommendations from previous actions, usually Ticket Dispatch, about which technician should handle each ticket. **Calendar management (optional)**: Create new calendar appointments, or reschedule existing movable entries (ConnectWise Tentative entries; Autotask by status and priority) to free up time for scheduled work. Before using calendar integration in production, verify working hours are correctly configured and technician calendars are accurately maintained in your PSA. Neo reads each move back from your PSA and reports the time the PSA returned. If your PSA accepts a move but does not apply it, Neo reports a failed move and names where the entry still sits, so you can check the slot it was meant to free. **Reassignment cleanup (optional)**: Turn on **Remove calendar time booked for technicians no longer on the ticket** when a reassignment should move the booking instead of adding a second one. Without it, a ticket that moves from one technician to another keeps both bookings. Neo only removes time that has not started yet and belongs to a technician this run is not booking. Completed entries, work already under way, and every technician booked by the run stay in place, so a multi-technician dispatch is unaffected. **Status updates (optional)**: Automatically change ticket status after assignment, such as "Assigned", "Scheduled", or "In Progress". The status selected for "Target Status" must exist in your PSA and be appropriate for the ticket's board or queue. **Notifications (optional)**: Send email notifications to newly assigned technicians. For scheduled workflows, avoid assigning tickets outside business hours unless appropriate. ## Example workflows <Accordion title="Smart Dispatch with Full Automation"> 1. **Ticket Dispatch** - Analyzes new tickets and suggests best technicians with timing 2. **Assign Ticket to Technician** - Assigns tickets, creates calendar appointments, updates status to "Scheduled", and emails technicians </Accordion> <Accordion title="Priority-Based Assignment"> 1. **Filter Tickets** - Find high-priority unassigned tickets 2. **Ticket Dispatch** - Suggest technicians based on expertise and availability 3. **Assign Ticket to Technician** - Assign immediately and notify technicians </Accordion> <Accordion title="Scheduled Maintenance Assignment"> 1. **Find Entities** - Identify maintenance tickets scheduled for specific times 2. **Ticket Dispatch** - Match technicians with appropriate skills and availability 3. **Assign Ticket to Technician** - Assign with calendar blocking and status updates </Accordion> ## Integration notes ### ConnectWise * Integrates with ConnectWise scheduling and resource management * Works with ConnectWise's built-in email notification system * Supports ConnectWise board and status configurations ### Autotask * Compatible with Autotask's resource and queue management * Integrates with Autotask's calendar and scheduling features * Works with Autotask's notification preferences * A technician is attached to a service call rather than stored on it, so Autotask cannot move a booking to a different technician. When reassignment cleanup is on, Neo removes the previous service call and books a new one. If that service call is also booked on another ticket, Neo keeps it and reports it as kept, because removing it would take the visit off the other ticket too. # Create New Ticket Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/create-new-ticket Create new tickets in your PSA system with structured fields and context This action creates a new ticket in your Professional Services Automation (PSA) tool from ticket details prepared earlier in the workflow. <Warning> **This action creates nothing on its own.** It needs a [Build New Ticket](/building-automations/actions/ai/build-new-ticket) action before it to supply the ticket details. Build New Ticket is deprecated but still supported, and is currently the only action that can feed this one, so keep using the pair. For new automations we recommend an [Agent](/core/agents) instead, which decides a ticket is needed and creates it in one step. A workflow with one action but not the other does nothing: Build New Ticket alone prepares data that no action consumes, and Create New Ticket alone has nothing to create. Saving a new workflow that has Build New Ticket without a Create New Ticket after it is rejected; workflows that are already unpaired keep working. </Warning> ## How it works ### Step 1: Input Data The action takes a list of `NewTicketToBeCreated` objects. Each object contains ticket details such as title, description, company, contact, status, priority, and board/queue. These details are typically generated and passed by a "Build New Ticket" action. ### Step 2: Ticket Creation For each `NewTicketToBeCreated` object received, the action makes a request to your PSA system to create a new ticket with the specified attributes. ### Step 3: Output Structure The action outputs messages confirming the creation of each new ticket, including the new ticket's ID and title. This information is available to subsequent actions and is logged in Executions. ## Configuration options ### Default Tickets to Create This field expects a list of ticket objects. Typically, this input is provided by the output of a "Build New Ticket" action that runs earlier in the workflow. Each ticket object contains the information for the new ticket. ## What you'll get After the action runs, you'll see: * **Executions:** Messages confirming the creation of each new ticket with details like the new ticket ID and title * **Internal Messages:** Messages intended for internal MSP use that can be used in subsequent actions like "Add Ticket Note" * **Zero Credits:** Creating a new ticket does not consume any credits ## Use cases <Accordion title="Automatically Create a Ticket from a Re-opened Issue"> **Trigger:** A customer replies to a closed ticket **Action 1:** Build New Ticket - Configured to prepare details for a new ticket based on the re-opened issue (e.g., copy details, append "\[Re-opened]" to title) **Action 2:** Create New Ticket - Creates the new ticket in the PSA **Action 3:** Add Ticket Note - Adds a note to the original closed ticket referencing the new ticket ID </Accordion> <Accordion title="Create a Follow-up Task Ticket"> **Trigger:** A ticket is resolved with a status indicating a follow-up is needed **Action 1:** Build New Ticket - Configured with instructions to create a new ticket for the follow-up task (e.g., title "Follow-up: \[Original Ticket Title]", assigned to a specific team) **Action 2:** Create New Ticket - Creates the new follow-up task ticket </Accordion> ## Best practices ### Ensure Required Fields Ensure the "Build New Ticket" action is configured correctly to provide all mandatory fields required by your PSA for ticket creation (e.g., Board/Queue, Status, Priority, Company). ### Link to Original Tickets If you need to update the original ticket that led to the new ticket's creation (e.g., add a note with the new ticket ID), use an "Add Ticket Note" action after "Create New Ticket". ## PSA compatibility ### ConnectWise * Creates tickets with all standard ConnectWise fields * Integrates with ConnectWise boards and workflow rules * Supports ConnectWise's built-in notifications ### Autotask * Creates tickets with Autotask queue and field configurations * Works with Autotask's ticket lifecycle management * Supports Autotask's notification preferences ### Halo * Creates tickets with Halo ticket type, status, priority, and source * Sets the ticket company and contact This action supports ConnectWise, Autotask, and Halo. Other PSA systems are not supported. # Delete Schedule Entries/Service Calls Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/delete-schedule-entries Remove appointments and scheduled work from tickets with full control over what gets deleted Five independent settings determine whether the action deletes past or future entries and pending or completed entries. <Warning> This action permanently deletes calendar scheduled entries and cannot be undone. Test it first. </Warning> <Info> This action supports **ConnectWise** and **Autotask**. In Autotask it removes the ticket's service calls, which also clears the technicians attached to them. **Delete resource entries** is ConnectWise only, because Autotask has no technician assignment that exists without a service call. </Info> ## Quick Start <Steps> <Step title="Choose your trigger"> Use **Ticket Update** when status changes to "Resolved" or "Cancelled" </Step> <Step title="Filter carefully"> Use ticket filters to target only tickets that need schedule cleanup </Step> <Step title="Configure deletion scope"> Choose which types of entries to delete using the five configuration options </Step> <Step title="Test first"> Test on a few non-critical tickets before running on important data </Step> </Steps> ## Configuration options You can choose which schedule entries to delete with five independent settings: | Setting | Default | Description | | - | - | - | | **Delete future pending entries** | Enabled | Remove upcoming appointments that are NOT yet completed | | **Delete future completed entries** | Disabled | Remove upcoming appointments that ARE already marked done | | **Delete past pending entries** | Enabled | Remove past appointments that are NOT yet completed | | **Delete past completed entries** | Disabled | Remove past appointments that ARE already marked done | | **Delete resource entries** | Disabled | Remove ALL technicians/resources not marked as done (ConnectWise only) | In Autotask, the four past/future settings apply to the ticket's service calls. Removing a service call also removes every technician attached to it, so a call shared by two technicians disappears once. A service call that is booked on more than one ticket is kept, not deleted, because removing it would take the visit off the other tickets too; the run reports it as kept. Cancelled service calls are ignored. ### Default Behavior By default, the action deletes all **pending (not completed)** calendar entries: both past and future. It preserves completed work history. ### Resource Entries (ConnectWise Only) In ConnectWise, you can add resources to a ticket without scheduling a specific time slot. These "resource entries" appear in the Schedule section but don't have calendar dates. Enable the **Delete resource entries** option to remove not completed resource assignments from the ticket. ### Full Cleanup Mode Enable all five options to remove every schedule entry from the ticket, including resource assignments. Use this when completely closing out cancelled tickets. ### Ticket Selection The action processes tickets based on your workflow trigger and any filters you've configured. Use precise filters to avoid affecting the wrong tickets. ## What you'll get After the action runs, you'll see: * **Executions:** Confirmation of which scheduled entries were deleted * **Clean Calendar:** Removed appointments no longer appear in technician calendars * **Updated Tickets:** Tickets no longer have the deleted scheduled work attached ## Example workflows <Accordion title="Cleanup on Resolution"> 1. **Trigger:** Ticket status changes to "Resolved" 2. **Filter:** Only tickets with scheduled work 3. **Delete Schedule Entries:** Use default settings to remove pending scheduled work 4. **Result:** Resolved tickets no longer have pending appointments, but completed work history is preserved </Accordion> <Accordion title="Full Cleanup on Cancellation"> 1. **Trigger:** Ticket status changes to "Cancelled" 2. **Filter:** Tickets tagged with "Project" or "Maintenance" 3. **Delete Schedule Entries:** Enable all five deletion options 4. **Result:** Cancelled tickets are completely cleaned up with no schedule entries or resource assignments remaining </Accordion> <Accordion title="Clean Past Incomplete Work"> 1. **Trigger:** Scheduled workflow runs weekly 2. **Filter:** Tickets older than 30 days with status "Closed" 3. **Delete Schedule Entries:** Enable only "Delete past pending entries" 4. **Result:** Old closed tickets no longer have incomplete past appointments cluttering calendars </Accordion> <Accordion title="Remove Unscheduled Resources (ConnectWise)"> 1. **Trigger:** Ticket status changes to "Resolved" 2. **Filter:** ConnectWise tickets only 3. **Delete Schedule Entries:** Enable "Delete resource entries" along with default pending entries 4. **Result:** Resolved tickets have both scheduled appointments and unscheduled resource assignments removed </Accordion> # Overview Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/intro Workflow actions that write back to your PSA — update ticket fields, add notes and labels, assign technicians, update time entries. Index of the Write-to-PSA category. ## Common updates * Update ticket fields * Add notes and labels * Assign technicians * Update time entry fields # Merge Ticket Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/merge-ticket Combine related tickets into one, consolidating duplicate issues and communications <Info> This action is available only as a **triggered** action in a workflow. </Info> ## Quick Start <Steps> <Step title="Set up ticket detection first"> Always use the "Find Ticket to merge with" action before this one. It identifies which tickets should be merged together. </Step> <Step title="Create a triggered workflow"> Set up your workflow to trigger when new tickets are created, so it can catch duplicates right away. </Step> <Step title="Add basic merge settings"> The action will automatically handle the merge, but you can optionally: * Move the merged ticket to a specific queue (Autotask only) * Set custom statuses for the merged tickets </Step> <Step title="Test with safe tickets"> Try it first with test tickets or in a development environment to see how it works with your PSA setup. </Step> </Steps> ## Configuration options ### Merge Source The action automatically processes merge recommendations from the "Find Ticket to merge with" action. No manual configuration needed for basic merging. ### Queue Management (Autotask) **Move merged ticket to specific queue:** Optionally move the merged ticket to a specific queue after merging **Copy ticket notes into the parent ticket:** On by default. Copies the merged ticket's notes into the ticket that receives the merge. ### Status Updates **Update the current (Ticket B) status:** Set a specific status for the original ticket being merged (e.g., "Merged - Duplicate") **Update the destination (Ticket A) status:** Set a specific status for the ticket receiving the merge Status names must exist in your PSA. Keep the destination ticket status active so work can continue. ## What you'll get The action records: * **Executions:** Confirmation of which tickets were merged and the results * **Consolidated Ticket:** All information from both tickets combined into one ## Follow-up actions * **Notify Ticket's Contact** - tell the contact that their tickets are now one ticket. * **Add Ticket Note** - record why the merge happened, for your team. ## Common use cases <Accordion title="Duplicate Ticket Detection"> **When:** Client creates multiple tickets for the same issue **Setup:** 1. Trigger on new ticket creation 2. Find Ticket to merge with - Identify duplicates 3. Merge Ticket - Consolidate the duplicates **Result:** Single ticket with all client communications preserved </Accordion> <Accordion title="Email Reply Consolidation"> **When:** Client replies to old closed tickets **Setup:** 1. Trigger on ticket updates 2. Find Ticket to merge with - Find related active tickets 3. Merge Ticket - Combine old and new tickets **Result:** Current ticket includes all historical context </Accordion> <Accordion title="Multi-Channel Issue Consolidation"> **When:** Same issue reported via phone, email, and portal **Setup:** 1. Trigger on new tickets 2. Find Ticket to merge with - Identify related issues 3. Merge Ticket - Consolidate all channels **Result:** Single ticket with complete communication history </Accordion> ## PSA-specific behavior ### ConnectWise * Uses ConnectWise's native merge functionality * Preserves all ticket history and relationships * Maintains ConnectWise's audit trail * Handles time entries and notes automatically ### Autotask * Manually copies notes, attachments, and details * Provides more control over what gets merged * Allows queue changes during merge process * Maintains Autotask's activity history <Warning> Always test merging behavior in a development environment first. Different PSA systems handle merges differently, and you want to ensure the results match your expectations. </Warning> # Remove Ticket Fields Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/remove-ticket-fields Clear specific field values from tickets in your PSA system Use this action to remove incorrect assignments, clear outdated type/subtype, or reset a field for re-evaluation. <Warning> This action permanently deletes field values and cannot be undone. Use with caution and always test first. Double-check your field selection as well as your ticket filters. The cleared values cannot be recovered. </Warning> ## Quick Start <Steps> <Step title="Choose your trigger"> Works great with **Ticket Update -> Board, Status** </Step> <Step title="Start with filters"> Use ticket filters to target exactly which tickets need field clearing </Step> <Step title="Choose your fields"> Select which specific fields to remove (like assigned technician, type, etc.) </Step> <Step title="Test first"> Always test on a few non-critical tickets before running on important data </Step> </Steps> ## Setup **Fields to clear**: Select which specific fields you want to remove from the tickets: * **Primary technician** - Removes the main assigned technician/owner * **All assignments** - Removes all technician assignments and resources (ConnectWise) * **Ticket type** - Clears the type classification * **Ticket subtype** - Clears the subtype classification * **Priority level** - Removes the priority setting **Ticket selection**: The action processes tickets based on your workflow trigger and any filters you've configured. Make sure your filters are precise to avoid accidentally affecting the wrong tickets. When removing technician assignments, you have two options: * **RESOURCE** - Removes only the primary ticket owner (the main assigned technician) * **CW\_RESOURCES** - Removes all assignment entries from the ticket (clears all assigned technicians/resources) Choose RESOURCE if you only want to remove the ticket owner, or CW\_RESOURCES if you want to completely clear all technicians/assignments from the ticket. ## What you'll get After the action runs, you'll see: * **Executions:** Confirmation of which fields were cleared from which tickets * **Clean Fields:** Selected fields are now empty and ready for new values * **Preserved Data:** All other ticket information remains intact ## Example workflows <Accordion title="Clear Assignment Before Dispatch"> 1. **Trigger:** Ticket moves to "Triage" board 2. **Filter:** Tickets with existing assignments 3. **Remove Ticket Fields:** Clear RESOURCE field 4. **Follow-up:** Run ticket dispatch to reassign properly 5. **Result:** Tickets get fresh assignments based on current criteria </Accordion> <Accordion title="Reset Categorization"> 1. **Trigger:** Ticket priority changes to "Critical" 2. **Filter:** Tickets that need re-categorization 3. **Remove Ticket Fields:** Clear TYPE and SUBTYPE 4. **Follow-up:** Run ticket triage to re-categorize 5. **Result:** Critical tickets get fresh categorization review </Accordion> <Accordion title="Bulk Unassignment"> 1. **Trigger:** Scheduled workflow (daily) 2. **Filter:** Tickets assigned to technicians who are out of office 3. **Remove Ticket Fields:** Clear CW\_RESOURCES (all assignments) 4. **Follow-up:** Run assignment workflow 5. **Result:** Tickets are reassigned to available technicians </Accordion> # Update Ticket Fields Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/update-ticket-fields Update ticket information in your PSA system with smart action results or specific changes Apply changes suggested by other Smart Actions, or define specific updates for tickets in your PSA. ## How it works ### Step 1: Collect Update Instructions The action receives a list of changes to make, either from: * Previous Smart Actions, such as Ticket Triage suggesting a new priority * Specific updates you configure directly ### Step 2: Apply Changes For each ticket and field to update, the action: * Finds the right ticket in your PSA * Updates the specified field with the new value * Follows your rules about whether fields can be cleared ### Step 3: Record Results The action documents what changed and provides confirmation messages for your records. ## Configuration options ### Update Sources **From Previous Actions:** Use suggestions from actions such as Ticket Triage, Ticket Dispatch, or Customer Sentiment Analysis. **Manual Updates:** Set specific field values directly in this action. ### Field Protection **Allow Clearing Fields:** Choose whether the action can remove existing field values. * Turn this on if you want to allow fields to be cleared when appropriate. * Keep it off (default) to prevent accidental removal of important information. ### Specific Updates When you want to make the same change to all tickets, you can set: * **New Status:** Change tickets to a specific status * **New Priority:** Set a particular priority level * **New Board/Queue:** Move tickets to a different board or queue * **New Owner:** Assign tickets to a specific technician Some fields are PSA-specific and only appear for the matching PSA: * **Email CC List (HaloPSA):** the addresses CC'd on ticket notifications * **Halo Team (HaloPSA):** move the ticket to a specific Halo team (dropdown of your teams) * **Halo Workflow (HaloPSA):** put the ticket on a specific Halo workflow/process, e.g. *Working Issue (Remote)* (dropdown of your workflows) <Info> The **Halo Workflow** dropdown is populated from your Halo workflows the first time Neo syncs your Halo metadata after this is enabled (teams sync already, so **Halo Team** is available immediately). Neo matches the name you pick, or one named in custom instructions, to your Halo workflow/team. </Info> ## Common use cases <Accordion title="Apply Triage Results"> **Setup:** Use after a Ticket Triage action **What it does:** Applies the priority, type, and category suggestions from the triage process **Result:** Tickets are automatically categorized correctly </Accordion> <Accordion title="Assign and Update Status"> **Setup:** Use after a Ticket Dispatch action **What it does:** Assigns tickets to the suggested technician and updates status to "Assigned" **Result:** Tickets are routed to the right person and status reflects the assignment </Accordion> <Accordion title="Post-Resolution Updates"> **Setup:** Trigger when tickets are marked as resolved **What it does:** Sets custom fields like "Resolution Code" or updates billing categories **Result:** Proper documentation and billing information is captured </Accordion> <Accordion title="Bulk Status Changes"> **Setup:** Use in scheduled workflows to update multiple tickets **What it does:** Changes status of tickets that meet certain criteria **Result:** Consistent status management across your ticket system </Accordion> ## Best practices ### Be Careful with Field Clearing Only enable "Allow Clearing Fields" when you specifically want to remove information. Keep it disabled to prevent accidental data loss. ### Check Custom Field Names Make sure any custom field names match exactly what you have in your PSA system. Small spelling differences will cause updates to fail. On **ServiceNow**, use the field's column name rather than the label shown on the form. Custom columns are usually prefixed `u_`, so a field labelled "Asset Tag" is typically `u_asset_tag`. Neo uses exactly what you enter and won't add the prefix for you, because you choose the column name when you create the field. If you're unsure, right-click the field label in ServiceNow and choose *Configure Dictionary* to see its real name. ### Test First Before using this in important workflows, test it with a few tickets to make sure it behaves as you expect. ## Example workflows <Accordion title="Smart Triage and Apply"> 1. **Ticket Triage** - Analyzes new tickets and suggests priority, type, and owner 2. **Update Ticket Fields** - Applies all the suggestions from the triage 3. **Result:** New tickets are automatically categorized and assigned </Accordion> <Accordion title="Dispatch and Schedule"> 1. **Ticket Dispatch** - Suggests the best technician for a ticket 2. **Update Ticket Fields** - Assigns the ticket to the suggested technician and sets status to "Scheduled" 3. **Result:** Tickets are routed efficiently with proper status tracking </Accordion> <Accordion title="Quality Control"> 1. **Ticket QA** - Reviews completed tickets and assigns quality scores 2. **Update Ticket Fields** - Saves the quality score and feedback to custom fields 3. **Result:** Quality metrics are automatically tracked on every ticket </Accordion> ## Available updates You can update any ticket field, including status, priority, board/queue, owner, type, category, and custom fields specific to your PSA. ## Safety and reliability If any individual update fails, it won't stop the other updates from completing. All changes are logged with complete details of what was changed and when. # Update Time Entry Fields Source: https://docs.neoagent.io/building-automations/actions/write-to-psa/update-time-entry-fields Update specified fields on time entries with corrections and standardizations Use this action after "Time Entry QA" or "Time Entries Triage" to apply suggested changes or corrections to one or more time entries in your Professional Services Automation (PSA) tool. ## How it works ### Step 1: Input Data The action receives a list of PSA time entry objects, typically from a "Find Entities" action or a trigger. It also takes a list of fields to update, usually from an AI analysis action such as "Time Entry QA". ### Step 2: Field Update Preparation The action prepares the list of changes: * It combines suggested updates with any specified additional updates. * If "Allow Clearing Fields" is set to False (default), it filters out updates that would set a field to an empty value. ### Step 3: PSA Interaction For each time entry: * The action constructs the payload for your PSA. * It makes an API call to apply the changes. * For ConnectWise, it temporarily disables email notifications to prevent spam. The flag is restored after all time entries for that ticket are processed. ### Step 4: Output Generation The action generates a message for each updated time entry that details the fields changed. ## Configuration options ### Default Data The list of PSA time entry objects that this action processes and updates. This input is typically provided by a "Find Entities" action or directly from a workflow trigger. ### Default Fields to Update A list of field update instructions, usually generated by a preceding AI action such as "Time Entry QA". Each instruction specifies the time entry ID, the field to change, and its new value. ### Allow Clearing Fields **Default: False** - Determines whether the action can set fields to an empty or null value. * If **False** (default), updates that clear a field are ignored. * If **True**, the action proceeds with updates that set fields to empty or null. Before you set this to True, make sure each preceding action that supplies field updates either gives a value or clears the field on purpose. ### Update Additional Fields **Default: False** - Set this to True to configure specific, static field updates. ### Additional Fields to Update This section is enabled when "Update Additional Fields" is True. It lets you define updates to apply to all time entries processed by this action. Use additional fields for a single static change, such as always marking filtered time entries as non-billable. For changes that depend on the content of each time entry, use the output of an AI action such as "Time Entry QA" or "Time Entries Triage". #### Is Non-Billable (Autotask only) Set whether the time entry is non-billable. Choose "True", "False", or "Do not update". ConnectWise typically handles non-billable status through Work Type or other specific fields. ## What you'll get * **Executions:** Messages confirming the update of each time entry and detailing the changes made * **Internal Messages:** Messages for internal MSP use that can be used in subsequent actions such as "Add Ticket Note" * **Zero Credits:** Updating time entry fields does not consume any credits ## Use cases <Accordion title="Correct Time Entry after Automated QA"> **Trigger:** Time Entry Created **Action 1:** Time Entry QA - Analyzes the new time entry based on defined criteria **Action 2:** Update Time Entry Fields - Takes the suggestions from "Time Entry QA" and applies corrections like changing work type or billable flag </Accordion> <Accordion title="Standardize Non-Billable Time Entries"> **Trigger:** Time Entry Created **Filter:** Time entry's associated ticket has title containing "Internal Meeting" OR time entry notes contain "Internal Training" **Action:** Update Time Entry Fields - Set "Is Non-Billable" to "True" for Autotask, or update Work Type for ConnectWise </Accordion> ## Best practices ### ConnectWise Notifications For ConnectWise users, this action temporarily modifies the email notification flag on the parent ticket to prevent excessive notifications. This flag is restored after all time entries for that ticket are processed. ## Example workflows <Accordion title="Billing Compliance Check"> 1. **Trigger:** Time Entry Created 2. **Time Entries Triage** - Check billing compliance and work type accuracy 3. **Update Time Entry Fields** - Apply triage suggestions for compliance </Accordion> ## Available field updates You can update various time entry fields including: * **Work type** - Change the service category or work classification * **Billable status** - Set whether the time is billable or non-billable * **Notes/description** - Update or append to the time entry details * **Hours logged** - Modify the time amount (use with caution) * **Custom fields** - Update any custom fields specific to your PSA setup ## Safety features ### Data Protection * Default behavior prevents accidental field clearing * Individual time entry failures don't stop the entire batch * Detailed logging of all changes made ### Notification Management * ConnectWise: Temporarily disables automatic email notifications during updates * Autotask: Respects existing notification settings ### Validation * Ensures time entries exist before attempting updates * Validates field names match PSA configuration * Confirms new values are appropriate for field types # Dependencies Source: https://docs.neoagent.io/building-automations/managing-workflows/dependencies Control workflow ordering and safe sequential execution Workflow dependencies in Neo Agent allow you to control the execution order of your workflows. This ensures that workflows run in the correct sequence, especially when one workflow relies on the output or completion of another. ## Why dependencies matter <CardGroup> <Card title="Prevent conflicts" icon="shield"> Avoid situations where workflows might perform conflicting or redundant actions if run simultaneously or out of order. </Card> <Card title="Ensure data availability" icon="database"> Guarantee that data generated or processed by one workflow is available and finalized before a subsequent workflow that needs this data begins. </Card> <Card title="Enable complex automations" icon="link"> Build sophisticated, multi-step automation processes by chaining workflows together based on specific completion criteria. </Card> </CardGroup> ## How dependencies work When a Neo Agent workflow is triggered, it can be configured to wait for other specified workflows to complete before it starts its own execution. This is particularly useful for "Triggered" workflows. * If a workflow has dependencies, it will pause and wait until all its prerequisite workflows have finished successfully. * If a prerequisite workflow fails, the dependent workflow might not run, or its behavior could be affected, depending on your overall setup and error handling. ## Configuring execution order You can manage the execution order of your workflows directly from the [Workflows page](https://dashboard.neoagent.io/workflows) in Neo Agent. Ordering takes two settings, and both must be right: * **The position itself** — set by dragging a workflow in the list, or with the **Reorder** button. Lower runs first. * **The Obey Order toggle** — a switch in the **Obey Order** column of the Workflows list. This decides whether the position is used at all. <Warning> **Reordering alone does nothing until Obey Order is on.** New workflows and agents are created with Obey Order **off**, which means they run in parallel with everything else that matched the same event, no matter where they sit in the list. If a workflow you have carefully positioned still runs too early, check this toggle first. </Warning> ### Obey Order and ticket filters Obey Order does more than delay the start. When it is on and an earlier workflow has already matched the same event, Neo Agent **defers the workflow's ticket filter check** — it starts the workflow, waits for the earlier workflows to finish, and only then evaluates the filter conditions, against the ticket as it stands at that moment. This matters whenever a workflow filters on a field that an earlier workflow fills in. A common example: a triage workflow classifies a new ticket and sets its issue type and sub-issue type; a specialist agent — say a password-reset agent — then filters on sub-issue type. When the ticket is first created that field is still empty, because triage has not run yet. With Obey Order **off**, the specialist agent checks the filter immediately, finds no match, and never runs — a technician has to trigger it by hand. With Obey Order **on**, it waits for triage, re-checks the filter, and matches. <Note> The trigger event itself is always checked up front, and is never deferred. Obey Order only defers the **ticket filter conditions**. A workflow that triggers on "Ticket Created" still needs a ticket-created event; Obey Order just gives earlier workflows a chance to shape the ticket before the filter is applied. </Note> ### Sequential execution To make one workflow run only after another one finishes, you can establish a dependency. This is achieved by reordering workflows. The workflow that needs to run first should be placed higher in the execution order. For example, you might have a "Triage" workflow that first categorizes a ticket. An "L1 Engineer" workflow could then depend on the "Triage" workflow to ensure the ticket has the correct type, subtype, contact, and company information before it attempts to perform its tasks. <Frame> <img alt="Workflow reorder button" /> </Frame> In the image below, the "L1 Engineer" workflow is set to execute after the "Triage" workflow. This ensures that "L1 Engineer" only starts after "Triage" has completed its processing. Other workflows (like "Summarize Phone calls", "Notify about a ticket", etc.) that do not have explicit order dependencies with "Triage" or "L1 Engineer" can run in parallel or based on their own triggers and conditions. <Frame> <img alt="Sequential workflow execution example" /> </Frame> ### Workflow Finished trigger Another powerful way to create workflow dependencies is by using the "Workflow Finished" trigger. This trigger allows you to start a workflow automatically when another specific workflow completes its execution. <Frame> <img alt="Workflow Finished trigger configuration" /> </Frame> When configuring a "Workflow Finished" trigger: * **Select the prerequisite workflow**: Choose which workflow must complete before this workflow starts This approach is particularly useful when: * You want to create a clear chain of workflows that process the same ticket sequentially * Each workflow in the chain performs a distinct function (e.g., Triage → Analysis → Dispatch) * You need to ensure that one workflow's output is available before the next workflow begins <Tip> The "Workflow Finished" trigger is ideal for creating linear workflow chains where each step builds upon the previous one's results. </Tip> <Note> **The next workflow does not start the instant the first one finishes.** Neo Agent waits a moment for your PSA to reflect the first workflow's changes, then queues the handoff. It usually starts within seconds, but on a busy account it can take a few minutes. If a chained workflow has not started yet, give it a short while and check again before treating it as a fault. </Note> <Note> A workflow that other workflows depend on can't be deleted. If you try to delete a workflow while another workflow is set to trigger when it finishes, Neo Agent blocks the deletion and lists the dependent workflows. Remove the "Workflow Finished" trigger from those dependents (or delete them first), then delete the workflow. </Note> ### Parallel execution Workflows that do not have defined dependencies on each other can run in parallel. This means they can be triggered and execute concurrently, based on their individual trigger conditions (e.g., "Ticket Created", "Status - Closed"). Parallel execution is the default: a workflow with **Obey Order** off ignores its position in the list and starts as soon as its own trigger and filter match. Leave it off when the workflow is genuinely independent — it starts sooner and is not held up by an unrelated workflow that happens to sit above it. ## Best practices <AccordionGroup> <Accordion title="Start simple"> Begin with basic dependencies and gradually introduce more complex ordering as your automation needs evolve. </Accordion> <Accordion title="Avoid circular dependencies"> Ensure you don't create a loop where Workflow A depends on Workflow B, and Workflow B (directly or indirectly) depends back on Workflow A. This will prevent your workflows from running. </Accordion> <Accordion title="Review regularly"> Periodically review your workflow dependencies, especially as you add or modify workflows, to ensure the logic remains sound and efficient. </Accordion> <Accordion title="Use Executions"> Check Executions to monitor workflow executions and confirm that dependencies are behaving as expected. </Accordion> <Accordion title="A workflow only runs when triggered manually"> This is almost always Obey Order. If a workflow works when you run it by hand but never fires on its own, look at what its ticket filter needs. If any of those fields are set by an earlier workflow — issue type, sub-issue type, contact, company, priority — the filter is being checked before that workflow has run. Turn **Obey Order** on so it waits and re-checks. To confirm it, switch on PSA events in Executions, open the event and look at **Workflow Matching Results**. Its **Field Comparisons** table lists each condition with the value it wanted and the value the ticket actually had. A row showing `(empty)` under **Actual** for a field an earlier workflow is supposed to set is the signature. </Accordion> </AccordionGroup> <Tip> Clearly defining dependencies is key to building robust and reliable automation sequences in Neo Agent. </Tip> # Find and organize workflows Source: https://docs.neoagent.io/building-automations/managing-workflows/find-and-organize Search the workflow list by name or ID, and sort workflows and agents into groups The **Workflows** page lists every workflow and agent in two tables: **Triggered** and **Scheduled**. Once the list is long, search finds one by name, and groups keep related ones together. ## Open a workflow If you can edit a workflow or agent, click anywhere on its row to open its editor, the same as the pencil icon. Viewers, and agents managed by Neo, open no editor. The switches, buttons and drag handle on the row keep their own actions. When you come back to the list, it scrolls to the row you opened and that row flashes briefly, as long as the row is still on screen. A collapsed group hides it, and so does a search that no longer matches the name. An editor opened this way shows **Back to Agents** at the top left, which returns you to the list with your search still applied. It is not shown when you open an editor from a link or a saved address, which have no list behind them. To keep the list where it is, open the editor in a second tab: hold Cmd (Ctrl on Windows) as you click the row. The name is also a link, so your browser's **Open Link in New Tab** works on it, and so does a middle-click. A second tab has no list behind it, so it shows no **Back to Agents**. ## Search the list Type in the search box above the tables. The list filters as you type, across both tables and every group. * **Match by name.** The search ignores case, and each word you type must appear in the name, in any order. `triage alerts` finds *Ticket Triage - Alerts*. * **Match by ID.** Type a workflow's ID or part of it, with or without a leading `#`. `196` finds workflow 19697. * **See where it lives.** A matching workflow shows inside its group, and every group with a match opens, even one you collapsed. Groups with no match are hidden. * **See what triggers it.** A workflow that runs when another one finishes shows under that workflow, so the chain stays readable. * **Keep your place.** The search is part of the page's address, so refreshing the page or pressing browser Back keeps it. Copy the address to share the filtered list. The **Enabled Only** and **Disabled Only** filters still apply while you search. If nothing matches, the table offers to clear the search or to show all workflows. Press **Esc** or click the **×** in the search box to clear it. Your collapsed groups come back as you left them. <Note> Drag-and-drop reordering is off while a search is active, because the order would be saved from only the rows on screen. Clear the search to reorder. </Note> ## Group workflows Groups are part of the list order, and the list order is the execution order for workflows that obey order. Moving a workflow into another group, or moving a group, changes that order. See [Configuring execution order](/building-automations/managing-workflows/dependencies#configuring-execution-order). * **Create a group.** Click **New Group** above either table, name it, and tick the workflows it starts with. A group is stored on its workflows, so it needs at least one; you can drag more in afterwards. * **Move a workflow.** Drag it onto another group's header, or onto **Ungrouped** to take it out of every group. * **Rename or delete a group.** Double-click its name, or use the **⋮** menu on its header. Deleting a group moves its workflows to **Ungrouped**; it deletes no workflow. A group also disappears once you move its last workflow out. * **Collapse a group.** Click the arrow beside its name. This browser remembers which groups you collapsed. Viewers can search the list, but cannot drag workflows to reorder or regroup them. # Parallel Dispatch (Optimistic Locking) Source: https://docs.neoagent.io/building-automations/managing-workflows/parallel-dispatch Run Ticket Dispatch in parallel without double-bookings — drop the sequential safety knob without losing the safety net When a burst of new tickets arrives, Neo Agent normally dispatches them in parallel — much faster than processing one at a time. But running dispatch workflows in parallel has historically had a subtle risk: two tickets that arrive seconds apart can both ask the AI "who's free right now?", get the same answer, and end up double-booked on the same technician's calendar. **Parallel Dispatch** is the safety net that solves that race. It lets your dispatch workflows run fully in parallel for high throughput, while making sure each technician's calendar slot can only be claimed by one ticket. <Info> Parallel Dispatch is rolling out to clients in waves. Newly created dispatch workflows pick it up automatically as the rollout reaches your account; existing workflows continue to work unchanged. No action is required from you to enable it. </Info> ## What it does When a Ticket Dispatch action runs with scheduling enabled and an Assign Ticket action after it books the slot, Parallel Dispatch quietly: * **Reserves the chosen calendar slot** the moment the AI picks it, so two simultaneous dispatches can't both grab the same time on the same technician. * **Shows the AI the slots other dispatches have already reserved** before it picks, each with its technician and ticket, so it can choose a free time first. This part is rolling out account by account. A reservation covers only the technician it names, and the list changes nothing about who may take the ticket. * **Asks the AI to pick again** if the slot was reserved by a peer dispatch a moment ago, telling it which slot was lost. On an account that sees the reserved slots, it also lists every slot other dispatches hold at that moment, so one retry can clear them all. When several dispatches lose at the same moment, the first to lose retries as usual, and each later one is told its place among them and aims for a different opening, which makes a repeat collision much less likely. The conversation continues, so the AI keeps all the context it already had and your routing rules stay in force. * **Lets a ticket share a slot with a booking Neo could already see**, when the overlap is allowed. When the other ticket's booking is already on the technician's calendar as Neo reads it, Neo checks the overlap the same way as any other appointment: against your custom instructions and your urgent-priority rules. If the overlap is allowed (for example, your instructions say "an alert for the same host goes to the open ticket's owner, in the same slot"), the ticket gets the shared slot, and the reservation does not send it elsewhere. A Tentative booking can still send the ticket to another slot. It works when the other booking starts and ends on a 5-minute mark (09:00 to 09:30, for example); a booking such as 09:02 to 09:28 still sends the ticket to another slot. It does not apply on Autotask, because the calendar Neo reads does not link a service call to its ticket, so the reservation still sends the ticket to another slot. * **Hands the slot straight back** when the ticket ends up not being booked — somebody claimed it while Neo was deciding, for example. That technician stays available for the next ticket instead of looking busy until the reservation lapses. * **Holds the slot while a ticket waits for approval**, because that exact technician and hour are the ones being approved. Another ticket dispatched during the wait is offered a different technician or time, so two approvals can't be granted for the same slot. The hold lasts ten minutes. If nobody answers the card in that time the slot is released, and if the approval arrives later and the slot has since gone, Neo says so on the ticket and retries before asking again. * **Tells the AI which other dispatches are deciding at the same moment**, and where this one sits among them, so a workflow whose rules need to separate simultaneous tickets has something to separate them by. * **Names the technician a concurrent dispatch has just assigned**, so a later run does not repeat a choice whose record has not been written yet (see [Seeing what a concurrent dispatch just did](#seeing-what-a-concurrent-dispatch-just-did)). * **Re-reads the technician's live calendar before it settles on the slot** (when the workflow has an Assign Ticket action to book the slot), to find a booking made outside Neo while it was deciding that ticket: a technician who booked their own time, or one of your own automations that created a service call. The reservation covers other Neo runs. When the slot is now taken, Neo picks another slot or technician, and Round Robin moves to the next technician. An entry Neo already saw in the calendar when it chose the slot, such as one your instructions allow Neo to double-book, does not count. The re-read looks at the scheduled work your PSA books against the technician, which on Autotask means service calls. On ConnectWise, an entry that spans several days counts only for the hours it books on each day, the same as in the calendar Neo reads — unless ConnectWise returns the series with no per-day detail rows, or a full page that may be truncated, when Neo treats the whole span as overlapping rather than clearing it. You won't see a new setting in the workflow editor. It runs underneath the existing Ticket Dispatch action automatically whenever calendar booking is enabled and an Assign Ticket action books the slot. A workflow with no Assign Ticket action only suggests a slot and books nothing, so Neo reserves no slot while it decides. Two tickets dispatched together can then suggest the same slot; each one still gets its suggestion. ## Why it matters <CardGroup> <Card title="No more silent double-bookings" icon="shield-check"> Concurrent dispatches that pick overlapping slots used to fail quietly — both tickets ended up on the same technician's calendar at the same time. Parallel Dispatch makes that impossible. </Card> <Card title="Burst-day throughput" icon="bolt"> A Monday-morning burst of 30 new tickets dispatches in the time it takes to process the slowest single one, not 30 in a row. </Card> <Card title="Conflicts recover in place" icon="circle-pause"> When the AI's first pick loses the slot, Neo Agent tells it which slot went and asks for another in the same conversation. No context is lost and the ticket is not sent back to the queue. </Card> <Card title="Zero workflow changes" icon="hand"> Existing dispatch workflows benefit automatically once your account is on the new behavior. Your settings, custom instructions, and pool sources continue to work as-is. </Card> </CardGroup> ## Per-technician burst limit Alongside the calendar-slot safety net, Neo Agent limits how much work a single technician can be handed in one burst: **up to three assignments per rolling five minutes**, counted per technician across all dispatches running concurrently for your account. This is a fairness guard, not a capacity rule. Without it, a burst of thirty tickets that all look like the same person's speciality can land entirely on that person, because each dispatch reads the workload snapshot before any of the others have finished writing to it. The window is five minutes because a dispatch takes minutes to decide. A shorter window than one decision cannot see two assignments at once, so the limit never applies. Unlike calendar-slot reservation, this limit applies to **every** dispatch workflow — including those that only assign a technician without booking a calendar entry. ### What happens when the limit is reached Neo asks the AI to pick again, and the retry keeps your routing rules intact: 1. **A different technician your custom instructions still allow.** Within the allowed set Neo will take a slightly worse fit rather than pile onto one person. 2. **If every remaining candidate is outside your rules, Neo assigns the rate-limited technician it proposed last.** Neo will not route around a restriction you declared — a named team ("Security Incidents → only the Security Squad"), a named owner ("VIP accounts → only their account manager"), or a queue/tier rule ("Escalation queue → do not downgrade to lower teams") — just to get past the limit. That technician already satisfied those rules, so Neo lets them through instead of leaving the ticket for a human. 3. **If the AI keeps proposing rate-limited technicians**, after several attempts Neo allows the last one it proposed through rather than failing the dispatch. The limit is a guard, not a hard stop. With **Human in the loop** set to **Ask only when unsure**, case 3 asks an approver first, and the ticket waits for the answer. Case 2 asks nothing: your rules allow only that technician, so Neo assigns them. <Info> The limit is not configurable today, and there's no toggle in the workflow editor. If your dispatch is tier- or team-restricted and morning bursts regularly concentrate on a small group of technicians, reach out to support — we can look at the pattern with you. </Info> ## Seeing what a concurrent dispatch just did Assignment counts come from Neo's own dispatch record, which a run writes when it finishes. A dispatch spends a few minutes deciding, so a run that started shortly before could read counts that were already out of date. Two changes widen what each run sees: * **The counts are read immediately before the AI decides**, not at the start of the run. Any dispatch that finished while Neo was gathering context is included. * **A technician's in-flight assignments are listed by name.** A dispatch registers its choice the moment the AI makes it, ahead of the record being written. A run reading the counts after that point sees the entry under that technician, marked as work already given but not yet counted, and treats it as part of their load. Both apply to every dispatch workflow, with or without calendar booking, and to Round Robin as well as AI selection. ### What you see In Executions, a dispatch that met this situation names it in its reasoning — for example: *"Ryan Irwin holds 1 assignment from a concurrent dispatch (#895292) on top of 2 today; Charlie Mathena has 1 and is on shift, so this ticket goes to Charlie."* <Note> Tickets that arrive at the same moment are not covered by what a run can read. Dispatches that start within seconds of each other all reach the AI before any of them has decided, so none of them can see the others' choices. The [per-technician burst limit](#per-technician-burst-limit) is the guard for that case: it applies after each decision, so it catches the group that reading alone cannot. </Note> <Tip> Where a group of similar tickets concentrates on one person, the eligible pool is often the real cause rather than the counts: shift hours, time off, and named routing rules can leave only one or two technicians available at that moment. The run's reasoning lists every candidate it excluded and why. </Tip> ## When sequential dispatch is still the right choice Parallel Dispatch replaces most uses of the **Process Entities Sequentially** workflow setting, but not all of them. Keep it on when: <AccordionGroup> <Accordion title="Your dispatch workflow doesn't book calendar slots"> Sequential mode is still the right answer for dispatch workflows that only assign a technician without adding a scheduled entry. There's no slot to reserve in that case, so the parallelization safety net doesn't apply. </Accordion> <Accordion title="You want predictable, one-at-a-time processing for non-dispatch actions"> Sequential mode also covers actions like Find Ticket to Merge With and Trigger Another Workflow, where order matters across tickets. Parallel Dispatch only addresses the calendar-collision case. </Accordion> <Accordion title="Your volume is low and you don't see throughput pressure"> For workflows that fire a handful of times per day, sequential mode's simpler semantics are still a reasonable choice. There's no harm in leaving it on — Parallel Dispatch will treat sequential workflows as a no-op (the one-at-a-time guarantee already prevents the race). </Accordion> </AccordionGroup> ## Migrating an existing sequential dispatch workflow If you have a dispatch workflow currently running with **Process Entities Sequentially** enabled, you can safely turn it off once Parallel Dispatch is active on your account: <Steps> <Step title="Confirm the workflow books calendar slots"> Open the workflow's Ticket Dispatch action settings. Under **Scheduling options**, verify that calendar booking is enabled and that an Assign Ticket action follows the Ticket Dispatch action. If either is missing, leave sequential mode on — Parallel Dispatch only protects scheduled dispatches. </Step> <Step title="Turn off Process Entities Sequentially"> In the workflow's general settings, uncheck **Process Entities Sequentially**. </Step> <Step title="Save and let it run on real traffic"> Save the workflow. The next burst of tickets will dispatch in parallel. Calendar collisions remain impossible — the safety net catches what serialization used to prevent. </Step> <Step title="Check Executions after the first busy day"> Open the workflow's executions after a high-volume window. You should see dispatches finishing concurrently rather than queuing one-by-one. If a dispatch's reasoning mentions falling back to a different technician, that's Parallel Dispatch's conflict recovery working as designed. </Step> </Steps> <Tip> You don't have to migrate every workflow at once. Start with your highest-volume dispatch workflows — those are where Parallel Dispatch produces the biggest throughput win. </Tip> ## Expected throughput improvement The improvement depends on how many tickets the workflow processes in a typical burst: | Workflow shape | Before (sequential) | After (parallel) | | - | - | - | | 5-ticket burst | \~5–10 minutes serially | All 5 finish within the slowest single dispatch | | 30-ticket burst | Up to \~2.5 hours serially | All 30 finish within the slowest single dispatch | | Steady-state low volume | No meaningful change | No meaningful change | For workflows that handle scheduled dispatches with frequent multi-ticket bursts (after-hours backlogs, Monday-morning queues, post-outage cleanup), the practical effect is "the queue is gone." ## Frequently asked questions <AccordionGroup> <Accordion title="Do I need to enable anything in the workflow editor?"> No. Parallel Dispatch runs underneath the existing Ticket Dispatch action automatically whenever the action has calendar booking enabled and an Assign Ticket action books the slot. There's no checkbox to toggle. </Accordion> <Accordion title="What happens if every alternative technician is also busy?"> Neo asks the AI for another pick a limited number of times. If each one also loses its slot, the ticket is left unassigned for manual triage rather than double-booked, and Executions names the slots that were lost. This is rare in practice; it needs several dispatches competing for the same window and the same technicians at once. </Accordion> <Accordion title="What if the ticket must be done at an exact time?"> When your custom instructions say to book the time a ticket states, and that slot goes to another ticket, the AI keeps the time and looks for another technician your rules allow who is free at that exact time. It does not move the ticket to an earlier or later slot. If nobody permitted is free then, the ticket is left unassigned, and with Human in the Loop set to ask when unsure, your approvers get a question instead. A window, such as "between 5 and 7 pm", is not an exact time: the AI can pick another time inside the window. </Accordion> <Accordion title="What if the replacement slot clashes with something else?"> Neo checks the replacement the same way it checks a first pick — against time off, the technician's existing appointments, the SLA deadline and your urgent-priority rules. If it finds a problem, Neo hands the slot back so other tickets can use it, tells the AI every problem it found, and asks for another pick. The ticket is only left unassigned once those attempts run out. </Accordion> <Accordion title="Will it change the AI's technician selection?"> It can, in one direction: the AI now sees what concurrent dispatches have just assigned, so it can move a ticket off a technician who was picked seconds ago by a peer. Your custom instructions, pool source and routing rules are applied exactly as before — a substitution is only ever made from the candidates your rules already allow. </Accordion> <Accordion title="Does it affect Round Robin dispatch?"> Yes — Round Robin dispatch also benefits when scheduling is enabled and an Assign Ticket action books the slot. The same slot-claiming safety net applies whether the chosen technician came from the AI or from Round Robin rotation. </Accordion> <Accordion title="Can I see how often conflicts happen?"> Conflict and fallback events are tracked in observability dashboards on the Neo Agent side. If you want a per-workflow report, reach out to support — we can pull the rate for any workflow you're piloting the migration on. </Accordion> </AccordionGroup> # Templates Source: https://docs.neoagent.io/building-automations/managing-workflows/templates Curated workflow and agent templates: browse the library, apply one in the editor, or have Neo Support set it up with you Templates are blueprints curated by the Neo team — a trigger, actions or a toolbox, and instructions that already work for a common MSP job. Applying one creates a new, independent workflow or agent in your account; from that moment it is yours to adapt, and changes to the template never touch it. There are two ways to go from a template to a working automation: * **Apply it yourself** — the template opens in the editor, and you tailor it there before you save. * **Have Neo Support set it up with you** — you tell your Neo Support Agent which template you want, it asks the few questions the template can't answer on its own (which board, which statuses, who approves), and creates the workflow or agent disabled for your review. ## Browsing the library On [**Agents & Workflows**](https://dashboard.neoagent.io/), open **New** and pick **From a template**. The library lists workflows and agents together, marked by their icons. The picker has three parts: * **Categories** on the left, plus **Popular** for the templates the Neo team marks as a good place to start, and a search box that matches names, descriptions, categories and the integrations a template uses. * **The list** in the middle, grouped by category. * **The detail panel** on the right for the selected template: when it runs (its trigger or schedule), what it does, and **Integrations needed**. Each integration row shows a category — any one vendor in the category satisfies it, and the row collapses to your connected vendor with a ✓ once you have one. **Quick apply** is disabled while a needed integration category has nothing connected; connect one on the [Integrations page](https://dashboard.neoagent.io/integrations) and come back. ## Applying a template yourself **Quick apply** opens the editor with the template's configuration filled in. Two things do not travel between tenants: the people the author had selected, which arrive empty, and permissions for a PSA or RMM other than yours, which are dropped. Everything else — the trigger, the schedule, the filters, and the permissions for every other integration — arrives exactly as the template was authored, so those values still need your review. Nothing runs until you save, and the editor gives you two save buttons: **Save & Enable** lets the automation start straight away, and **Save as Disabled** parks it for you to finish. Before enabling, walk the settings the template cannot know about you: * **Where it fires** — the board or queue, the statuses, and any companies to include or exclude. Statuses and boards differ per tenant, so these usually need your values. * **Who is involved** — notification recipients and approvers arrive empty on purpose (a template is shared across every Neo customer, so it never carries another tenant's people). Fill them in where the template uses them. * **The name**, so your list stays readable. Use **Save as Disabled** until you have been through that list and tested it on non-critical data. Then enable it with the Enable option on your workflow list; **Save & Enable** is offered only before the first save. From there it behaves like any workflow or agent you built by hand — [Activity](/product/executions) shows its runs. ## Set up with Neo The same setup can happen as a conversation, and anyone who can create an agent can run it: the Owner, Admin and User roles. Ask your [Neo Support Agent](/chat-agents/neo-support-agent) — for example, *"Set up the Ticket Bundler template for me"* — and it runs the interview an onboarding call would: 1. It fetches the template already adapted to your workspace and reads the template's spec — the recipe the Neo team writes per template: what the automation does, what it writes at the end, which settings need your values, and the questions that matter for that specific template. Every template in Neo's library carries one. 2. It asks a handful of questions, offering your real values as clickable options — your actual boards, statuses and team members, never a blank "which board?". Where several answers can apply at once, you pick as many options as apply: each lands in the message box as a chip, you type anything of your own next to them, and send as usual. Questions that do not depend on each other arrive together on one card you answer in a single pass. Expect three to five questions: where the automation fires, which fields it should set and to what values, whether writes should wait for a technician's approval, and who to notify. Your own questions are welcome at any point — ask what a setting means and the interview picks back up where it was. 3. If the template can use an integration you have connected but doesn't strictly need, it asks one yes/no question about keeping that capability. Optional integrations you don't have are simply left out — they never block the setup. 4. It creates the workflow or agent **disabled** and points you to it. You review the configuration and enable it when you are happy — Neo Support only enables it if you explicitly ask it to. If a required integration isn't connected, Neo Support stops before creating anything and names what is missing and the vendors that would satisfy it. An admin can ask it for the connect link in the chat; everyone else connects the integration on the [Integrations page](https://dashboard.neoagent.io/integrations), or asks an admin when that page is not open to them. Two ways in. In the template picker, open a template and choose **Set up with Neo** — your Neo Support Agent opens with that template attached and room for a note of your own; send the message and the interview begins. Or ask the agent directly, for example *"Set up the Ticket Bundler template for me"*. The button appears for anyone who can create an agent, in a workspace with a Neo Support Agent they can reach. Neo Insights offers the same thing from a different angle. Rows there can carry their own **Set up with Neo** button, which attaches the evidence behind those tickets: the volume, the patterns it detected and example tickets. The interview then starts from your own data rather than from a blank template, and where no template fits, the agent builds a Workflow or Agent from that evidence instead. ## Good to know * **Every application is independent.** Editing one never affects another made from the same template, and template updates by the Neo team never rewrite what you already applied. Give a second application its own name: Neo Support reads a repeat request under the same name within half an hour as a retry of the first, and hands back the automation it just created. * **Agents created from a template remember their origin**, so the Neo team can see which templates earn their place in the library and improve the ones that need more setup than they should. * **Some templates come in pairs** — one workflow categorises, another acts on the category. Apply both and they work together with minimal setup. # Version history Source: https://docs.neoagent.io/building-automations/managing-workflows/version-history Track workflow changes and roll back if needed Neo Agent automatically tracks changes to your workflows, providing a comprehensive version history. This feature is crucial for: * Auditing changes for compliance and troubleshooting * Safely rolling back to a previous, stable version if an update causes unexpected behavior * Facilitating team collaboration by providing transparency on who changed what and when ## Accessing version history You can access the version history for any workflow directly from the main Workflows page: <Steps> <Step title="Navigate to Workflows"> Navigate to the **Workflows** section in Neo Agent. </Step> <Step title="Locate your workflow"> Locate the workflow you want to inspect. </Step> <Step title="Open the menu"> Click on the three-dots menu (kebab menu) on the right side of the workflow row. </Step> <Step title="Select Version History"> Select **"Version History"** from the dropdown menu. </Step> </Steps> <Frame> <img alt="Accessing workflow version history" /> </Frame> This will open a dialog displaying all saved versions of the workflow. ### Chat agents Chat (conversational) agents are versioned in exactly the same way — every save snapshots their custom instructions, tools, and integrations — but they don't appear on the Workflows page, so their version history lives in a different place: <Steps> <Step title="Go to Chat → Agents"> Open the **Chat** section and switch to the **Agents** tab. </Step> <Step title="Open the agent's menu"> Click the three-dots menu on the right side of the agent's row. </Step> <Step title="Select Version history"> Choose **"Version history"** to open the same dialog described below, including the change summary for every save and the ability to restore an agent's earlier configuration. </Step> </Steps> ## Understanding the version history dialog The Version History dialog has two panes. The **left pane** lists every version, newest first. Each entry shows the version number (v8, v7, …), when it was saved, who saved it, and — most usefully — **a set of labels summarizing what changed in that save**: for example *Instructions*, *Tools +2 −1*, *Trigger & filters*, *Enabled*, or *Renamed*. This makes it easy to scan months of history and spot exactly which save touched the thing you care about. A version that changed nothing visible shows *No config change*. A change that Neo made for you in a Neo Support chat shows the name of the person in that chat; the public API's `GET /agents/<id>/versions` also says how each version was saved (`saved_by`), so a change saved through the API for a person reads differently from one saved in the dashboard. Click a version (or use the arrow keys) and the **right pane** shows the full detail of that save, compared to the version before it: * Every changed field with its old and new value, for example `Priority filter High → Any` * Lists show which entries were added or removed, for example `added Hardware, Software +2 more` * Instructions (and other long text) show a line-by-line comparison with additions in green and removals in red, with unchanged lines collapsed Three actions are available for the selected version: * **Open in a new tab (arrow icon):** Opens this version's full configuration in the editor as a new, unsaved copy — in a second browser tab, while the version list stays open here. Useful for inspecting several versions in full, or comparing an old version with the current one side by side. * **Restore this version:** Loads this version into the editor for the same workflow or agent. Nothing changes until you click **Save Changes** in the editor, so you can review first. This button is disabled on the current version. * **Open as copy:** Opens this version in the editor as a new, unsaved workflow or agent, in the current tab. Useful for branching off an older configuration. Browsing never navigates you away — you can inspect any number of versions without losing your place in the list. The open dialog is also reflected in the page URL, so refreshing the page brings the version history straight back. A toggle in the dialog footer switches timestamps between your local timezone and UTC. <Note> A small number of settings are not part of version snapshots — for example who may access a chat agent. A save that only touched those shows as *No config change*. </Note> ## How versioning works Neo Agent's versioning mechanism is designed to capture a snapshot of your workflow whenever it's modified. ### Automatic version creation Every time a workflow is updated and saved, a new version is automatically logged in the `workflows_updates_log` table in the database. ### Data logged Each entry in the log includes: * The `workflow_id` to link it to the specific workflow * A complete snapshot of the workflow's configuration at that point in time, including its `name`, `state`, `trigger_type`, `schedule`, `actions`, and other settings * The `client_id` and `client_name` for organizational context * Information about the `created_by_user` (who made the update) * The `version_timestamp`, indicating precisely when this version was created ### Retrieval When you open the "Version History" dialog, Neo Agent queries this log table, filtering by the current `workflow_id`, `environment`, and `client_id`, and orders the results by `version_timestamp` in descending order to show the newest versions first. ## Key benefits <CardGroup> <Card title="Audit trail" icon="file-text"> Maintain a clear record of all modifications, essential for change management and compliance. </Card> <Card title="Rollback capability" icon="rotate-left"> If a new workflow configuration introduces issues, you can easily revert to a previously known good state by reviewing an older version and then restoring it. </Card> <Card title="Experimentation" icon="flask"> Feel more confident experimenting with workflow changes, knowing you can always go back. </Card> <Card title="Collaboration" icon="users"> Understand the evolution of a workflow, especially when multiple team members are involved in its development and maintenance. </Card> </CardGroup> ## Best practices <AccordionGroup> <Accordion title="Regular review"> Regularly review version history, especially after making significant changes, to ensure automations are behaving as expected. </Accordion> <Accordion title="Use for troubleshooting"> If you encounter an issue, the version history is your first stop for diagnosis and potential rollback. </Accordion> <Accordion title="Document changes"> When making significant changes, consider adding comments or notes about what was changed and why. </Accordion> <Accordion title="Review before restoring"> Always read the change summary of a version before restoring it, so you know exactly what will change. </Accordion> <Accordion title="Refresh before you edit"> If a teammate saved the workflow while your editor was open, your page is showing the older configuration — and saving it would write that older configuration back over their work. Neo now blocks this. You'll see **"This workflow has been updated by someone else since you started editing"** instead of the save going through. Copy any changes you want to keep, refresh the page to load the current version, then re-apply them. You'll also see it if you enable or disable a workflow from a Workflows page that's been open for a while. Refresh and try again. </Accordion> </AccordionGroup> <Tip> Regularly review version history, especially after making significant changes, to ensure automations are behaving as expected. If you encounter an issue, the version history is your first stop for diagnosis and potential rollback. </Tip> # Building a chat agent Source: https://docs.neoagent.io/chat-agents/building-a-chat-agent Create and configure your own chat agent — instructions, tools, integration permissions, and testing before you expose it to users A chat agent is configured like any other [agent](/core/agents) — instructions, tools, integration permissions. The differences: no trigger, no entity filter, and approvals land in the chat. ## What technicians use internal chat agents for An **Internal** chat agent carries your full MSP toolbox, so builds span the whole service desk. Five patterns cover most of them: | Pattern | A technician asks it… | What it draws on | | - | - | - | | **Research & lookup copilot** | "Summarize ticket 44821", "find the SOP for re-enabling MFA", "what did we do last time this client had this?" | Read-only search across your documentation, configurations, and past tickets — the most common build | | **Queue & dispatch** | "Give me my next ticket", "what's unassigned right now?", "triage my open queue" | Reads the live PSA queue and assigns or routes work — see the [self-serve dispatch recipe](/recipes/technician-self-serve-dispatch) | | **On-demand ticket actions** | "Reply to the customer", "log 15 minutes and set it to In Progress", "schedule a service call", "close it" | Ticket updates, notes, time entries, and service calls — gated behind [approval](/core/technician-in-the-loop) | | **Guided provisioning** | "Onboard these three new starters", "offboard [jdoe@acme.com](mailto:jdoe@acme.com)", "run the workstation-setup checklist" | Microsoft 365 / AD user, group, and license changes against a runbook — gated behind approval | | **On-demand reporting** | "Which Acme firewalls have warranties expiring in 90 days?", "top 10 noisy devices this month", "is Huntress installed on this machine?" | Pulls from PSA, RMM, and documentation, then builds a table or exportable file | A sixth thing technicians want — a self-service helper for your own Neo setup — you already have in the [Neo Support Agent](/chat-agents/neo-support-agent). ## Create the agent <Steps> <Step title="Create"> Go to [**Chat**](https://dashboard.neoagent.io/chat) → **New Chat Agent** (or [create an agent](https://dashboard.neoagent.io/agents/create?mode=chat) in chat mode). There is no Triggers & Filters step — chat agents start when someone messages them. <Frame> <img alt="Chat agent editor — name, test mode, sandbox, and subagent fan-out; no Triggers & Filters tab" /> </Frame> <Tip> Don't want a blank start? Open the [Neo Support Agent](/chat-agents/neo-support-agent#copy-it-for-a-head-start), click **Copy Agent**, and you get an editable Internal agent pre-loaded with its instructions and read-only toolbox to build on. </Tip> </Step> <Step title="Set the audience"> Pick the agent's **Audience** — it's fixed once set and shapes everything below: * **Internal** — for your **own technicians**. Carries your full MSP toolbox (PSA, RMM, Microsoft 365, cross-company lookups). Runs in the dashboard, as a [custom internal Teams bot](/integrations/teams/internal-bot), and is also what the Neo Support Agent is. * **End-user** — for your **clients' employees**. A deliberately narrow, company-scoped tool set, served through a branded end-user bot in [Teams](/teams-bot) or [Slack](/integrations/slack/end-user-bot). See [how end-user bots work](/chat-agents/how-end-user-bots-work). The audience filters the tool picker to the matching set, and a [channel](/chat-agents/channels) can only bind an agent whose audience matches it. </Step> <Step title="Write instructions"> Custom instructions define the agent's job, tone, and limits. Be explicit about what it should refuse and when to ask a technician. If end users will talk to it, write for them — not for your technicians. See [Writing effective agent instructions](/core/writing-agent-instructions) for the full guide. </Step> <Step title="Enable tools and permissions"> Pick [tools](/agents/tools/overview) and set per-integration permissions exactly as for other agents. Enable the minimum the job needs — every enabled write permission is reachable from a chat message. Internal chat bills **per tool call**, not once per turn. Skills under Built-in Capabilities are free to load; the tools they use are not. See [Tool credit costs](/agents/tools/credit-costs). </Step> <Step title="Test in the dashboard"> Chat with it on the **Chat** page before exposing it anywhere. With **test mode** on, the agent describes side-effecting actions in its reply instead of performing them. Test mode does not stop credit spend — each tool call still bills. To come back and edit an agent later, click **Configure** on its row in [**Chat** → **Agents**](https://dashboard.neoagent.io/chat?tab=agents). The **Neo Support Agent** has no **Configure** — Neo manages its configuration. </Step> </Steps> ## Settings that work differently in chat | Setting | Behavior for chat agents | | - | - | | Trigger & filters | None — user-initiated | | Technician-in-the-Loop | Always delivered as an inline approval card in the chat | | Test mode report | Always reported in the chat reply | | Model & reasoning | Platform-managed; no per-agent override | | Mention mode | In Teams group chats and channels, and in Slack channels, the agent is **mention-only** — it answers when @mentioned and stays quiet otherwise. 1:1 chats always respond. Not configurable. | ## PSA records carry the technician's name When a technician asks an internal chat agent to create something in your PSA, that record is attributed to **them**, not to Neo — a time entry lands on their timesheet, a ticket and its notes carry their name. Nothing to switch on: it applies wherever Neo can tell who is asking. This is what makes Teams usable as a quick time-entry front end: "log 20 minutes on T20260729.0031, replaced the switch" from a phone, credited to the right person. Neo identifies the technician from their signed-in identity — their Microsoft account in Teams, or their dashboard login on the web — never from anything they type, so it can't be talked into logging time as someone else. Either way the person needs to be mapped under [**Microsoft Teams — Technician Mapping**](/integrations/teams/workforce-availability), which is also what makes "assign this ticket to me" work. Anyone unmapped isn't blocked: their record is created as Neo, and the agent tells them so in its reply, so it can be reassigned and mapped for next time. **What gets attributed** | PSA | Attributed to the technician | | - | - | | Autotask | Time entries, and tickets, notes and attachments the agent **creates** | | ConnectWise, Halo, ServiceNow | Time entries | Three things to know: * **Creating, not changing.** A status change, a reassignment or a close on an existing ticket stays recorded as Neo — PSAs attribute an edit to whoever's credentials made the call, and only offer attribution on new records. * **Automations are never attributed.** Only chat turns driven by a person are. Anything Neo does on its own — a triage agent, a scheduled sweep — stays visibly Neo's work, so your audit trail still shows what was automated. * **These records behave like a technician's.** A note attributed to a technician is, as far as your PSA is concerned, a technician's note: it fires your "technician added a note" automations, and on a client-facing note your end user sees the technician's name. Notes Neo writes as itself stay recognisably Neo's. <Warning> **Autotask needs a permission on two security levels.** Attributing a ticket, note or attachment uses Autotask's **Resource Impersonation**, which must be allowed both on your Neo API user's level *and* on the level each technician sits on. The first is part of the standard setup; the second is easily missed, and it's per security level — so most of your team can be attributed correctly while everyone on one level isn't. Nothing breaks if it's refused: the record is still created, just under Neo, and Neo tells the technician plus raises an inbox item for your admins naming both levels. Time entries never use impersonation and are unaffected. Full detail: [records created from Teams](/integrations/psa/autotask/overview#records-created-from-teams-carry-the-technicians-name). ConnectWise, Halo and ServiceNow need no extra permission. </Warning> ## In a Teams channel thread When you @mention the agent in a **reply** under a channel post, Teams hands it your reply and nothing else — not the post the thread hangs under. So the agent also reads that original post and treats it as context for the turn, including any screenshot pasted into it. "@Neo create a ticket with this" under a form submission works without you re-typing the form. A few things to know: * It reads the post **once per thread**, on the first message that mentions the agent there. Everything after that is already in the conversation. * Each thread is its own conversation. Mention the agent in a different thread and it starts fresh — the same as opening a new chat. * It reads the post that **started** the thread, not the other replies in between. If a detail lives in a mid-thread reply, quote that reply when you mention the agent. ### What has to be permitted, and by whom Reading the surrounding conversation is permitted **per team**, by an **owner of that team**, at the moment the app is added to it. It is not covered by the one-time admin consent that installed the app, because it is a stronger thing to ask for: it lets the agent read messages in that team's channels, not only the ones that mention it. | | Who does it | Where | | - | - | - | | **Install the app** | a Microsoft Teams or Global admin | the install link you send them, once per tenant | | **Add it to a team, and permit the reading** | an **owner of that team**, for each team | Teams → the team's **⋯** menu → **Manage team** → **Apps** → **Add** | The permission prompt appears at that second step and names your app — your branding, not Neo's. Whoever accepts it is telling you they're happy for the agent to read that team's channel messages, so it's worth them knowing what they're agreeing to. <Note> **A team that already has the app doesn't pick up the reading permission on its own.** Updating the app (**Publish update**) updates what a *new* team sees when it's added — it doesn't reach a team that added the app earlier. For those, an owner of that team needs to **remove the app and add it back**: Teams → **Manage team** → **Apps** → find the app → **Remove**, then **Add** it again. That re-triggers the permission prompt, and accepting it turns the reading on for that team. Until then the agent still answers normally — it just won't see the post above. **If the team belongs to your client, so does the owner.** For a client-facing (end-user) agent the app lives in your client's Microsoft 365 tenant, so the team owners are their people, not yours — you can't do this step for them from the dashboard. Worth folding into the same conversation where you introduce the agent. </Note> ## Who can chat with the agent By default every chat agent is open to your whole team. An admin can change who may message a specific agent from [**Roles & Access** → **Chat Agent Access**](https://dashboard.neoagent.io/rbac?tab=chat-agent-access): | Option | Who can message the agent | | - | - | | **Everyone on your team** | Anyone on your team — the default | | **Admins only** | Your admins only | | **Specific people** | Admins, plus the individual people you choose | The **Specific people** picker lists people who hold a membership. A technician who only uses Microsoft Teams needs one first. Add them through [Add technicians](/product/rbac#adding-technicians-in-bulk) with the **Chat only** role: no dashboard access, no email. Only admins can change this, and it controls *messaging* only — not who can see or edit the agent's configuration, and not what company data the agent may use for each person. That second question is [AI chat data access](/product/rbac#ai-chat-data-access), set per person, so you do not need **Admins only** to keep your PSA or documentation private. It applies to every internal chat agent, including the **Neo Support Agent**. (End-user agents served through a [channel](/chat-agents/channels) are governed by that channel instead.) ## Per-client instructions for end-user agents If the agent serves end users through a [channel](/chat-agents/channels), give a client its own rules with [Memory](/core/memory): create a memory scoped to that company and set its audience to **Chat agents — External**. Neo applies it whenever a user from that company is talking — use it for company-specific policies, escalation contacts, or tone. **Pin** it if it should apply to every conversation; leave it unpinned if the conversation itself will bring it up. <Note> The old **Chat Instructions** box on a company record is retired and no longer read. If you set one before, its text was carried over into Memory for you — you'll find it on the [Memory](https://dashboard.neoagent.io/memories) page, scoped to that company. </Note> ## Before going live * Require [Technician-in-the-Loop](/core/technician-in-the-loop) on write permissions. * For end-user-facing agents, prefer read-only permissions plus "create a ticket" over direct writes. * [Test the agent as an end-client](/chat-agents/channels#testing-as-an-end-client) at a chosen company before you roll the bot out — you'll see its per-company instructions and end-user tools exactly as that company's users will, without installing anything. * [Share a read-only preview](/product/sharing-agents) with the client before rollout — a public, no-login link that shows what the assistant does, with sensitive values masked. # Channels Source: https://docs.neoagent.io/chat-agents/channels Put a chat agent in Microsoft Teams or Slack — for your own technicians (Internal) or your clients' employees (End-user) A **channel** puts one of your chat agents in Microsoft Teams or Slack as a branded bot people message directly. It binds a single chat agent to a transport, carries the branding people see — display name, icon, welcome message — and declares an **audience**: your **own technicians** (Internal) or your **clients' employees** (End-user). The two are equally first-class; the audience is what decides where the bot installs and what the agent can reach. **Microsoft Teams** carries both audiences. **Slack** carries End-user channels: each gets its own branded Slack app, which Neo builds on request (see [Slack](#slack-end-user)). Portal is reserved for a future release. ## Audience: who the channel serves Every channel has an **Audience**, which must match its agent's: * **Internal** — a bot for your **own technicians**, installed into your **own** Microsoft 365 tenant and running with the **full MSP toolbox** you give the agent (it can work across all your companies). Deploy it with the [custom internal bot guide](/integrations/teams/internal-bot). * **End-user** — a white-label bot for your **clients' employees**, installed into **each client's** Microsoft 365 tenant or Slack workspace and **scoped to one company** per conversation. Deploy it with the [end-user Teams bot guide](/integrations/teams/end-user-bot) or the [end-user Slack bot guide](/integrations/slack/end-user-bot). You set the audience on the **New channel** page, and it filters the agent picker to matching agents (an agent's audience is fixed when you build it). The two serve different [trust domains](/chat-agents/how-end-user-bots-work#two-trust-domains), so a channel can't mix them. <Warning> **Audience is fixed once the channel exists.** It decides which tools the agent may use and whose Microsoft 365 tenant the bot installs into, and the Teams app is built for that choice — so there's no way to switch a live channel to the other audience. On an existing channel the field is read-only. To serve the other audience, create a second channel. You can run **several Internal channels** side by side — each gets its own bot identity, so each installs as its own app in your tenant — plus an End-user channel per client tenant, including your own tenant if you want to try the end-user experience yourself. </Warning> This page covers what's **shared** by both — the channel record, branding, and management. The audience-specific parts (where the bot installs, how it's scoped, how to test) live in the two deploy guides linked above. Where a section below is end-user-only, it says so. ## How it fits together ``` Internal: Technician (your tenant) ──> Your branded bot ──> Channel (Internal) ──> Your chat agent · full MSP toolbox, all companies End-user: Employee (client tenant) ──> Your branded bot ──> Channel (End-user) ──> Your chat agent · locked to that one company ``` The channel decides which agent answers and how the bot presents itself; the **audience** decides the rest. You are always the [owner](/chat-agents/overview#whos-talking-to-whom) — your configuration applies and usage bills to you — but the user differs: * **Internal** — the user is one of your technicians, in your own tenant. The agent runs with your full MSP toolbox, across your whole client base. * **End-user** — in Teams, the user's company is recognized automatically from the Microsoft 365 tenant their message comes from, via the tenant ID on the [Company](https://dashboard.neoagent.io/end-companies) record, and every conversation is scoped to that company with a narrower toolbox ([per-company instructions](/chat-agents/building-a-chat-agent#per-client-instructions-for-end-user-agents) apply; the why and how: [how end-user bots work](/chat-agents/how-end-user-bots-work)). In Slack, the company is the one the workspace's install link was made for; see [Slack](#slack-end-user). ## Managing channels Open [**Chat** → **Channels**](https://dashboard.neoagent.io/chat?tab=channels) → **New Channel**. The **New channel** page asks only for the four things a channel is made from: <Frame> <img alt="Channels tab on the Chat page with an active Teams channel" /> </Frame> | Field | Meaning | | - | - | | Transport | Teams, or Slack for an End-user channel. Fixed once created. | | Audience | **Internal** (your technicians) or **End-user** (your clients' employees). It must match the agent, and **can't be changed after you create the channel**. See [Audience](#audience-who-the-channel-serves). | | Name | Internal label, never shown to end users. Must be unique across your channels: it's how you tell them apart in the list, and a second channel with the same name is rejected. | | Agent | **Required**: the chat agent that answers. The picker lists only agents of the chosen audience. | Click **Create channel**. The channel starts **Active** with Neo's default branding and opens on its **Installs** tab. You set everything else on the channel's page. <Note> **Creating a channel doesn't make it reachable.** A new channel is **Active** immediately, but that only means routing isn't paused. For a Teams channel, nobody can message it until the Teams app is **installed** into a Microsoft 365 tenant, and only a **Teams or Global administrator** of that tenant can approve that. For a Slack channel, the Slack app must be requested and ready, and then installed by each client workspace's Slack administrator (see [Slack](#slack-end-user)). See [Installing the bot](#installing-the-bot) below. Over the [API](/developers/introduction), a channel that still needs installing comes back with `install_required: true` and the outstanding step spelled out in `install_next_step` — so don't treat a created channel as live until that field is gone. The **Channels** table and the channel's page show such a channel as **Not installed**. </Note> ### The channel page The header shows the channel's name, which you rename in place, and badges for its transport, audience and status: **Active**, **Disconnected**, or **Not installed**. The **⋮** menu holds **Download Teams app package** (Teams channels) and **Delete channel…**. Delete asks you to confirm, because Neo then stops answering in every installed tenant and Slack workspace; the app stays there until it is removed there too. Below the header are three tabs. Each has its own URL (`?tab=installs`, `?tab=chat`, `?tab=app`), so a link can open the right one. Each setting saves on its own; there is no **Save** button. | Tab | What it holds | A change takes effect | | - | - | - | | **Installs** (opens first) | Where the bot is installed: **White-label installs** on an End-user Teams channel, **Install in your tenant** on an Internal one, install links and connected workspaces on a Slack one. See [Installing the bot](#installing-the-bot) | — | | **Chat** | Agent, Status, Welcome message, Show progress updates, Start fresh after, and Relayed technician messages (End-user only) with a preview of the relayed card | At once, in every tenant. The tab opens with "Changes apply immediately." | | **Teams app** | A live preview of the app, then Show the Tickets tab, Open the app on and Links on the Tickets tab (End-user only), Display name, Description and Icon | In an installed tenant, only after you [publish an update](#publishing-an-update). The tab opens with "Installed tenants get these after you publish." The links are the exception: they need no publish, and show the next time the Tickets tab loads or is refreshed. | | **Slack app** (Slack channels, in place of **Teams app**) | Display name, Description, Icon, Show the Tickets tab, Links on the Tickets tab, and **Request Slack app** | The branding when you request the app again; the Tickets tab when you switch it. See [Updating the app](/integrations/slack/end-user-bot#updating-the-app) | ### Settings that apply at once, and settings that need a publish The **Teams app** settings are part of the app installed in each tenant, so Neo has to send each tenant a new version. The **Chat** settings, and the assigned agent with its instructions and tools, live on Neo's side, so no publish is involved. **Show the Tickets tab** gives an end-user app a **Tickets** tab beside the chat, with each employee's open tickets and those closed in the last 30 days. **Open the app on** picks the tab people see first. A new end-user channel starts with the Tickets tab on and opens on it. **Links on the Tickets tab** puts up to five of your links, such as an emergency number, at the top of that tab. The links need no publish: they show the next time the Tickets tab loads or is refreshed. Everything else on this tab waits for a publish. In a client tenant where users can't approve apps themselves, the Teams tab needs the organization-wide approval of the install link, or each employee is asked for an administrator's approval. Details: [The Tickets tab](/integrations/teams/end-user-bot#the-tickets-tab). A Slack channel has the same switch and links on its **Slack app** tab, where the Tickets tab becomes the Slack app's Home tab: see [the Slack Tickets tab](/integrations/slack/end-user-bot#the-tickets-tab). ### Branding On a Teams channel **all branding is optional**: a blank field uses the Neo default, so a channel works the moment you create it, and clearing a field restores its default. The display name defaults to the channel name. The preview at the top of the **Teams app** tab shows the app as it will look in Teams, including the Tickets tab when it's on. A Slack channel needs a display name before its Slack app can be requested, and its icon comes from the Slack icon upload (see [Slack](#slack-end-user)). <Frame> <img alt="The Teams app tab of an end-user channel: a preview of the app in Teams, the Show the Tickets tab switch, and the display name and description fields" /> </Frame> For **Icon**, pick **Neo** (the default mark), **AI sparkle**, or **Upload your own**. The first two set both the color and the outline icon. With **Upload your own**, set each one: the color icon (192×192) and the outline icon (32×32). Paste an image URL or **Upload** a file (Neo resizes and stores it); **Reset** restores the Neo default. ### Publishing an update Once a tenant has installed the app through an install link, the channel's page shows when that tenant is not on the current Teams app: * **A bar pinned to the bottom of the screen**, on every tab. It reads **Not published:** and lists what waits, such as "Icon changed", "Tickets tab turned on", "App opens on the Tickets tab" or "1 tenant on an older version". * **A dot on the Teams app tab**. * **A Not published marker** beside each field on the **Teams app** tab whose change waits for a publish. The **Channels** table shows **Update not published** under the channel's status. A channel no tenant has installed through a link never shows any of this: a new install always gets the current app. Click the bar's **Publish to N tenants** button (**Publish to your tenant** on an Internal channel). The **Publish update** dialog lists what changes; confirm, and Neo sends the current app to the tenants that need it. After a change to the app, that is every tenant that installed through an install link. With no change, it is only the tenants on an older or unknown version, so a publish after a partly failed one leaves alone the tenants that already updated. An icon set by a pasted image link is the exception: the image can change behind the same link, so that channel always publishes to every tenant. Conversations carry on, and no admin approves anything again unless a tenant's approval has expired or been revoked; the result then lists that tenant ([updating the bot after rollout](/integrations/teams/end-user-bot#updating-the-bot-after-rollout)). Then Teams rolls it out ([Microsoft: app update experience](https://learn.microsoft.com/en-us/microsoftteams/apps-update-experience)): * Teams shows the update after a few hours ([Microsoft](https://learn.microsoft.com/en-us/microsoftteams/teams-custom-app-policies-and-settings)). * In a tenant where the admin did **Install for everyone**, every user gets the update without a prompt. * A user who added the app themselves also gets it without a prompt, unless Microsoft makes each user approve the change. For a channel, that is turning the Tickets tab on or off, or a new bot identity. Each of those users then clicks **Update** in Teams once. The dialog says when this applies. Each tenant installed through an install link shows its version under its status on the **Installs** tab: **Up to date**, **Older version** (the next publish brings it up to date), or **Version unknown** (Neo has not recorded a publish to that tenant yet). When something stops Neo publishing into a tenant, the tenant shows what instead, until it is fixed ([the reasons](/integrations/teams/end-user-bot#troubleshooting)). A new install does not put the other tenants on an older version: it gets the same app they have. With nothing waiting, the bar is gone and a **Publish update** button beside **White-label installs** (**Install in your tenant** on an Internal channel) sends the current app again: to the tenants of unknown version if there are any, or else to every tenant. Tenants that did not update, and tenants installed from the manual zip: [updating the bot after rollout](/integrations/teams/end-user-bot#updating-the-bot-after-rollout). ### Testing as an end-client Before rolling a bot out to a client, chat with the end-user agent **as a real end-user at that company** — the same [per-company instructions](/chat-agents/building-a-chat-agent#per-client-instructions-for-end-user-agents) and the same restricted end-user toolbox apply, scoped to that person's own tickets, just as they'd experience it — without installing anything in their tenant, and without needing a channel at all. It's the fastest way to tune an agent's per-client behavior. The test is reached from the **Agents** tab, because it tests the *agent*, not the channel. Admins and super-admins only, since the test acts as a real end-user. <Frame> <img alt="The Test as end-client dialog — pick an end-client company and an end-user email to chat with the agent exactly as that person would" /> </Frame> <Steps> <Step title="Open the agent's test"> On [**Chat** → **Agents**](https://dashboard.neoagent.io/chat?tab=agents), click **Test** on the end-user agent's row (or open the row's **⋮** menu → **Test as end-client**). Internal agents show **Chat** here instead — they have no end-client to act as. </Step> <Step title="Choose who to act as"> In **Test as end-client**, pick the **End-client company**, then enter an **End-user email** — a real, active [contact](https://dashboard.neoagent.io/end-companies) at that company. The agent acts as this person, so its tools resolve to *their* tickets. </Step> <Step title="Chat"> **Start test chat** opens a normal dashboard chat. A banner — *acting as \<email> at \<company>* — stays pinned above the conversation so the identity is always clear. **New chat** in the session list starts a fresh conversation as the *same* person, keeping the banner; open the agent's **Test** again to switch to a different company or contact. </Step> </Steps> The agent behaves exactly as it would for that end-user: it answers from your customer-facing knowledge and runs the [end-user tools](/agents/tools/end-user/overview) you've added — look up and report the contact's ticket status, file a ticket, post a reply — and nothing that reaches across your client base ([why](/chat-agents/how-end-user-bots-work)). <Note> Anything the agent files lands in your PSA as a **real** record, but unmistakably tagged: ticket titles get an **\[MSP TEST]** prefix and a body line noting the ticket came from a dashboard test, not a real end-user. Test sessions bill like any other dashboard chat. </Note> This checks the agent's *behavior*. To test the actual **Teams experience** — branding, the welcome message, adaptive and approval cards, proactive messages — install the bot into your own tenant first: see [test in your own tenant first](/integrations/teams/end-user-bot#test-in-your-own-tenant-first). #### Troubleshooting | What you see | Why | Fix | | - | - | - | | **Test** is missing or disabled on the agent's row | It's for **end-user** agents only, and acting as a real end-user is admin-only — Internal agents show **Chat** instead | Sign in as an admin or super-admin; if the agent is Internal, use **Chat** (it has no end-client to act as) | | *No active contact with that email at this company* | The email must match an **active** [contact synced from your PSA](/integrations/psa/end-user-communication) under the chosen company | Use an email that exists and is active for that company — re-sync contacts if it's missing — or pick the company the contact actually belongs to | | The agent can't see the contact's tickets | The contact resolved but the tickets live under a different company | Pick the company the contact's tickets belong to | | *A session must be started as a specific end-client contact* on **New chat** | An end-user agent only works inside an end-client identity — without one it has no contact to act as and no per-company setup to apply, so it can answer but not actually do anything | Start the chat from the agent's **Test** button instead. **New chat** carries the current identity forward on its own; you only see this when there is no test session open to carry it from | ## Installing the bot For a Teams channel, where the bot installs follows the audience. Both produce a branded Teams app and bind routing to this channel; the full step-by-step lives in each guide. A Slack channel installs as described in [Slack](#slack-end-user). ### Internal — into your own tenant An **Internal** channel installs into your **own** Microsoft 365 tenant for your technicians. On the channel's **Installs** tab, under **Install in your tenant**, **Generate install link** and open it yourself as a Teams/Global admin (or sideload the package from **⋮** → **Download Teams app package**). Full walkthrough: the [custom internal bot guide](/integrations/teams/internal-bot). An Internal channel can **only** be installed in your own tenant — Neo refuses a client tenant, because it runs your full cross-company toolbox. **Several Internal channels.** Each new Internal channel gets its own bot identity, so several install side by side in your own tenant — say one for dispatch and one for documentation. The identities come from a fixed pool; once it is used up, creating another Internal channel is refused, on the **New channel** page and over the API alike, and the message tells you to delete an Internal channel you no longer use or to contact support. ### End-user — into client tenants Send each client's Teams or Global administrator a **magic install link** from the **White-label installs** table on the channel's **Installs** tab: one sign-in publishes your branded app into their tenant and registers routing. **One branded bot per client**: a tenant already bound to another channel is refused. The table has one row per tenant, and each row shows where that tenant is: **Link sent**, **Installed**, **Live for everyone** and so on. The **Channels** table shows each channel's tenant count. The step-by-step procedure, the manual zip path, verification and troubleshooting are in the [end-user bot deployment guide](/integrations/teams/end-user-bot). <Info> The company picker uses the Microsoft 365 **tenant ID** set on each [Company](https://dashboard.neoagent.io/end-companies) — a company without one can't be added until you set it there. </Info> ## Slack (End-user) A Slack channel reaches your clients' employees in their own Slack workspace, under your brand. A Slack channel is always **End-user**, and a channel can't be switched between Teams and Slack. In Slack the app's name and icon belong to the app itself, so every Slack channel gets **its own Slack app**, which Neo builds for you. In short: on the channel's **Slack app** tab, set the branding (a display name of at most 35 characters, and an icon of at least 512 × 512 px), click **Request Slack app**, and wait for **Ready**. Then, on the **Installs** tab, generate an install link per client company and send it to that client's Slack admin. The workspace that installs with it is linked to that company, and every conversation from it is scoped to that company. The full procedure, what end users see in Slack, how it differs from Teams, and troubleshooting are in the [end-user Slack bot guide](/integrations/slack/end-user-bot). ## What people experience in Teams This section covers Teams; for Slack, see [what end users see](/integrations/slack/end-user-bot#what-end-users-see). In Teams it's the same for both audiences: your bot, your name and icon — Neo isn't visible. The welcome message greets them on first contact; 1:1 chats always respond, group chats follow the agent's [mention mode](/chat-agents/building-a-chat-agent#settings-that-work-differently-in-chat); **"start a new chat"** starts a fresh conversation. While the bot works on a reply it can show a live **"working…"** card listing the steps it's taking, so a longer answer never looks stuck. That's **Show progress updates** on the channel's **Chat** tab, and a new channel starts with it **on for Internal channels and off for end-user ones** — technicians generally want to see the agent working, employees generally just want the answer. Switch it either way per channel at any time; the bot's answers are identical either way. On an end-user channel the card only ever shows plain progress labels, such as "Checking your tickets" or "Filing a ticket" — never tool names, the details a tool was sent or returned, or the agent's reasoning. On an Internal channel your technicians can also tap a step to see those details. While the agent works, the card has a **Stop** button. It stops the agent before its next step, and also drops any message sent after it that is still waiting for an answer. The card then reads **Stopped**, and no reply follows. Only the person whose message the agent is answering can press it, so in a group chat nobody stops a colleague's question. The conversation stays, so the next message carries on from there. In **1:1 chats**, a long answer can appear as it's written rather than arriving all at once, with a **Stop** button to cut it short. Group chats and channels always receive the finished reply in one message, which is a Microsoft Teams limitation rather than a setting. ### Starting fresh after a pause A conversation carries on where it left off, however long the gap — so someone who comes back the next morning doesn't have to re-explain themselves. When picking up an old conversation would be slow, though, the bot offers a **Start fresh / Continue** card instead of silently resuming, and the person chooses. Nothing is ever discarded automatically. Out of the box that only happens on conversations long enough to have grown large, which is exactly when resuming is worth a question. A **transactional** bot — one where each request stands on its own, like an onboarding or access-request assistant — usually wants it sooner: a new visitor tomorrow shouldn't inherit yesterday's half-finished request. Set **Start fresh after** on the channel's **Chat** tab to a number of minutes and the bot offers the card that much after the last message too. Leave it empty for the built-in timing alone. The card is the same either way, and **Continue** always resumes the existing conversation — so a short window costs someone at most one tap if they were only away for coffee. On an **end-user** channel, when a technician's reply on a ticket is [relayed into the chat](/integrations/teams/end-user-bot#live-ticket-updates-in-the-chat), it arrives as a card showing who replied — by default the technician's own name and avatar — with the ticket's title, number and current status, so employees know it isn't the AI. Under **Relayed technician messages** on the channel's **Chat** tab you can show your own name instead of individual technicians', change the wording or language, or switch labelling off entirely. That avatar is the technician's **real Microsoft 365 profile photo** for anyone mapped through [Microsoft Teams — Technician Mapping](/integrations/teams/workforce-availability#technician-photos-on-relayed-replies), and coloured initials otherwise. Nothing to configure per channel — the channel's settings choose *whose name* appears, and the mapping decides whether that name comes with a face. The card's title line is the ticket's own title, which is what tells one of a contact's open tickets from another — somebody with six of them open reads "the password one", not a number. Turn off **Show the ticket title** if your ticket titles are internal shorthand rather than the words the end-user raised the ticket in. The status on that card is the status name from your PSA, in whatever language your PSA is set up in — Neo passes it through and can't translate it there. If that language isn't one this channel's end-users read, turn off **Show the ticket status**. The two switches are independent, and the **ticket number is always shown** — it is the one thing that ties the card to a ticket in any language. <Warning> **End-user channels only:** the bot is messaging-only in client tenants — no Microsoft Graph access there. Anything the agent does happens through **your** integrations under **your** permissions — and every end-user session is **scoped to the end user's company**: tools that operate across your whole client base (MSP-wide ticket search, company listings, generic API access) never run for end users, regardless of the agent's toolbox — see [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access). (An **Internal** channel is the opposite by design: it runs your full MSP toolbox across all companies.) The magic-link install does have the client's Teams admin sign in once, but that authorizes a separate **Neo Installer** app only to publish the app to their catalog — it grants the bot no standing access to their data. </Warning> # How end-user bots work Source: https://docs.neoagent.io/chat-agents/how-end-user-bots-work The architecture behind your branded Teams or Slack bot — a fast conversational front end, your Neo agents doing the heavy lifting, and the ticket as the secure boundary between them Your branded Teams or Slack bot and the Neo agents that resolve tickets are deliberately **not the same thing**. Understanding the split explains both why the bot is safe to put in front of your clients' employees and where its real power comes from. ## Two trust domains A technician on your team and an employee at your client are different audiences with different rights: * **Your technicians** work across your whole client base. Agents serving them (the dashboard, [Neo Support](/chat-agents/neo-support-agent), your triggered workflows) can search every company's tickets, call your PSA and Microsoft 365 integrations directly, and act under your permission groups and approvals. * **Your clients' employees** are entitled to their own company's support experience — and nothing else. Not your other clients' names, not MSP-wide ticket history, not direct access to your integrations. One agent configuration can't safely serve both, no matter how carefully its tools are picked — so Neo doesn't try. The boundary is enforced by the platform, not by configuration: a conversation through an end-user channel is recognized from the sender's Microsoft 365 tenant (and, when that tenant spans several companies, the sender's verified email), or in Slack from the workspace the app was installed in for that company, and locked to one company for its whole life (see [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access)). ## Three layers ``` Client employee in Teams or Slack │ ▼ ┌─────────────────────────┐ │ Your branded bot │ conversation: understand the request, answer │ (the interface) │ what it can, check status, gather details └─────────────────────────┘ │ tickets — the only crossing point ▼ ┌─────────────────────────┐ │ The ticket │ the employee sees title, status, and │ (the boundary) │ client-facing replies — never internal notes └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ Your Neo agents │ full power: PSA, Microsoft 365, RMM, │ and workflows (the core) │ diagnostics — under your permissions & approvals └─────────────────────────┘ ``` **The bot is a smart interface, not a powerful agent.** Its job is conversation: turn "my wifi is bad" into a well-described ticket, answer the questions your instructions cover, and keep the employee informed about their requests. For the common requests you see repeatedly, you can give it [intents](/chat-agents/intents) so it collects exactly the right details and files each ticket categorised correctly. It works only with the employee's own identity — their company and their tickets — taken from the verified session, never from anything typed in the chat. **The ticket is the boundary object.** It's the one artifact both sides legitimately touch. The employee's side sees the client-facing projection: title, status, the replies meant for them. Your side sees everything and can do everything. A ticket the bot files moves through statuses you nominate — **initial** while the bot still has it, **resolved** if it fixes the issue outright, and optionally an **escalation** status for when it hands over to a technician. The end-user ticket tool needs two things configured: a destination for its tickets (the board or queue and type, per your PSA) and the initial/resolved status pair — the escalation status stays optional. See [where end-user tickets land](/agents/tools/end-user/overview#configure-where-end-user-tickets-land) and [handing a ticket to a technician](/agents/tools/end-user/overview#handing-a-ticket-to-a-technician). **Your existing agents are the muscle.** A ticket filed by the bot triggers your workflows exactly like a ticket from email or your portal — same triggers, same tools, same integration permissions and [technician approvals](/core/technician-in-the-loop), same billing. The full power of Neo reaches your clients' employees *through* the ticket, without the bot ever holding that power itself. ## Why it's built this way * **Security by construction, not by configuration.** There is no toolbox setting that can accidentally expose your client base through an end-user channel — the platform resolves a separate, end-user-only tool surface for these conversations regardless of the agent's configuration. * **Nothing new to govern.** All powerful execution stays inside the controls you already configured: integration permissions, technician approvals, audit history, credits. Putting a bot in front of a client adds no new access to review. * **Each layer fits its job.** The chat edge is high-volume and latency-sensitive; deep resolution work is neither. Splitting them lets the conversation stay snappy while the heavy work runs with full context behind the ticket. <Info> What the bot can do inside its own lane — every tool it holds, what each one is scoped to, and the ticket destination and statuses you configure — is documented in [end-user tools](/agents/tools/end-user/overview). For which capabilities reach end users and what happens for tenants that aren't linked to a company, see [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access). </Info> # Intent Forms Source: https://docs.neoagent.io/chat-agents/intent-forms Turn an intent's intake into a form the employee fills in — dropdowns, dates and yes/no answers collected in one go instead of a back-and-forth Some intake is a list of specific answers rather than a conversation — a device from a list, a start date, a yes/no. Add a **form** to an [intent](/chat-agents/intents) and the employee gets all the questions at once instead of a back-and-forth: one card with a dropdown, a date picker and a toggle beats four rounds of questions, and the answers come back in the shape you asked for. <Frame> <img alt="A branded end-user bot in Microsoft Teams. The employee wrote 'i need to onboard a new user' and the bot replied that it's opening the New/Existing User Deployment Request intake, followed by a form card with labelled fields — full name, job title, direct manager, contact number, work location, address, start date, device assignment — each marked required." /> </Frame> ## What the employee sees The bot recognises the request from the intents offered to their company, then posts the form and waits. It doesn't ask those questions itself and doesn't repeat them back — the form is the intake. * **Required questions are enforced in the card.** A missing answer is flagged where the employee is typing, before anything is sent. * **Each form is submitted once.** Scrolling back and re-tapping an old card doesn't inject stale answers into a live conversation — the bot shows what was already sent instead. * **After Submit the card becomes a read-only summary** of the answers that went through. Because the answers reach the agent as a submission rather than a typed message, that summary is the employee's record of what they sent. * **In a group chat, the form belongs to whoever asked.** Everyone can see the card, but only the person whose request produced it can submit it. Then the agent carries on exactly as it would after a conversation: it files the ticket to its configured Create Ticket destination with every answer in the body. Forms also render in the dashboard chat, so you can fill one in yourself to check the wording before rolling it out to a client. ## Building a form Forms are built on the intent itself, under **Form**, below **Questions to ask**. <Frame> <img alt="The Neo dashboard intent editor for New/Existing User Deployment Request, showing Name and Description at the top, a Questions to ask text area, and a Form section listing question rows — each with a Question field, a Type dropdown set to Short text, and a Required toggle." /> </Frame> <Steps> <Step title="Open the intent"> Go to [**Intents**](https://dashboard.neoagent.io/intents) under **Data** in the left navigation and open the intent (or create one). </Step> <Step title="Add your questions"> Under **Form**, select **Add question**. Each question has the text the employee sees, a **Type**, and a **Required** toggle. Reorder with the arrows — the form asks them in the order you list them. </Step> <Step title="Add a description where the question needs one"> Select **Add description** on a question to add an optional line shown under it, for anything the question itself can't carry — a rule, a lead time, what counts as an exception. *"Please note there is a ten day lead time on all new starters"* belongs here, not in the question. Most questions don't need one, so the box only appears when you ask for it; the ✕ beside it removes the description again. It reaches every surface: under the input on a form, and in brackets after the question in the numbered list a triggered agent sends. </Step> <Step title="Add options where the type needs them"> **Dropdown** and **Multi-select** questions take an **Options** list; the other types don't. </Step> <Step title="Save"> The form is live on the next message — you don't need to restart a conversation that's already open. </Step> </Steps> ### Question types | Type | What the employee gets | | - | - | | **Short text** | A single-line answer — a name, a phone number. | | **Long text** | A multi-line answer — an address, a description. | | **Dropdown** | One choice from your options list. | | **Multi-select** | Any number of choices from your options list. | | **Number** | A numeric answer. | | **Date** | A date picker. | | **Time** | A time picker. | | **Yes / No** | A toggle. | **Dropdown** and **Multi-select** need at least one option; the other types don't take options at all. ### Limits An intent's form can hold up to **25 questions**, with up to **40 options** on any one question and **150 options** across the whole form. A description can run to **750 characters**, and **5,000 characters** across the whole form. None of these are taste. Everything on a form travels inside one Teams card, options twice over, and a card past 28KB doesn't render at all. The editor shows your counts as you build and blocks a save that goes over. ## Forms and "Questions to ask" together The two can coexist, and which one is used depends on where the request arrives: | | Form only | Both filled in | Questions only | | - | - | - | - | | **End-user chat** | The form | The form | The questions, asked in conversation | | **Internal chat** | The form | The form | The questions, asked in conversation | | **Triggered agents** | The form's questions, as a numbered list | Your written questions | The questions, in the agent's reply | Both chat surfaces can draw a form, so someone in internal chat fills in the same card an end user would. A ticket has nowhere to draw one, so on a [triggered agent](/core/triggers-and-schedules/triggered-workflows) the same questions become a numbered list in the agent's client-facing reply, options spelled out. Nothing is lost; it just arrives as an email. That's the reason to fill in both: write prose specifically for the email round-trip while chat users get the form. Leave **Questions to ask** empty and the form's questions stand in on every surface. <Tip> Use form questions for answers you need in a fixed shape (which office, which laptop model, what date) and **Questions to ask** for anything conditional or judgement-based (*"if they need RDS access, ask which existing user to mirror"*). A form can't branch — a question can. </Tip> ## Related <CardGroup> <Card title="Intents" icon="clipboard-list" href="/chat-agents/intents"> What an intent is, how it's matched, and how to scope one to agents and companies. </Card> <Card title="How end-user bots work" icon="sitemap" href="/chat-agents/how-end-user-bots-work"> The trust boundary and the bot-ticket-agent split behind every end-user conversation. </Card> <Card title="Triggered workflows" icon="bolt" href="/core/triggers-and-schedules/triggered-workflows"> How ticket events trigger an agent — and how a customer reply re-triggers it to continue intake. </Card> <Card title="Teaching Neo" icon="graduation-cap" href="/core/teaching-neo"> Where intents fit next to instructions, skills, and memory — and how the four compose. </Card> </CardGroup> # Intents Source: https://docs.neoagent.io/chat-agents/intents Teach Neo the common requests your clients raise — and exactly which details to collect — so intake is complete and consistent whether the request arrives in chat or as a ticket **Intents** are for the requests you see over and over — a new starter, a hardware request, a mailbox permission change. For each intent you tell Neo *what details to collect*, in plain language. Neo then runs a consistent intake every time: it gathers exactly the information your team needs before work starts, instead of a technician chasing the requester for the start date or the 2FA number afterwards. Intents work on three kinds of agents, and you choose which with the intent's **Applies to** setting: * **End-user chat** — your [branded end-user bot](/chat-agents/how-end-user-bots-work) recognises the request in conversation, asks the intake questions, and files the ticket. * **Internal chat** — an internal (MSP) chat agent does the same for **your own people**, in the dashboard or a Teams channel of yours. * **Triggered agents** — a [ticket-triggered agent](/core/triggers-and-schedules/triggered-workflows) recognises the request on an inbound ticket (typically an email), checks what the ticket already answers, and asks the end user only for what's missing. An intent can apply to one surface or several — the same "New Starter" intent can drive your chat bot, your internal bot, *and* your email-intake agent. ## How it works in chat When an employee's request matches one of the intents offered to their company, the bot: 1. **Recognises it** from the short menu of intents set up for that employee's company. 2. **Pulls up the intake** for that intent on demand — so the bot's instructions stay small no matter how many intents you add. 3. **Collects the details** — either by showing the employee a [form](/chat-agents/intent-forms) to fill in (if the intent has one), or by asking only what it doesn't already know from the conversation, one dependent question at a time, exactly like a good technician taking the request. 4. **Files the ticket** to the agent's configured Create Ticket destination, with everything collected in the body. If nothing matches, the bot simply handles the request as normal free-form conversation. Intents add structure to the common cases; they never get in the way of the rest. ## How it works in internal chat Give an intent the **Internal chat** surface and assign it to one of your internal (MSP) chat agents, and your own people get the same intake — in the dashboard or wherever you've put that agent in Teams. Someone raising a quote request in your quote-request channel gets the form instead of a back-and-forth, and the request arrives complete the first time. Two things work differently here: * **Companies don't scope this surface.** An internal conversation isn't attached to a client company, so internal chat offers only intents that apply to **all** companies. An intent scoped to specific companies still runs on your end-user and triggered agents — it just doesn't appear in internal chat. If you need the details to differ per client, ask for the client in the intake and let the agent's instructions branch. * **The Neo Support Agent can carry intents too**, but only when you pick it by name. Leaving **Applies to — agents** empty means "every internal chat agent" — except that one, so an intent you meant for your own bots never quietly changes the agent Neo maintains for you. ## How it works on a triggered agent Most requests don't arrive in a chat — they arrive as an email that becomes a ticket. Give an intent the **Triggered agents** surface and assign it to a ticket-triggered agent (for example the agent watching your service-request board), and that agent gains the same structured intake: 1. **Recognises** that the new ticket matches one of your intents — most tickets won't, and the agent is explicitly told never to force a match. 2. **Loads the intake questions** for that intent. 3. **Compares** them against what the ticket already contains — the original email and any replies. 4. **Asks the end user only for what's missing**, in one client-facing note, then waits. The requester's reply re-triggers the agent, which continues with the complete picture — the same ask-and-wait loop your triggered agents already use for clarifying questions. For example, with a "User Onboarding" intent, an office manager's email — *"Hi, we've got someone new starting in the Bristol office"* — comes back with one reply asking for the full name, start date, an access-template colleague, and the 2FA mobile number. When the manager answers, the agent picks the ticket back up with everything a technician (or your onboarding automation) needs. ## What an intent contains | Part | What it's for | | - | - | | **Name** | A short label — e.g. "New Starter", "New Hardware", "Mailbox Access". | | **Description** | How Neo recognises the request. Neo reads only the name and description of each intent when it decides which one fits, and loads the questions after it has picked. Say when to use it, in the words people use, and when not to use it. Up to 500 characters when you save an enabled intent. See [Writing a good description](#writing-a-good-description). | | **Questions to ask** | The details to gather for this request, in plain language (e.g. *"Full name, start date, which existing user to copy access from, and the 2FA mobile number"*). Neo skips anything it already knows and asks dependent questions in order. | | **Form** *(optional)* | The same intake as a set of typed questions — dropdowns, dates, yes/no toggles — shown to the employee as a form instead of asked one at a time. See [Intent Forms](/chat-agents/intent-forms). | | **Applies to — surfaces** | Where this intent runs: **End-user chat**, **Internal chat**, **Triggered agents**, or any combination. | | **Applies to — agents** | Which of your agents offer this intent — leave empty to apply it to every agent of the selected surface(s), except the Neo Support Agent, which applies only when named (see [Scoping](#scoping)). | | **Applies to — companies** | Which of your client companies this intent is offered to — leave empty for all. A company-scoped intent doesn't appear in **Internal chat** (see [Scoping](#scoping)). | Tickets always land in the agent's own configured destination — an intent is a pure intake script and doesn't change where or how the ticket is filed. ### Writing a good description The name and description together decide whether Neo loads the intent at all, and the description carries most of that. Neo sees each intent as one line, its name and its description, and picks from that list before it reads any questions or form. With many intents on one agent, a description that only repeats the name leaves Neo guessing between similar requests. * Say when to use it, in the words people use when they ask: *"Someone new is joining and needs accounts, a laptop and access set up. People also say new starter, new hire or onboarding."* * Say when not to use it, and name the intent to use instead: *"Not for changes to an existing employee (use Mover) or someone leaving (use Leaver)."* * Keep the questions out. They belong in **Questions to ask** or the form, which Neo reads after it has picked. The editor shows the line Neo reads, and lists the other intents the same agents offer so you can see what yours must stand apart from. An intent whose description is empty, repeats its name, or is only a few words shows **Weak description** on the Intents page. ### Writing good questions The **Questions to ask** field is free text read by the agent, so write it the way you'd brief a junior technician: * List every detail your team needs to action the request without a follow-up — names, dates, devices, approvals. * Note conditional questions inline: *"If they need RDS access, ask which existing user to mirror."* Neo asks dependent questions one at a time. * Don't include details Neo can infer (the requester's own name or company) — Neo already knows the conversation and the ticket, and only asks for what's genuinely missing. ## Forms Some intake is a list of specific answers rather than a conversation — a device from a list, a start date, a yes/no. For those, add a **form** to the intent and the employee fills it in instead of answering one question at a time: a dropdown, a date picker and a toggle in one card. On a triggered agent, where there's nowhere to draw a form, the same questions arrive as a numbered list in the agent's reply. See [Intent Forms](/chat-agents/intent-forms) for the question types, the limits, and how a form and **Questions to ask** work together. ## Scoping Intents are **tenant-level and cross-agent** — you author one library of intents and assign each one to the surfaces, agents, and companies it should apply to. Agent and company scope work the same way, and **leaving either empty means "all"**: * **Agents** — assign an intent to specific agents (e.g. only your "VIP Support" bot, or only the service-request board's agent), or leave it empty to offer it on every agent of the selected surfaces. Authoring a common request like "New Starter" once and applying it everywhere beats duplicating it per agent. * **Companies** — offer a different set to different clients: one client's "New Starter" intent collects a 2FA number and an RDS-access answer, another's doesn't; a client on a phone system gets a "Ring Group Change" intent that others never see. **Internal chat only offers all-company intents** — an internal conversation has no client attached to match a company scope against, so a company-scoped intent is simply absent there. At runtime a request only ever meets the intents whose surface, agent scope, **and** company scope all include it — the surface it arrived on, the agent handling it, and the requester's company. <Note> **The Neo Support Agent never picks up an intent by wildcard.** It's a valid target on **Internal chat** and you can assign one to it deliberately, but "every agent of the selected surfaces" (empty **Applies to — agents**) skips it — so an intent you wrote for your own bots can't change how the agent Neo maintains for you behaves. </Note> <Note> **At most 40 intents can apply to any single agent.** Every applicable intent is offered to the agent, and the more it has to choose from, the more each description matters. If enabling or assigning an intent would push an agent past 40, Neo blocks the save and names the agent — disable or reassign one of that agent's intents first. Remember a broad intent (empty **Applies to — agents**) counts toward every agent of its surface. Disabling an intent is always allowed and frees up a slot. </Note> ## Example: a new-starter intent in chat > **Employee:** Can you set up a new starter for me? <br /><br /> > **Bot:** Happy to help. Please share the new joiner's full name, their start date, an existing user to copy access from, and whether they need RDS access. <br /><br /> > **Employee:** Jamie Rivera, starting 14 July, copy access from Alex Morgan, and yes to RDS. <br /><br /> > **Bot:** Thanks — what's the 2FA mobile number for Jamie? <br /><br /> > **Employee:** 07700 900123 <br /><br /> > **Bot:** All set — I've raised ticket #4821 for Jamie Rivera's onboarding and your IT team will take it from here. The same intent with the **Triggered agents** surface handles the email version: a half-complete onboarding email becomes a ticket, the agent replies asking only for the missing 2FA number and start date, and the requester's answer re-triggers the agent to finish intake. ## Setting up intents Your intents live in one place — add as many as you need, and edit or disable them any time. Owners, Admins and Users can change intents. A **Viewer** sees the same list and can open each intent, but read-only. See [Role-Based Access Control](/product/rbac). <Steps> <Step title="Open Intents"> Go to [**Intents**](https://dashboard.neoagent.io/intents) under **Data** in the left navigation. </Step> <Step title="Add an intent"> Select **New intent**, then give it a **name** and a **description** that says when to use it and when not to. Neo picks an intent from these two alone. </Step> <Step title="Say what to collect"> Either write the **questions to ask** in plain language — Neo asks only for what it doesn't already know, and works through dependent questions in order — or build a **form** the employee fills in, or both. See [Intent Forms](/chat-agents/intent-forms). </Step> <Step title="Choose where it applies"> Switch to the **Applies to** tab and pick the **surfaces** — end-user chat, internal chat, triggered agents, or any combination — then which agents offer this intent and which client companies it applies to (leave agents/companies empty to apply to all; a company-scoped intent doesn't appear in internal chat). </Step> <Step title="Save"> The intent goes live immediately for the surfaces, agents, and companies you chose. </Step> </Steps> <Tip> **Adjust with Neo** sits at the top of a saved intent's editor. Click it, say what you want changed, and the [Neo Support Agent](/chat-agents/neo-support-agent) reads the saved intent, proposes the edit, and applies it once you confirm — questions, form, surfaces, scope, any part of it. It reads the *saved* intent, so the button stays disabled until you've saved what's on screen, and a brand-new intent has to be saved once before the button appears. </Tip> ## Managing intents with the API Intents are also fully manageable over Neo's public API — list, read, create, update, and delete them under `/public-api/intents` — so you can author your intent library from your own scripts or provision it per client. See the [API reference](/developers/introduction). ## Related <CardGroup> <Card title="Intent Forms" icon="table-list" href="/chat-agents/intent-forms"> Turn an intent's intake into a form — question types, limits, and what the employee sees. </Card> <Card title="Teaching Neo" icon="graduation-cap" href="/core/teaching-neo"> Where intents fit next to instructions, skills, and memory — and how the four compose. </Card> <Card title="How end-user bots work" icon="sitemap" href="/chat-agents/how-end-user-bots-work"> The trust boundary and the bot-ticket-agent split behind every end-user conversation. </Card> <Card title="Triggered workflows" icon="bolt" href="/core/triggers-and-schedules/triggered-workflows"> How ticket events trigger an agent — and how a customer reply re-triggers it to continue intake. </Card> <Card title="End-user tools" icon="screwdriver-wrench" href="/agents/tools/end-user/overview"> Every tool a branded bot uses — find docs, check tickets, file, resolve, attach files. </Card> <Card title="Built-in tools" icon="toolbox" href="/agents/tools/built-in/overview"> Load Intent and the other tools an agent gets automatically. </Card> </CardGroup> # Neo Support Agent Source: https://docs.neoagent.io/chat-agents/neo-support-agent The Neo-managed chat agent every MSP gets — answers Neo configuration questions and searches your docs and tickets Every MSP has a **Neo Support Agent**: a chat agent built and maintained by Neo. It answers questions about your Neo setup ("why didn't this workflow trigger?", "how do I enable test mode?") and can search your own documentation and past tickets to help technicians. ## What it can do | Capability | How | | - | - | | Answer Neo product and configuration questions | Reads your workflows, agents, settings, and execution history through Neo's own API, plus the public docs | | Search your knowledge base | Documentation search across your connected doc systems | | Search your tickets | Finds similar past tickets and summarizes them | | Look things up on the web | Web fetch for vendor docs and KB articles | | Email you a data export | Builds a report or CSV and emails it to **you** (the person chatting) as a durable attachment, so a large result isn't dumped into the chat | | Build and manage your skills | Compiles a [custom skill](/agents/skills/custom-skills) from a past run (or a description), tests it, and saves it to your Skills tab | | Manage agent memories | Views, adds, corrects, pins, and removes the [memories](/core/memory) Neo recalls into agent runs — e.g. "why does Neo keep saying our VPN is Cisco?" → find the wrong fact and replace it. Every change asks for your approval first | ## What it can access The Neo Support Agent automatically gets **read-only** access to your connected PSA and documentation systems — no setup needed. It cannot write to your PSA, run scripts, or touch Microsoft 365. Sensitive permission groups are excluded. Which of those systems it reads depends on who is asking. Admins reach every connected system; for everyone else it reads only what that person is granted under [AI chat data access](/product/rbac#ai-chat-data-access), and it says what it cannot reach rather than answering with less data. When it emails you a data export, it can send **only to you** — the person it is chatting with, resolved from your signed-in identity. It cannot email any other address, so this is a way to keep your own report, not a way to send data out. When it reviews or edits an agent's custom instructions, it also checks that each part is in the right place. A fact about one client company that Neo cannot already read from your PSA or documentation belongs in a [memory](/core/memory), a routine of about five or more steps that applies to only some of the agent's runs in a [skill](/agents/skills/custom-skills), and the questions for one request type in an [intent](/chat-agents/intents). Where it finds such content it offers up to three moves, one line each, and moves nothing until you say yes; instructions that hold only the agent's own rules get no such offer. A password or key inside the instructions is reported as a security finding with an offer to remove it. The rules it applies are on [Teaching Neo](/core/teaching-neo#where-does-this-belong). It can also curate your Neo configuration on your behalf — agents, settings, skills, and [agent memories](/core/memory). Agent edits (like updating an agent's custom instructions) apply directly once you confirm the exact change in the conversation — you're the approver, so there's no second approval card. The same goes for creating an agent as a disabled draft (the guided template setup's shape): it stays inert until you review and enable it in the dashboard, so your go-ahead in chat is the approval. Creating an agent that would start enabled still asks first. Higher-blast-radius writes — deleting an agent, tenant-wide settings, disconnecting an integration, memory changes — still show an inline approval card first, so nothing destructive happens without an explicit approve click. ## Asking for something Neo can't do yet If you ask for a feature Neo doesn't have, the agent tells you plainly, then tells you where to click: [**Roadmap & Updates**](/product/roadmap-and-updates), in the **Help** menu at the bottom of the dashboard's left-hand menu. That's Neo's feedback board, where other MSPs can vote on your request. The agent also offers you a short write-up you can paste straight into the post. It won't open a support ticket for a feature request. It raises a support ticket only for something broken, something blocking you right now, or when you ask for a human — and when it does, it calls it a support ticket. ## It knows which page you're on When you chat from the **Need help?** widget, the agent is told which dashboard page you have open — and, on an agent or workflow page, which one you're looking at. So "why did this run fail?" or "add a rule to this agent" works without spelling out which agent you mean. What travels with your message is the page name and the id already in the address bar (for example: *Agent editor, "L1 Engineer (Advanced)" (id 19363)*). Nothing else — not what's on your screen, not what you've typed into a form, not what you're scrolled to. It's context for resolving "this", not the subject of your question: ask about something on another page and the agent follows you, not the page. You'll see a small marker under a message when the page went with it, and the widget only sends it again once you've moved somewhere new. <Note> This applies to the **Need help?** widget only. The full-page [**Chat**](https://dashboard.neoagent.io/chat) surface and the Microsoft Teams bot send exactly what you type. </Note> ## Managed by Neo Its configuration — instructions, tools, model — is owned by Neo and updated centrally, so every MSP always runs the latest version. That's why it shows a **Managed by Neo** badge and can't be edited or deleted in the dashboard. ## Copy it for a head start You can't edit the Neo Support Agent itself, but you can **copy** it. Open it from the [**Chat**](https://dashboard.neoagent.io/chat) page and click **Copy Agent** — Neo opens *your own* editable Internal chat agent, pre-loaded with the Neo Support Agent's instructions and read-only toolbox. The copy starts unsaved, so click **Create Chat Agent** to keep it. The copy is fully yours: rename it, rewrite the instructions, and add write tools (PSA updates, Microsoft 365, RMM) to turn a read-only assistant into one of the [internal patterns](/chat-agents/building-a-chat-agent#what-technicians-use-internal-chat-agents-for) above. ## Where to find it * **Dashboard** — first card on the [**Chat**](https://dashboard.neoagent.io/chat) page, and the **Need help?** button in the bottom-right corner of every page. Both appear for everyone allowed to message the agent under [Chat Agent Access](/product/rbac#chat-agent-access) (everyone on your team, by default). The panel it opens is resizable: drag its top or left edge to the size you want, and use the expand button in its header to switch between your size and the original compact one. Your size is remembered. A fresh conversation offers a few conversation starters. In the **Need help?** widget, opening it while you're looking at a specific agent, workflow or run gets starters drafted for that one ("Troubleshoot this agent"); everywhere else — and on the full-page Chat surface — you get a fixed set (build a scheduled report, build a new agent, adjust an agent, troubleshoot an agent, create a reusable skill), with page-specific picks on the Skills and Memory pages. Picking one drops a ready-made opening into the message box; add your specifics and send. And where a conversation opened from a dashboard button asks you to type into a note field — a template's guided setup, updating a saved agent's instructions or one field's box, adjusting an intent or a skill — tappable note suggestions appear under the card, drafted from what you handed over. * **Microsoft Teams** — install the [Neo AI Agent app](/integrations/teams/intro) and message it directly (@mention it in group chats). <Note> The Neo Support Agent is Neo's own managed assistant. To put one of **your own** agents — your prompt, your tools, your branding — in front of your technicians in Teams, build a [custom internal bot](/integrations/teams/internal-bot) instead (or [copy this one](#copy-it-for-a-head-start) to skip the blank start). That page compares the two side by side. </Note> ## Open it with a message from a link A link of the form `https://dashboard.neoagent.io/support?prompt=<message>` opens a new Neo Support conversation with the message already in the message box. The Neo team uses it to hand you a request to send, and you can put one in your own runbooks. Encode the message for a URL: a space is `%20`, for example. The message is never sent for you. Read it, change it if you want, then press send; a short notice says the message came from a link. If your account can't message the Neo Support Agent, the link opens the Chat page instead. ## Billing Its support tooling (Neo API, web fetch, skill loading, the sandbox shell, approvals) is free to use — asking the Support Agent to explain, debug, or build your Neo setup costs nothing. The tools that read your own tickets and documentation still bill as normal. Chat-agent billing more broadly is still being finalized — see [Sessions & billing](/chat-agents/sessions-and-billing). # Chat Agents Source: https://docs.neoagent.io/chat-agents/overview Conversational agents your technicians and end users talk to directly — the third way to run an agent, alongside triggered and scheduled A chat agent is an [agent](/core/agents) you talk to. Same tools, same integrations, same custom instructions — but instead of firing on a ticket or a schedule, it answers messages in a conversation that remembers context across turns. ## The three ways agents run | | Triggered | Scheduled | Chat | | - | - | - | - | | **Starts when** | A PSA event matches | A schedule fires | A person sends a message | | **Works on** | A ticket or time entry | Custom instructions alone | The conversation | | **Conversation** | Continues across runs on the same ticket | Fresh each run | Continues across the session | | **Approvals** | Teams card or chat | Teams card | Inline card in the chat | | **Use case** | Triage, resolution, communication | Audits, hygiene, reports | Q\&A, ad-hoc ops, end-user support | ## Who's talking to whom Every conversation has two parties, and keeping them straight explains everything else: * **The owner** — the MSP whose agent it is. The owner's configuration runs and the owner is billed. * **The user** — the person typing. Either one of the MSP's own **technicians**, or an **end user** at one of the MSP's client companies. The distinction isn't cosmetic: technician conversations run with your full MSP-level tools, while end-user conversations are locked to the user's own company with a separate, narrower capability set — see [how end-user bots work](/chat-agents/how-end-user-bots-work) for the architecture, and [end-user tools](/agents/tools/end-user/overview) for the capability set itself and the one-time setup it needs. ## The chat surfaces A chat agent can run in the dashboard, in Microsoft Teams or in Slack. In Teams it can face either your own technicians or your clients' employees; in Slack it faces your clients' employees. The same agent you build can be put on more than one surface. <CardGroup> <Card title="Chat in the dashboard" icon="message" href="/chat-agents/using-chat"> Your technicians chat with your agents on the **Chat** page — sessions, history, sharing, feedback, inline approvals. Every agent works here; it's where you build and test. </Card> <Card title="Your custom internal Teams bot" icon="user-gear" href="/integrations/teams/internal-bot"> Put one of **your own** agents in front of **your technicians** in Microsoft Teams — your prompt, your tools, your branding. Runs with your full MSP toolbox, across all your companies. </Card> <Card title="Your branded end-user Teams bot" icon="bot" href="/teams-bot"> Put one of your chat agents in front of **your clients' employees** as a branded Teams bot — your name, your icon. They get instant answers and file tickets right in Teams, scoped to their own company. **The headline use case.** </Card> <Card title="Your branded end-user Slack bot" icon="slack" href="/integrations/slack/end-user-bot"> The same end-user agent for clients who work in Slack: a Slack app with your name and icon, installed in each client's workspace and scoped to that client's company. </Card> <Card title="Neo Support Agent" icon="life-ring" href="/chat-agents/neo-support-agent"> A chat agent managed by Neo, available to every MSP. Answers "how do I configure X in Neo" and searches your docs and tickets. Reachable in the dashboard and through the **Neo AI Agent** Teams app. </Card> </CardGroup> ## Finding an agent's ID Every chat agent has a numeric **ID**. You'll rarely need it day to day, but Neo Support will ask for it when you raise an issue about a specific agent — it identifies the agent unambiguously, where a name might be duplicated or since renamed. It's shown in two places on the **Chat** page, each with a copy button: * In the **ID** column of the agents table, so you can read off any agent's ID without opening it. The column sorts, which helps when you have many agents. * Under the agent's name in the sidebar while you're chatting with it. ## When to use a chat agent Use a chat agent when a **person initiates** and the value is back-and-forth: a technician asking "which mailboxes have forwarding enabled for Contoso Contractors?", or an end user asking for a password reset. Use a [triggered or scheduled agent](/core/workflows-vs-agents) when the work should start from an event or a clock — no one needs to ask. To get started: [build a chat agent](/chat-agents/building-a-chat-agent), validate it [in the dashboard](/chat-agents/using-chat), then [connect it to a channel](/chat-agents/channels) to reach people in Teams or Slack — a [custom internal bot](/integrations/teams/internal-bot) for your technicians, or a branded end-user bot in [Teams](/teams-bot) or [Slack](/integrations/slack/end-user-bot) for your clients' employees. # Sessions & billing Source: https://docs.neoagent.io/chat-agents/sessions-and-billing How chat sessions keep context, how user identity is tracked, and how chat turns consume credits ## Sessions A session is one conversation: one person, one agent, one context. * **Continuity** — the agent remembers earlier turns in the session, including files it produced in its sandbox. New session = clean slate. * **Per channel** — dashboard, Teams and Slack sessions are separate, even for the same person and agent. * **Auto-titled** — sessions name themselves from the first exchange. * **Reset** — archive in the dashboard, type **"start a new chat"** in Teams, or use `/new` in Slack. * **Fresh start after a break** — in Teams, when a long-running conversation comes back after a while, Neo offers a one-tap "Start fresh" card (or just keep typing — that starts fresh too). Long active sessions are also summarized automatically so they stay fast and economical. ### Identity on sessions Every session records who's talking: * **Dashboard** — the signed-in technician. * **Slack (end-user channels)** — the end user, matched by their Slack profile email, and the company the workspace was installed for (see [who the Slack bot serves](/integrations/slack/end-user-bot#who-the-bot-serves)). As in Teams, the company is bound to the session and scopes what the agent can access. * **Teams (end-user channels)** — the end user and their company, recognized from the Microsoft 365 tenant the message arrives from. The company is bound to the session when it's created and can't change afterwards. It scopes [per-company chat instructions](/chat-agents/building-a-chat-agent#per-client-instructions-for-end-user-agents), keeps client conversations attributable, and — most importantly — scopes what the agent can access: end-user sessions never run tools that operate across your whole client base (see [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access)). ## Billing How a chat agent is billed depends on **who it serves**: * **Internal chat agents** — your technicians chatting with Neo in the dashboard or Teams — are metered in **credits**, charged **per tool call** the agent makes, from the same [plan credits](/product/billing-and-credits#how-credits-are-spent). A turn with no billable tool costs nothing. Test-mode turns still bill for the tools they call. The full per-tool list is on [Tool credit costs](/agents/tools/credit-costs). * **The branded end-user bot** — the white-label bot your clients' employees use in Teams or Slack — is **not** metered in credits. It's priced **per client company**, as below. ### End-user Teams bot pricing You pay a flat monthly price **per client company** — and only for the clients where someone actually used the bot. The Slack bot is priced the same way. Two rules, and that's the whole model: 1. **Nobody used it, it's free.** A client where no employee messaged the bot that month costs **\$0**. 2. **Someone used it, you pay that client's flat price** — no matter how many of their people use it, or how much. **Two numbers, two jobs.** Whether anyone *used the bot* decides **if** a client is billed. How many of their people *opened a ticket* decides **how much**. They're different counts, and the second is much the larger of the two: **ticket-openers means everyone who raised a ticket with you that month by any route — email, phone, portal or the bot** — not just the people using the bot. It's what sizes the client, and it's a number you can check yourself in your PSA. It counts **people, not tickets**. Someone who raised fifty tickets last month is one ticket-opener, the same as someone who raised one. And tickets nobody raised — RMM alerts, monitoring, anything your tools opened automatically — don't move the number at all: hundreds of them count as one opener at most, and usually none, because there's no person on them. A noisy monitoring month can't push a client into a higher band. That's deliberate. The band is meant to track how many of a client's staff you support, because that's what decides how much work the bot can take off you — not how much ticket volume your tooling generates. | People who opened a ticket at that client, this month | Price for that client | | - | - | | Up to 24 | **\$9** | | 25–99 | **\$29** | | 100–499 | **\$79** | | 500+ | **\$1.00 per person who used the bot**, min \$199 | **No platform fee, no per-seat pricing, no usage limits.** One client, one line, one price. #### An example You've turned the bot on for four clients. Last month: | Client | Opened a ticket | Used the bot | Price | | - | - | - | - | | Acme Manufacturing | 12 | 5 | \$9 | | Contoso Legal | 60 | 22 | \$29 | | Fabrikam Health | 140 | 31 | \$79 | | Northwind Logistics | 35 | nobody | **\$0** | | | | **Total** | **\$117** | Northwind's 35 people still raised tickets by email and phone — but nobody opened the bot, so it costs nothing. ### Working out your cost Open **[Billing](https://dashboard.neoagent.io/billing) → Estimate cost** and we've done the arithmetic for you. It lists your clients with the number of people who opened a ticket at each last month, already priced. Tick the clients you'd turn the bot on for and the total updates as you go. It opens with every client that raised a ticket, and there's a ticket-opener range above the list — set a floor (say 25 and up) and one click selects every client in it, so you can price "just the bigger ones" without hunting through the list. You get two figures, because one wouldn't tell you enough: * **The ceiling** — what you'd pay if someone at every client you ticked used the bot. The most you can ever be charged. * **What the clients already using it come to** — real, not a projection. Your actual bill sits between the two, and moves toward the ceiling as adoption spreads. You're never paying ahead of it. If you'd rather check by hand, the ceiling is just the price band for each client added up, and the ticket-opener counts are in your PSA. The one client you can't price from your PSA alone is a 500+ one, because its price follows how many of its people actually use the bot rather than a fixed band — for that one, £159 / \$199 / €179 is the floor and the Estimate cost page shows the rest as adoption builds. ### Seeing what you were charged for The **[Billing page](https://dashboard.neoagent.io/billing)** shows this month's projected charge with a **Show breakdown** link underneath. That opens the per-client lines behind the number: each client, how many of their people opened a ticket, how many used the bot, which band that put them in, and what they cost. Clients where nobody opened the bot don't appear — they aren't billed, so there's nothing to explain. ### Free trial The end-user Teams bot starts with a **14-day free trial — no credit card required**. The trial begins automatically the first time you install the white-label bot for a client, in Teams or Slack. During the trial the bot is fully live for your end users, and you can watch your projected cost build client by client on your [Billing page](https://dashboard.neoagent.io/billing). **When the trial ends:** * **If you already have a payment method on file** (for example, from your Neo plan) you move to the paid add-on **automatically** — no interruption. * **If Pax8 bills you**, you move to the paid add-on automatically too — Pax8 partners need no card. * **If you have not chosen a Neo plan yet**, nothing happens. The bot keeps working and you are not charged, because the add-on is sold on top of a plan. It moves to paid on the day you choose one. * **If you don't have a card on file**, the bot **pauses** for your end users until you click **Subscribe** on the [Billing page](https://dashboard.neoagent.io/billing), add a card when it asks, and click **Subscribe** again. They see *"This assistant isn't active for your organization right now. Please contact your IT provider to re-enable it."* Your Neo account and plan credits are unaffected — only the end-user bot is gated. We email you before the trial ends, so the move to paid is never a surprise. ### How you're billed * **In arrears, monthly.** Once the month closes we work out which clients used the bot, price each one, and add a single line to your invoice. The current-month figure on the Billing page is a live **projection**. * **Per calendar month.** Both numbers — who opened a ticket, and who used the bot — are counted within the month being billed. Nothing carries over. * **Separate from credits — but the work it hands off isn't.** The bot's own price never draws from your plan credits. When it files a ticket, your usual triage, dispatch and resolution automations run on that ticket and spend credits exactly as they would for a ticket raised by email. You pay for the front door once, and for the work behind it as normal. * **Your currency.** You're billed in your account's currency at published local prices — nothing is converted, so an exchange-rate move can never change your bill. In GBP the bands are **£7 / £23 / £63** (500+ £0.80 per person who used the bot, min £159); in EUR **€8 / €26 / €71** (500+ €0.90 per person who used the bot, min €179). ### Turning the bot off You can turn the end-user bot off anytime from the **[Billing page](https://dashboard.neoagent.io/billing)** — during the trial or after you've converted to paid. * **During the trial** — it stops immediately and you're never charged. * **After you've converted** — the bot stops for your end users right away; your next invoice covers the clients that used it up to that point, and nothing is billed afterwards. You can turn it back on anytime from the same place. # Chat in the dashboard Source: https://docs.neoagent.io/chat-agents/using-chat The technician chat experience — sessions, history, sharing, feedback, and inline approvals on the Chat page Open [**Chat**](https://dashboard.neoagent.io/chat) in the dashboard sidebar. You'll see two tabs: **Agents** (pick an agent to chat with) and **Channels** (connect agents to [external channels](/chat-agents/channels)). Admins also see a third tab, [**History**](#history-owners) — the workspace's conversation record, readable by owners. The [Neo Support Agent](/chat-agents/neo-support-agent) is listed first with a **Managed by Neo** badge; your own chat agents follow. Click an agent to open its chat view. Each row also carries the agent's [ID](/chat-agents/overview#finding-an-agents-id) — the value Neo Support asks for when you raise an issue about a specific agent. <Frame> <img alt="Agents tab on the Chat page — the Neo Support Agent and a custom chat agent, each row showing its ID, audience, access, channels, state and last-updated date" /> </Frame> <Info> The Neo Support Agent is listed for everyone its [Chat Agent Access](/product/rbac#chat-agent-access) mode admits — everyone on your team, by default — and those people also get the **Need help?** button in the bottom-right corner of any page. Restricting that mode removes both for the people it excludes. Which company data the agent uses is a separate per-person setting: [AI chat data access](/product/rbac#ai-chat-data-access). </Info> ## Sessions Each conversation is a **session** — scoped to you and the agent you picked. * **New conversations** start from the session sidebar. Each session keeps its own context; the agent remembers earlier turns within it. * **Auto-naming** — sessions title themselves from the first exchange, so the sidebar stays scannable. * **Archiving** removes a session from your sidebar. In Teams, **"start a new chat"** does the same and starts fresh; in Slack, `/new` does. * **Sharing** — share a session with teammates; they get a read-only view of the conversation. * **Long conversations** open on your most recent messages. **Load earlier messages**, at the top of the conversation, brings in older ones a page at a time. <Frame> <img alt="A chat session with the Neo Support Agent — auto-named sessions in the sidebar, tool calls and the reply in the conversation" /> </Frame> <Tip> Start a new session when you change topic. Long mixed-topic sessions dilute the context the agent works from. </Tip> <Note> If the agent replies that a request pulled in more than it can work with at once, ask again more narrowly — a shorter date range, fewer records, or only the fields you need. This is usually one oversized question (for example, "go through every ticket this year"), not a conversation that ran too long, so you can carry on in the same session. </Note> ## Attaching files Click the paperclip in the composer, or paste a screenshot, to attach up to 6 files to a message. You can attach images (PNG, JPEG, GIF, WebP) and documents: CSV, Excel (`.xlsx` and `.xls`), PDF, Word (`.docx` and `.doc`) and plain text. Hover the paperclip to see the list. Teams chat takes the same files. * **Images** — the agent sees them directly, so it can read an error on a screenshot. * **Documents** — your own chat agents and the Neo Support Agent copy a file into their [sandbox](/agents/tools/built-in/sandbox#files-users-attach-in-chat), where they run code, when they need to read it, and work on it there. A spreadsheet is read row by row with code, and a PDF or Word document as text, so a request like "look up each Autotask ticket in this sheet and summarise it" works on every row, not a sample. In a workbook with several worksheets the agent reads the first one, so put the rows you need there or save that sheet as CSV. * **On a ticket** — the agent can also put any file you shared on a PSA ticket with [Attach File to Ticket](/agents/tools/management/attach-file-to-ticket). You can refer back to a file several messages later. The agent keeps the files from your last 20 messages that had attachments, for up to 90 days; if it cannot find an older file, attach it again. Two kinds of file can't be read. The agent can't open an old Word `.doc`, and will ask you to save it as `.docx`. A scanned PDF has no text inside it, so send screenshots of the pages you need instead. Both can still go on a ticket. <Note> End-user Chat Agents don't read document contents. They can only put a shared file on the end user's ticket, where your technicians open it. </Note> ## Scripts that run after the reply An RMM or on-prem PowerShell script the agent starts runs on the device, and can still be running when the reply ends. The chat does not post the result by itself when the script finishes. For a short script, the agent waits and checks within the same reply. Otherwise it tells you the script is still running, and reads the result the next time you message it, for example "is it done?". ## Stopping the agent While the agent is working, the composer's send button becomes a **Stop** button. Stop tells the agent to stop — it will not start another action, and the run ends. The reply keeps whatever it had already written. A stop takes effect at the agent's next step, so if it's in the middle of a long-running action (a script, a large lookup), it stops once that action returns. Teams' own stop control on a streamed reply does the same thing. <Warning> Stop prevents actions the agent **hasn't taken yet**. Anything it already did — a ticket updated, a config saved — stays done; undo those the usual way. </Warning> If your browser loses the connection to a running conversation — you close the tab, the network drops, or you stop it — the conversation tells you the agent is **still working** and offers **Reconnect** (re-attach to the live reply) and **Stop**. Take that notice seriously: until the turn ends, sending a follow-up won't reach the work already in flight. If you want to correct the agent, stop it first, then send the correction. ## Approvals happen in the chat When a chat agent needs [Technician-in-the-Loop](/core/technician-in-the-loop) approval for a sensitive action, the approval card appears **inline in the conversation** — you approve or reject right where you asked. Chat agents always use the in-chat approval channel; Teams card delivery doesn't apply because you're already in the conversation. ## Your own records are never withheld from you A Chat Agent reads your systems with your MSP's integration credentials, not with the account of the person chatting, and it reaches only the systems and [tools](/agents/tools/overview) you enabled on it. So what it retrieves is your own data, read under access your organisation granted it — a technician can get a record through an authorised agent even when their personal PSA or Microsoft 365 account could not open it. It reports those values as the source system holds them — assigned resource and technician names, contact names and email addresses, ticket titles, device and account names — without redacting, anonymising or relabelling them. There is no privacy setting in Neo that hides your organisation's own records from you, and an agent should never tell you there is. If one of those record values comes back as a placeholder such as `Assigned — redacted` or `[Name redacted]`, or the agent claims a data-protection rule stops it from naming a person or a record, that is a bug: raise it with the [Neo Support Agent](/chat-agents/neo-support-agent) and link the conversation. Three things are genuinely restricted, and each has its own scope. Not printing a secret applies to every Chat Agent and every audience: an agent never puts a secret value — a password, an API key, a token — into a reply; it replaces the value and tells you it did. Handing the value over safely is an internal Chat Agent capability. It needs the [Generate Secure Link](/agents/tools/management/generate-secure-link) tool enabled on the agent, which puts the secret behind a link that expires and allows only a limited number of views. The link is not spent after the first open — treat it as live until it expires, so pass it only to the person who needs the secret. Anyone who reaches the link can read the value, so keep it out of a shared mailbox, a group chat, or a document your whole team reads. Recording the link itself is fine where the plaintext value would not be, so an agent that generates a credential — a password reset, a new mailbox, a rotated client secret — writes the link wherever that run has to deliver it: an internal ticket note, its own run summary, or the client-facing update the request calls for. The link is the delivery channel by design; only the plaintext value is kept out. Neo never does this on its own: no agent scans your tickets for credentials your technicians wrote, and none rewrites a note or a time entry to move one. They stay where your team left them unless one of your technicians asks an agent to change them. That tool is internal-only, so an end-user Chat Agent has no way to deliver a secret at all: it replaces the value and stops there. Internal notes are the second. Every Chat Agent carries a standing instruction not to reproduce an internal note in a reply, so a request to quote one back can come back declined even though the note is your own. That restriction covers the note text itself and nothing else: the ticket's own fields — title, assigned resource, contact, status — still come back verbatim, and a refusal that reaches those fields is the bug described above. To read an internal note itself, open the ticket in your PSA. The third restriction applies to one kind of agent. An [end-user Chat Agent](/chat-agents/how-end-user-bots-work) — the agent your client's employees talk to — is declared as a separate trust domain with a much narrower toolset, so it does not see your internal records at all. What sets this is the agent's own declared audience, so an internal agent stays on the full internal toolset for everyone who chats with it. ## Feedback Every agent reply has thumbs-up / thumbs-down; feedback is collected per message and reviewed to improve agent behavior. ## History (owners) The **History** tab shows every conversation in your workspace — dashboard, Teams and Slack, across all users — so you can read how an agent actually behaves without being the one chatting with it. Typical uses: checking why a change to an agent broke its replies, finding the conversations that consume the most credits, and reviewing what your clients' employees ask an [end-user bot](/chat-agents/how-end-user-bots-work). * **Two lenses.** **Internal** lists conversations your technicians had with internal agents; **End-user** lists conversations your clients' employees had with your white-label bot, with a company filter. The End-user lens only appears when you run an end-user agent. * **Filters and sorting.** Narrow by agent, user (or client company), channel, and time window, or search titles. Sort by last activity, most credits, or most turns — "most credits" is the fastest way to find expensive conversations. * **Cost per conversation.** Each conversation in the list shows its credits and what they cost you, for example **42 cr ≈ \$4.91**, at your [price per credit](/product/billing-and-credits#what-your-credits-cost). The transcript header gives the total for the whole conversation. * **When each message happened.** Every message in the transcript shows its date and time to the second. Most replies also show how long the agent took to answer, for example **44s**; conversations from before June 2026 do not record it. The **Local** button in the transcript header switches every time in the conversation to UTC and back. * **Per-turn cost detail.** Under each reply, the transcript shows what that turn cost and which tools it called (for example, `AUTOTASK_PSA_REQUEST ×28`). A turn that consumed a large share of the conversation's credits is highlighted, so the expensive step is visible at a glance. These are the same numbers that power [sessions & billing](/chat-agents/sessions-and-billing). * **Drill into any reply.** Each reply expands: **Reasoning** shows why the agent chose what it did, and every tool call opens to the exact request it sent and the response it got back — so you can see what each of those PSA calls actually was, not just the count. * **Feedback in place.** Conversations where someone rated a reply down are marked in the list, and the rating (with any comment) shows under the reply itself. * **A clean view to share.** The **Hide details** button in the transcript header hides the reasoning, tool calls, credits and ratings, so you can screenshot the conversation for a client. The messages and their times stay. **Show details** brings everything back; each transcript opens with details shown. History is read-only and limited to **workspace owners** — reading everyone's conversations is deliberately narrower than admin access. Your first user started as the owner; owners grant (and remove) ownership under [Roles & Access](/product/rbac). Other admins see the tab with a note about who to ask. Deep-link to one agent's history with `/chat?tab=history&agent=<id>`. What the agent can do is its configuration — enabled [tools](/agents/tools/overview), integration permissions, custom instructions. If it refuses something or lacks access, see [Building a chat agent](/chat-agents/building-a-chat-agent). # Actions Source: https://docs.neoagent.io/core/actions How workflow actions work — Smart Actions (AI), Write-to-PSA, and Notify categories, plus safe sequencing tips for first deployments. ## What actions are Actions are the steps your workflows execute. They analyze data, update your PSA, notify people, and coordinate follow-ups. Each action is purpose-built for MSP workflows and designed to be reliable, auditable, and fast. <Frame> <img alt="High-level diagram of how actions execute within a workflow" /> </Frame> ## Types of actions * **Smart actions**: AI-powered steps that summarize, extract, classify, or draft responses. * **Write to PSA actions**: Safely change fields, add notes, create or merge tickets, and update time entries. * **Notify users actions**: Send clear updates to end users or internal teams via email or chat. <Tip> Start with read-only or comment-first actions in early tests. Move field-changing steps later in the sequence once results are consistent. </Tip> # Agents Source: https://docs.neoagent.io/core/agents Neo Agents are AI-powered workers that can analyze tickets, communicate with users, and take action on your behalf Neo Agents are the intelligent workers behind your workflows. Unlike simple automation rules, agents understand context, make decisions, and can handle complex multi-step tasks just like a human technician would. <Tip> Wondering whether to build an agent or a [workflow](/core/workflows) for your use case? See [Workflows vs Agents](/core/workflows-vs-agents) — start with workflows for triage, dispatch, resolution, escalation, and merge; reach for agents for everything else. </Tip> <CardGroup> <Card title="Tools" icon="wrench" href="/agents/tools/overview"> Discover the tools agents can use to accomplish tasks </Card> <Card title="Skills" icon="book-open" href="/agents/skills/overview"> Best practices and guidance agents load on-demand </Card> </CardGroup> ## Building Your First Agent Watch this 5-min walkthrough of building agents in Neo Agent: <iframe title="Building Agents Demo" /> ## What Agents Can Do Agents combine AI understanding with real-world actions. When a ticket comes in, an agent can: * **Analyze** the problem using past tickets, documentation, and web knowledge * **Communicate** with end users to gather information or provide updates * **Take Action** in your PSA, RMM, or Microsoft 365 environment * **Request Approval** from technicians before sensitive operations Agents can also run **on a schedule without a ticket** — performing proactive tasks like M365 compliance audits, inactive account cleanup, and recurring admin operations. <CardGroup> <Card title="Scheduled Agents" icon="clock" href="/core/scheduled-agents"> Run agents on a recurring schedule for proactive tasks that don't start from a ticket </Card> <Card title="Chat Agents" icon="message" href="/chat-agents/overview"> Agents your technicians and end users talk to directly — in the dashboard or via Teams </Card> </CardGroup> ## How Agents Work <Steps> <Step title="Receive Context"> When a workflow triggers, the agent receives the ticket details, company information, and any custom instructions and [memory](/core/memory) you've configured. For [scheduled agents](/core/scheduled-agents), the agent runs from your custom instructions and enabled tools alone — no ticket needed. </Step> <Step title="Analyze & Plan"> The agent analyzes the situation, searches for relevant information, and determines the best course of action based on your instructions. </Step> <Step title="Use Tools"> The agent selects and uses the appropriate tools to accomplish the task—whether that's searching documentation, updating a ticket, or communicating with a user. </Step> <Step title="Report Results"> After completing its work, the agent provides a detailed log of actions taken, along with any relevant outputs or recommendations. </Step> </Steps> ## Agent Tools Tools are the capabilities you enable for your agents. Each tool allows the agent to perform specific actions: | Category | What It Does | | - | - | | **PSA** | Read and write your PSA — tickets, notes, time entries, contacts, configurations | | **RMM** | Read device and monitoring data, and run scripts on target devices to fix problems | | **Microsoft 365** | Manage Entra ID, Active Directory, Exchange, and Intune — users, groups, licenses, mailboxes | | **Communication** | Send messages to end users and internal teams — ticket notes, email, Teams, SMS | | **Search** | Find documentation, similar tickets, configurations, and web resources | | **Documentation** | Read and write IT Glue and Hudu resources — documents, configurations, assets, passwords | | **Management** | Log time, generate passwords and secure links, trigger workflows, call external APIs and Neo's own API | | **Built-in & Internal** | Tools the agent always has or gets automatically — search helpers, the sandbox, plumbing | | **Approvals** | Request human approval before sensitive actions | <Info> Tools are configured per-workflow. You choose which tools an agent can use and customize their settings to match your processes. </Info> ## Agent Skills Skills provide specialized guidance that agents load on-demand. Unlike tools (which perform actions), skills teach the agent **how** to approach a type of task. | Skill | What It Provides | | - | - | | **Resolve Issue** | Structured diagnosis methodology, root cause analysis, and resolution planning | | **End User Communication** | Message templates, tone guidelines, and safety rules for end user messaging | Skills are always available and loaded automatically when relevant. Custom instructions take priority over skill guidance when there's a conflict. You can also create **your own skills** for the repeatable procedures your agents run again and again — a weekly report, a monthly reconciliation — so every run comes out the same reliable way. See [custom skills](/agents/skills/custom-skills). <Card title="Learn more about Skills" icon="book-open" href="/agents/skills/overview"> See all available skills, including how to build your own </Card> ## Credit Tiers Tools sit in four tiers: **Free** (0), **Basic** (1), **Standard** (2), **Advanced** (3). What you pay depends on how the agent starts. The same toolbox is cheap on a ticket-triggered agent and can be expensive on a [scheduled](/core/scheduled-agents) or [chat](/chat-agents/sessions-and-billing) agent. | How the agent runs | What you pay | | - | - | | **Ticket- or entity-triggered** | Highest tier among the tools *you chose*, once per run. Always-on tools (searches, sandbox) do not set this price. The agent can call enabled tools as many times as it needs. | | **Scheduled, with no ticket** | Each tool call, at its [per-call price](/agents/tools/credit-costs). Test-mode runs bill the same way. | | **Internal chat** | Each tool call, same prices. A turn with no billable tool costs nothing. | [External API Request](/agents/tools/management/external-api-request) is Advanced (3 credits per call on scheduled and chat). The **Neo API** tool is Free. The API *skills* under Built-in Capabilities are also Free to load — they are not the API tools. The full list is on [Tool credit costs](/agents/tools/credit-costs). To get an email on a day an agent uses far more credits than usual, switch on **Daily Credit Alert** on the agent's **Overview** tab. [A daily credit alert for one agent](/product/billing-and-credits#a-daily-credit-alert-for-one-agent) explains how Neo sets its cap. ## Testing an agent before you trust it ### From a new agent to a trusted one Neo asks for your approval before each change the agent makes. [What supervision does not cover](/core/supervised-mode#what-supervision-does-not-cover) lists the exceptions. 1. **Run it in Supervised mode on a real ticket.** In [Executions](/product/executions), choose **Run now** and turn on **Supervised run**. The dashboard offers this step as soon as you create an agent. 2. **Approve, reject or comment on each card as it works**, in Teams or on the **Approvals** page. 3. **When the ticket is done, click Train on the run in Executions**, say what should change, and send. 4. **Neo Support reviews the run and your decisions and updates the agent** when you confirm the edit it proposes. Repeat on a few tickets. When the runs need no corrections, enable the agent. [Supervised mode](/core/supervised-mode) has what each card shows and what an approval covers. ### Two questions while you write instructions Two different questions, and they need different tools. **"Does the agent do the right thing with this ticket?"** Open the agent in Executions and use **Run now**. It executes the agent immediately against that ticket, skipping the trigger, so you can change the instructions and run again without waiting for an event. This is the fast loop while you are writing instructions. To watch it work before you trust it, turn on **Supervised run** there and approve each change yourself: see [supervise a single run](/core/supervised-mode#supervise-one-run-or-every-run). **"Does my agent fire when a customer replies?"** Run needs a real event, so you have to produce one. Set up a **test company with a test contact**, raise a ticket for that contact on a board the agent watches, and reply from the contact's mailbox. <Warning> **Reply from an address your PSA holds as a contact, not as a technician account.** ConnectWise attributes an inbound email to the ConnectWise **member** whenever the sending address also belongs to one, and a member's note is a technician note — not a customer reply. So a **Customer replied** agent does not fire for it, by design. This catches people testing from their own work mailbox, which is usually a member. Your real customers are contacts, so the agent behaves correctly for them; only the test is wrong. Use a mailbox that is not a technician account in your PSA — a test contact on a test company is the simplest setup. Neo records which of these happened. On [Executions](/product/executions), the event's match reason reads `no customer note is present`, and where Neo can tell which note the reply was it adds `:` and the cause. Most causes name something in ConnectWise — the member it attributed the note to, or a sender it does not hold as a contact — and those are settings on your side rather than faults. One names Neo's own reply on the ticket, which flips the same flag ConnectWise uses for a customer reply; an agent does not answer its own note, and there is nothing for you to change. When two notes on the ticket could have been that reply, or the nearest is too far off to be sure, Neo names none rather than guess, so a reason with no cause after it is not an error. If you believe a genuine customer reply is being missed, send us the reason text and the ticket. </Warning> Keep **test mode** on for the first runs either way, so the agent reads without writing. ## Best Practices <AccordionGroup> <Accordion title="Start with test mode on"> When test mode is on, no action changes your systems: updating tickets, creating time entries, client-facing notes, internal notes and the like are simulated. It still reads, and it still works through the whole job: each write it would make is simulated, and it goes on to the next step as it would on a live run. The writes it would have made appear in the run's output when the run ends, next to the agent's run summary — see **Report test results via** for where else Neo posts that report. Monitor agent decisions closely when first deployed to ensure quality. When test mode looks right, a [supervised run](/core/supervised-mode) lets the agent make real changes, each after a technician approves it, and **Train** on that run updates the agent from your decisions. See [From a new agent to a trusted one](#from-a-new-agent-to-a-trusted-one). </Accordion> <Accordion title="Use technician-in-the-loop"> For sensitive operations, start with Technician-in-the-Loop enabled. This gives you oversight while still benefiting from AI-powered analysis. </Accordion> <Accordion title="Write clear custom instructions"> The better your instructions, the better the agent performs. Be specific about your processes, preferences, and edge cases. Iterate based on feedback to refine the agent's behavior. See [Writing effective agent instructions](/core/writing-agent-instructions) for the full guide. </Accordion> </AccordionGroup> # Backfills Source: https://docs.neoagent.io/core/backfills Apply a workflow to past tickets it didn't run on — paced overnight, resumable, with concurrency caps. A **backfill** runs an existing workflow against historical tickets that the workflow's normal trigger would never re-fire for. The same workflow logic, the same tools, the same approvals — just applied to entities that already exist in your PSA instead of waiting for new ones. <Tip> A workflow is the *what* (triage a ticket, dispatch it, update a time entry). A backfill is the *when* and *how-much* — it takes that workflow and applies it to a set of past tickets you choose, paced over execution windows so it doesn't flood your environment. </Tip> ## When to use a backfill * **You just built a new workflow** and want it to handle the last 30 days of open tickets, not only newly-created ones. * **You edited a workflow's logic, prompts, or tools** and want the corrected version to re-process recent tickets that ran under the old version. * **You want to test a workflow on a small sample of historical tickets** before enabling it for live trigger events. * **You changed assignment or dispatch rules** and want to apply them across an open queue. A backfill **doesn't modify** the target workflow — it just reuses it. Each past ticket that matches the backfill's filter gets dispatched into the workflow exactly as it would have if a fresh trigger had arrived. ## Setting one up From the dashboard, go to **Backfills → New backfill**. The wizard has four steps: <Steps> <Step title="Pick the target workflow"> Choose the workflow you want to apply to historical tickets. The workflow must be enabled. A backfill runs its tickets through the target workflow, so a disabled workflow would process nothing. The picker only lists enabled workflows, and the API refuses a backfill against a disabled or deleted one. If you've just built a workflow, enable it before you backfill it. </Step> <Step title="Choose a filter"> Two options: * **Reuse workflow filters** — the backfill processes the same tickets the workflow normally matches, optionally narrowed with extra rules (e.g. "the workflow's normal filter PLUS createDate > 2026-04-01"). Best when you want history that matches what's running live today. * **Custom filters** — the backfill defines its own ticket scope, ignoring the workflow's own filter. Best when you want to one-off process a set of tickets that the workflow wouldn't normally match (e.g. an old queue that's been migrated). See [Filter tickets](/core/filter-tickets) for the rule-builder reference. </Step> <Step title="Configure the execution window"> Pick the days of the week and start/end times when the backfill is allowed to dispatch. Times are interpreted in the timezone you select (defaults to your browser's timezone). The classic pattern is **weeknights 22:00 → 06:00 in your local timezone**: the PSA is quiet, the backfill stays out of business-hours traffic, and you wake up to a fresh batch of processed tickets. </Step> <Step title="Review and create"> The review step previews how many tickets currently match your filter and the upper-bound credit cost so you know what you're committing to before you click **Create backfill**. </Step> </Steps> ## Execution windows Windows tell the backfill *when* it's allowed to dispatch. Outside the window, it stays paused-but-alive — no new tickets get picked up, and the detail page shows a "Waiting for window" badge with the next opening time. A window can span midnight (`22:00 → 06:00` means from 22:00 on the configured day through 06:00 the next morning), and you can configure different windows per day — or leave a day empty to skip it entirely. The backfill resumes automatically at the next opening; no need to babysit it across nights. ## Filters The filter builder is the same one used to configure workflow conditions, so anything you can express on a workflow's filter — queue, status, priority, custom fields, contact attributes — works here too. When you pick **Reuse workflow filters**, the wizard takes a snapshot of the workflow's current filter rules at the moment you create the backfill. Editing the workflow's filter later doesn't change what an in-flight backfill is processing. In **Custom filters** mode, the workflow's own filter is intentionally bypassed at dispatch time — the backfill is the authority on which tickets run. This is what makes it possible to "re-run a workflow on tickets it wouldn't normally match." ## States | State | Meaning | | - | - | | **Running** | Actively dispatching during the execution window, waiting between windows. | | **Paused** | You paused it. No new dispatches until you resume. | | **Completed** | Every matching ticket has finished. | | **Cancelled** | You cancelled it. Tickets already mid-run will still finish on their own. | | **Failed** | Something went wrong that we couldn't recover from. The backfill says what, and disabling the target workflow mid-backfill is the common cause. | When a backfill is **Running** but currently outside the configured window, the detail page shows a **"Waiting for window"** sub-status with the next opening time. This is helpful when a backfill is created at 10 AM for a 22:00 window — nothing is broken; it's just waiting until tonight. ## Progress counters Each backfill row shows four numbers: * **Started** — tickets the backfill has dispatched into the workflow so far. * **Succeeded** — tickets whose workflow run finished successfully. * **Failed** — tickets whose workflow run finished with an error. * **In flight** — tickets currently mid-run. Succeeded and failed counts may briefly lag the started count by a second or two while the latest dispatches are still wrapping up. ## Pause, resume, cancel | Action | Effect | | - | - | | **Pause** | Stops new dispatches at the next moment the backfill checks in. Tickets already mid-run still finish. | | **Resume** | Picks up where it left off and continues dispatching the rest of the matching tickets. | | **Cancel** | Terminal. Stops the backfill permanently. Tickets already mid-run still finish on their own. | Pause and resume are reversible — use them freely to throttle a backfill that's making more noise than expected, or to pause overnight if you want to review the morning's results before letting it continue. Cancel is permanent; if you change your mind, create a new backfill with the same filter to pick up the unprocessed tickets. After clicking Pause, Resume, or Cancel, the button shows a spinner for up to \~30 seconds while the backfill picks up the signal. The status badge updates as soon as the change takes effect. If a backfill shows Running but has already stopped, Cancel still works: it settles the backfill straight away, so it stops blocking a new backfill for that workflow. ## Cost Each ticket the backfill processes is billed at the target workflow's normal credit cost — a backfill of 1,000 tickets through a triage agent at 2 credits per run costs 2,000 credits. Backfills don't add a markup; they're just a pacing mechanism for the workflow's existing per-run cost. The wizard's review step shows the upper-bound cost (`number of matching tickets × credits per run`) before you commit, so the ceiling is explicit at create time. ## Concurrency Backfills cap how many tickets are mid-run at once (default 5). This protects your PSA from rate-limit issues and keeps the backfill out of the way of live traffic. <Tip> The cap counts **all** running executions of the target workflow, not just backfill-driven ones. If three tickets are already running because of live triggers, your backfill (capped at 5) only takes two slots until those finish. This is intentional — the cap protects your PSA, not just the backfill. </Tip> ## Troubleshooting <AccordionGroup> <Accordion title="The status is Running but no tickets are being processed"> The backfill is alive but currently outside its execution window. Check the **"Waiting for window"** badge on the detail page — it tells you the next opening time. If you created the backfill at 10 AM for a 22:00 window, this is expected; it'll start dispatching at 22:00. </Accordion> <Accordion title="A second backfill for the same workflow won't create"> Only one active backfill (Running or Paused) is allowed per workflow at a time. Cancel or finish the existing one first, then create the new one. </Accordion> <Accordion title="Started count is climbing but succeeded / failed stays at zero"> Succeeded and failed counts are updated as each ticket's workflow run actually finishes — there's a short delay between "dispatched" and "finished." If they stay at zero for more than a minute or so, the workflow itself may be stuck on a ticket; open one of the ticket's execution history to see what it's doing. </Accordion> <Accordion title="My backfill isn't getting all of its concurrency slots"> The concurrency cap counts every running execution of the target workflow — including ones triggered by live PSA events, not just by the backfill. If live trigger traffic is consuming slots, the backfill shares the pool. This is by design to protect your PSA. </Accordion> <Accordion title="It's been running for days and hasn't finished"> Backfills run only inside their execution window. A weeknight 22:00 → 06:00 window over 1,000 tickets at 5 concurrent will take several nights. If progress looks stuck *during* the window, check the detail page's progress card and the workflow's executions — usually a tool or approval is waiting, not the backfill itself. </Accordion> </AccordionGroup> ## Limits * **Concurrency**: 1–10 tickets in flight per backfill. * **Filter safety check**: the wizard's review step warns when a filter matches more than 5,000 tickets and blocks creation when it matches 50,000 or more. A single backfill processes at most 50,000 tickets — when the check reports "at least 50,000", the real match count is larger, so split the work into multiple backfills (for example by date range). * **Maximum lifetime**: 7 days. A backfill that hasn't finished in 7 days usually means the filter is too wide for the configured window — narrow the filter or widen the window. * **One active per workflow**: at most one Running or Paused backfill per workflow in your account. Completed and cancelled backfills don't count. # Configuration reference Source: https://docs.neoagent.io/core/configuration-reference Every workflow, agent, and trigger setting in one place — what each field does, where it lives, default values, and common gotchas (custom-field filters, business hours, delays, test mode, TIL channel, sub-entity dedup, credits). A single index of the settings most often asked about in support. Each entry lists the **field name**, **where it lives** in the workflow/agent JSON, the **default**, and a one-line description. If a question starts with *"how do I…"* or *"what does X do?"*, the answer probably starts here. ## Triggering | Field | Where | Default | What it does | | - | - | - | - | | `trigger_type` | workflow | required | `SCHEDULED` (runs on a clock), `TRIGGERED` (runs when a PSA event matches), or `NONE` ([chat agent](/chat-agents/overview) — user-initiated). **Fixed at creation** — see below. | | `entity_type` | workflow | `ticket` | What this workflow processes: `ticket`, `project_ticket`, `task`, `scheduled_entry`, `time_entry`. Shown in the builder as **"What to process"**. **Fixed at creation** — see below. | | `callback_settings.target_changes` | workflow (TRIGGERED only) | required | List of PSA events that fire this workflow. Each entry is a `change_type` (e.g. ticket created, ticket updated) plus, for a field-change trigger, a `target_field` and optional `target_value`/`source_value`. `target_field` is limited to a fixed set of standard fields — status, priority, board/queue, ticket type. A custom field / UDF cannot be a `target_field`; to act on one, trigger on ticket created/updated and filter on it with a custom-field condition. | | `callback_settings.run_only_once_per_entity` | workflow (TRIGGERED only) | `false` | If `true`, the workflow runs on each ticket at most once, ever. Used when you want a workflow to fire on creation but never again. It applies no matter what starts the run — a PSA event, another workflow's **Trigger Another Workflow** action, or an agent's **Trigger Workflow** tool. The exceptions are: a [backfill](/core/backfills), whose whole purpose is re-processing tickets you already handled; an agent's **Trigger Workflow** call that waits for completion, which starts the run directly and skips the run-once check; and an event that explicitly sets the bypass flag. Enabling **Bypass filter ticket conditions** on the trigger action does *not* switch this off — that setting only skips the target's ticket filters. | | `process_sub_entities_only_once` | workflow | `false` | For sub-entities (time entries, notes, scheduled entries on a ticket): if `true`, Neo processes each sub-entity at most once. Without it, the same time entry can be re-processed every time its parent ticket changes. | | `process_entities_sequentially` | workflow | `false` | If `true`, the workflow processes matched tickets one-by-one instead of in parallel. Slower but predictable when later steps depend on earlier ones. Incompatible with `REQUEST_TECHNICIAN_APPROVAL`. | | `execution_order` | workflow | required | Integer position in the per-client ordering. Lower runs first when multiple workflows match the same event. Set by dragging the workflow on the Workflows page, or with **Reorder**. | | `ignore_execution_order` | workflow | `true` | Inverse of the **Obey Order** toggle on the Workflows page — `ignore_execution_order: false` means Obey Order is **on**. While `true` (the default) the workflow ignores its position and runs in parallel with other matching workflows, so `execution_order` has no effect. Setting it to `false` also **defers the ticket filter check** until the earlier workflows finish, which is what lets a workflow filter on a field an earlier workflow fills in. See [Dependencies](/building-automations/managing-workflows/dependencies). | **`entity_type` and `trigger_type` can't be changed after creation.** Both controls are disabled in the builder once the workflow or agent exists, and an API update that sends a different value is rejected with a `400` naming the field. To process a different entity — or to switch between scheduled and triggered — **create a new agent** with the setting you want; the filters, conditions, and downstream actions are all shaped by these two fields, so there is no in-place conversion. <Note> Before 2026-07-31, the "What to process" dropdown in the **agent** builder looked editable on an existing agent (the workflow builder always locked it). Changing it appeared to save but reverted on reload, and a later unrelated save could silently switch the agent back to processing tickets. If a customer reports an agent that "keeps resetting to Ticket", that was this bug — it is fixed, and the three affected agents were corrected. </Note> ## Scheduling (SCHEDULED workflows) `schedule` object on the workflow. | Field | Default | What it does | | - | - | - | | `schedule.time_period` | `null` | Recurrence interval, e.g. `{ "interval": 1, "unit": "HOUR" }` for hourly, `{ "interval": 1, "unit": "DAY" }` for daily. | | `schedule.start_datetimes` | `[]` | Specific clock times when the workflow runs (e.g. `08:00` and `15:00` for twice-daily). | | `schedule.daily_execution_windows` | `null` | Per-weekday allowed run windows. Use this when a workflow should only run during business hours (e.g. Mon-Fri 08:30-17:30). Preferred over the deprecated `allowed_execution_hours` + `should_skip_weekends`. | | `schedule.timezone` | `UTC` | IANA timezone for the schedule (e.g. `America/New_York`, `Europe/London`). All other schedule times are interpreted in this timezone. | | `schedule.allowed_execution_hours` | `null` | Deprecated — replaced by `daily_execution_windows`. Single start/end window applied every day. | | `schedule.should_skip_weekends` | `false` | Deprecated — set `daily_execution_windows` with weekday entries only instead. | **Common gotcha — business-hours triggering:** `TRIGGERED` workflows have their own execution windows on the trigger settings — **Only run during these hours** plus a weekday selection. A trigger event that fires outside the window does not run the workflow, so use this control to keep a triggered workflow inside business hours. For a restriction the window can't express, you can also gate on the ticket's `received_at` with a deterministic business-hours filter. ## Filters The trigger filter lives on the first action, `FIND_ENTITIES`, at `input_as_dict.ticket_conditions.conditions` and `input_as_dict.time_entry_conditions.conditions`. An `entity_type=ticket` agent uses the ticket conditions alone. An `entity_type=time_entry` agent uses both: the ticket conditions select the tickets to search, and the time-entry conditions select the time entries on those tickets. `conditions` is a **rule tree**: a group with a `combinator` and a list of `rules`, where each rule is either a leaf (a single condition) or a nested group. | Field | Where | What it does | | - | - | - | | `combinator` | on each group | `and` or `or` — how that group's `rules` combine. Mix AND/OR by nesting groups (a group can itself contain groups). | | `rules` | on each group | The list of child conditions and/or nested groups. | | `field` | a leaf rule | PSA field to match on — board, status, priority, type, sub-type, item, queue, company, owner, etc. (the field's PSA name). | | `operator` | a leaf rule | One of `=`, `!=`, `in`, `notIn`, `contains`, `doesNotContain`, `beginsWith`, `endsWith`, `null`, `notNull`, `<`, `>`, `<=`, `>=`. | | `value` | a leaf rule | A single value, or a list for `in` / `notIn`. | **`value` shape is enforced.** A list belongs only with `in` / `notIn`. Put one under `=` or `!=` and Neo reads it as set membership and rewrites the rule — `= ["Acme"]` becomes `= "Acme"`, and `= ["Acme", "Contoso"]` becomes `in ["Acme", "Contoso"]` — so the filter matches what you meant. The public API is stricter: `POST /public-api/agents`, `PUT /public-api/agents/{id}` and `POST /public-api/backfills` answer `400 validation_error` for a list under any operator other than `in` / `notIn`, and `POST /public-api/backfills/verify` reports it as `success: false` with `safety_level: ERROR`. The filter builder in the dashboard cannot produce the shape. Two optional sibling blocks sit next to `conditions` under `ticket_conditions`: | Field | What it does | | - | - | | `custom_field_conditions` | Filter on PSA custom fields / UDFs — its own `{ conditions: [{ field, operator, value }], combinator }` block. `field` is an option `id` from `GET /public-api/schemas/entity-options?entity_name=TICKET_CUSTOM_FIELD`: the internal name where the PSA has one (`CFDispatchTicket` in Halo, `u_business_unit` in ServiceNow), else the field's name. In Autotask, ConnectWise, Halo and Syncro, a name that is not a custom field reads as empty on every ticket. | | `workload_conditions` | Restrict to tickets a technician logged service activity on within a date range. | **Where a rule sits changes the logic.** A company exclusion (`companyID notIn […]`) placed inside an `or` group only excludes when the other branches also miss — to exclude unconditionally it must be a top-level rule under the root `and`. **AI filters.** Alongside the deterministic rules above, a filter can include natural-language ("AI") conditions — e.g. *"ticket content is related to a printer issue"* — and Neo can generate the deterministic rules for you from a description. These are configured in the filter builder; see [Filter tickets](/core/filter-tickets). AI conditions are slower and consume credits per evaluation, so lead with deterministic rules and use them only for fuzzy matches. **Common gotcha — NULL handling in ConnectWise filters:** ConnectWise's API uses SQL three-valued logic. A filter like `Owner != "Alice" AND Owner != "Bob"` silently drops tickets where `Owner IS NULL`, because `NULL != "Alice"` evaluates to `NULL` (not `TRUE`). To include unassigned tickets, use `Owner IS NULL OR (Owner NOT IN ["Alice", "Bob"])` instead. ## Test mode and re-running | Field | Where | Default | What it does | | - | - | - | - | | `agent_settings.test_mode` | agentic / conversational workflows | `false` | If `true`, the agent still calls its tools, but no change reaches your systems: PSA writes, emails, SMS, and Microsoft 365 or Active Directory changes are simulated. Reads still work — the agent investigates against your live systems exactly as it would on a real run. The one exception is a PowerShell script the agent writes itself, which is held back even when it only reads; see [Microsoft 365 test mode](/agents/tools/m365/overview#test-mode). The block covers **every** PSA write for the whole run, internal ticket notes included — so the agent does not add its own note to say what it would have done. It still makes each write the job needs, as on a live run: every one is simulated, so the report shows the whole set of changes the agent would have made, not only the first. Neo collects the writes it blocked, adds the agent's own run summary, and reports both as one dry-run report at the end of the run — see `report_test_via` below. | | `agent_settings.report_test_via` | agentic / conversational workflows | `Internal Ticket Note` | Where **Neo** posts that dry-run report when `test_mode=true`. The report holds the agent's run summary (its findings and the next steps it recommends) followed by one line per blocked write. Each of those names the tool and the operation, and most also carry the payload the agent would have sent. Channels: `Internal Ticket Note`, `Email to Internal Team` (sent to the addresses listed in the agent's Send Email tool), `Teams Message to Internal Team`, or `Dashboard Message`. Neo writes the report itself when the run ends, so it does not need the agent's own note tool. Delivery still depends on the run having a ticket: `Internal Ticket Note` is skipped for a Chat Agent, and a run on no entity (a scheduled agent with no ticket) reports on the dashboard only, whatever this field says. | | `emulate_main_ticket_as_newly_created` | re-run dialog | `false` | When re-running, pretend the ticket was just created (so triage logic that gates on "newly created" runs again). The run sees only the ticket's original description — no existing notes, time entries, or resolution — and is fully isolated from earlier runs: previously granted approvals don't carry over, and an approval granted during the emulated run resumes that run only. Note this changes what the agent *sees*, not what it can *do* — combine with `test_mode` if writes must be suppressed too. | | `ignore_previous_neo_executions` | re-run dialog | `false` | Same as **"Start fresh"** in the UI — the agent doesn't see prior Neo executions on this ticket. Without it (**"Continue previous"**), the agent picks up where it left off. | ## Technician-in-the-Loop (TIL) | Field | Where | Default | What it does | | - | - | - | - | | `agent_settings.til_channel` | agentic / conversational workflows | `Teams` (AGENTIC) · `Chat` (CONVERSATIONAL) | Where TIL approval requests go: `Teams` (adaptive card sent to configured technicians) or `Chat` (approval card inline in the chat session). CONVERSATIONAL ([chat](/chat-agents/overview)) agents are pinned to `Chat` at create time — Teams delivery doesn't apply because the requester is already in the chat. | ## Custom instructions | Field | Where | What it does | | - | - | - | | `agent_settings.custom_instructions` | agentic / conversational workflows | Free-text instructions that the agent loads as a system prompt. Use to encode MSP-specific naming, escalation paths, tone, prohibitions. | | Action-level instructions | CHAINED\_ACTIONS `Action.instructions` | Per-step instructions for an individual action (e.g. dispatch agent specifics). Layered on top of `custom_instructions`. | | Skill files | `src/agents_v2/skills/prompts/` | Built-in skills the agent loads on demand (resolve-issue, end-user-communication, etc.). | | Skill loader settings | `agent_settings` | Which built-in skills are enabled. | ## Notify-action delays `Notify` actions support a configurable random delay so messages don't all leave at the same second. | Field | Default | What it does | | - | - | - | | `include_random_delay` | `false` | If `true`, the notify action waits a random number of minutes before sending. | | `min_range_delay_in_minutes` | `null` | Lower bound (in minutes) of the random delay. | | `max_range_delay_in_minutes` | `null` | Upper bound (in minutes) of the random delay. | If `include_random_delay=true` but `min` and `max` are both `0`/null, the delay is skipped (not an error). ## Sub-entity callbacks | Field | Where | Default | What it does | | - | - | - | - | | `sleep_before_callback_processing_seconds` | client (not per-workflow) | `4` | Seconds Neo waits after receiving a PSA callback before kicking off the matched workflows. Gives the PSA time to settle (audit rows visible, related records consistent). Tune per-client only if your PSA needs longer. | | `process_sub_entities_only_once` | workflow | `false` | See *Triggering* above. | ## Inbox notifications | Field | Where | What it does | | - | - | - | | `InboxException(send_email=…)` | source code | When `True`, dispatches an email + inbox card to the MSP admin (used for required action like missing settings, auth failures). When `False`, only an inbox card. Default is `False` — emails are reserved for *MSP admin must act*. | | Dedup key | derived | `client_id + message_id`. If the same `InboxMessageId` can occur for distinct subjects (per end-client, per mailbox), use `compose_inbox_message_id(...)` to scope per-subject and avoid collapsing distinct failures into one message. | ## Credits | Concept | Detail | | - | - | | `CHAINED_ACTIONS` workflows | Each action sets its own `credits_consumed` (typically 1 per ticket). Sum = total per run. | | `AGENTIC` entity-triggered | Billed at the **max credit tier** across the resolved toolbox (raw + auto-injected). Tiers: `BASIC`=1, `STANDARD`=2, `ADVANCED`=3. | | Chat agents and `AGENTIC` scheduled (no entities) | Billed as the **sum** of each call's price across the tools actually invoked. A generic API call prices by operation (`api_call_credit_cost`); see [Tool credit costs](/agents/tools/credit-costs). | | Auto-injected tools | `MS_GRAPH_REQUEST` (when MS Graph perms non-disabled), `CW_PSA_REQUEST` (when CW PSA enabled), `SANDBOX_BASH` (always — every agent has a sandbox; `STANDARD` tier), and integration `*_REQUEST` tools all count toward credits — even though they don't appear in the dashboard toolbox. | | Tools you can't switch off | A tool that is always on keeps its normal tier but is excluded from the per-run **max** — your agent's per-run price is set by the tools you chose, not by the ones Neo adds for you. Per-call billing (chat, scheduled) charges every call, always-on tools included. Examples are on [Tool credits](/agents/tools/overview#credit-tiers); in code the rule sits above `ToolType` in `models_tools.py`, keyed off `always_enabled`. | | Neo Support Agent | The Neo-managed support agent bills nothing for the tools that only help you use Neo (Neo API, Web Fetch, Load Skill, Sandbox Bash, approval requests). Tools that read your own tickets and documentation still bill as normal. | | Generic API tool tier | `STANDARD` when all enabled perms are READ\_ONLY; `ADVANCED` when any perm is READ\_WRITE. PowerShell tools stay `ADVANCED` regardless. | ## Time saved Each successful run records the minutes of technician time it saved, and the [Performance page](/product/analytics) adds them up as **Time Saved**. | Field | Where | What it does | | - | - | - | | `manual_minutes_per_run_override` | workflow (triggered `CHAINED_ACTIONS` only) | The minutes one successful run saves, as your team measured it. Set it under **Time saved per run** on the workflow's **Review & Launch** step; leave it empty to use the default. A scheduled workflow records no time saved, so it has no such field. The default adds up fixed minutes for each action, for example Triage Ticket 3, Update Ticket Fields 1 and Add Ticket Note 1 make 5. On a run where an action changed nothing (no field written, no note posted, no merge, no dispatch, no configuration found), that action counts 0; triage always counts. A run where every action changed nothing records 0, even with your own figure. Must be a whole number from 1 to 1440. The workflow shows `manual_minutes_per_run`, `manual_minutes_source` (`DEFAULT` or `SET_BY_USER`) and `manual_minutes_parts` (each action's fixed minutes). | | Agents | — | An agent estimates the time each run saved on its own, so it takes no fixed figure. | ## Versioning & sharing | Field | Where | What it does | | - | - | - | | `created_by_user` | workflow | Who owns the workflow. Required to view/edit unless the workflow is **shared** (or unless you are a super-admin). | | `version_timestamp` | workflow | Optimistic-lock version. PUT requests must include the version they're editing against; mismatches return `409 Conflict`. | | `state` | workflow | `ENABLED`, `DISABLED`, or `DELETED`. Disabled workflows don't run on their triggers and disabled chat agents can't be messaged; deleted are tombstoned. | | `group_name`, `group_order` | workflow | Purely organizational folder + position within the folder. Doesn't affect execution. | ## See also * [Filter tickets](/core/filter-tickets) — how to combine deterministic and AI filters. * [Triggers & Schedules](/core/triggers-and-schedules/intro) — choosing between `SCHEDULED` and `TRIGGERED`. * [Workflows vs Agents](/core/workflows) — when to pick `CHAINED_ACTIONS` vs `AGENTIC`. * [Actions](/core/actions) — what each action does and which credit it costs. # Filter tickets Source: https://docs.neoagent.io/core/filter-tickets Combine deterministic and AI filters with AND/OR logic to target the right work Filters determine which tickets a workflow will process. You can use either *Deterministic filters* (i.e Status = `New`) or *AI filters* (i.e Ticket content is related to `printer issue`) to target the right tickets. ## Deterministic filters Deterministic filters match explicit criteria like queue, status, priority, and company. They are predictable and fast. Example below when trying to filter for all tickets that are from a company called `Autotask Corporation` and are in a `New` status. <Frame> <img alt="Deterministic filter configuration for tickets" /> </Frame> <Note> **A value dropdown offers the first 100 matches.** Fields like Company and Contact can hold tens of thousands of entries in your PSA, so the dropdown shows the first 100 that match and tells you how many more matched — keep typing to narrow it. The limit applies only to what the list offers at once: you can still select as many values as you need. To reach an entry the list does not show, type the start of its name — the dropdown offers the names that begin with what you typed before the names that only contain it. </Note> ## AI filters AI filters capture intent across inconsistent fields and text. They reduce noise and catch edge cases. Example below when trying to filter for all tickets that are related to a `printer issue`. <Frame> <img alt="AI filter configuration for tickets" /> </Frame> ## Let Neo write the filter **Adjust with Neo**, beside **Verify Rules**, opens the Neo Support chat for this workflow's filter. Say which items it should run on — "only P1s from Contoso", "skip anything already assigned" — and Neo reads the saved filter, shows you the conditions before and after, and applies them once you confirm. It replaces the whole condition set when it writes, so it works from what is saved rather than patching part of it. Save the workflow first: Neo reads the saved version, so the button waits while you have unsaved edits. ## Filters that search for text you type Some filters ask a yes/no question about text you supply. `[Extra] Ticket Notes contain`, `[Extra] Audit Trail Contains` and `[AI] Ticket content is related to` all work this way. Pick one of these fields and the builder shows one text box beside it, with no label. Type the words to search for there — `!!AssignMe`, or `~Ticket Closed~`. The builder sets the rest of the rule for you, so there is no operator to choose and no second value to fill in. <Note> Do not move the search text anywhere else, and do not look for a `contains` operator on these rules. The field name already names the comparison: `contain` on the notes and audit-trail filters, `related to` on the AI one. A rule of this kind with an empty text box is the one to fix. </Note> On `[AI] Ticket content is related to` and `[AI] Ticket content is not related to`, type a topic, such as `domain renewal invoices`. The AI asks one question per ticket, whether the ticket is related to that topic, and the field you picked sets the direction. Do not type instructions such as "exclude X, but do not exclude Y": the AI reads the whole text as the topic, so a ticket that fits the "do not exclude" part counts as related, and the "not related to" rule then skips it. To narrow the set, make the topic narrower, or add a second rule on a field such as category or ticket type. ## Filter on custom fields Switch on **Use custom field conditions** under the filter to match on your PSA's own ticket fields: user-defined fields in Autotask and ConnectWise, custom fields in Halo and Syncro, and custom columns (`u_…`) in ServiceNow. Each condition has a field, an operator and a value, and the conditions are combined with the rest of the filter using AND. Pick the field from the list. The list holds your PSA's ticket custom fields as of the last PSA sync. Where a field has an internal name different from its label, as in Halo (`CFDispatchTicket`) and ServiceNow (`u_business_unit`), the list shows both and the condition stores the internal name. * A standard field is not a custom field. Halo's Category 1, a ConnectWise source or status, and similar fields go in the filter rules above. In Autotask, ConnectWise, Halo and Syncro, a custom field condition on such a name reads the field as empty on every ticket, so `null` matches them all. * A saved field that is not in the list shows a warning under the condition. Pick the field from the list to fix it. * In ServiceNow, a column that only another ticket table defines, such as Request Item, names that table in the list. A scheduled workflow searches incidents only, so such a column filters only a triggered workflow. * A field you created in your PSA today appears after the next PSA sync. * Before the first PSA sync stores your custom fields, the field is a text box. Type the field's internal name where your PSA has one: `CFDispatchTicket` in Halo, `u_business_unit` in ServiceNow. In Autotask, ConnectWise and Syncro, type the name exactly as your PSA shows it. ## Reorder rules and groups Every rule and every nested group has a drag handle (⋮⋮) on its left and **Move up** / **Move down** arrows on its right. * **Arrows** move the item one slot within its own group. This changes only how the filter reads; it never changes which tickets match, because rules inside one AND or OR group apply regardless of order. * **Drag** a rule or group by its handle and drop it on another rule to take that rule's slot, or on a group's header (the AND/OR selector) to move it into that group. Drop it on the top header to move it out of a nested group. Moving an item into or out of a group **does** change what the filter matches — a short notice confirms the destination, and the warnings under the filter refresh straight away. Click **Verify Rules** if you want to check the result against live tickets. ## Where each filter runs Filters are applied in two places, and the split affects how fast a scheduled workflow runs and how many credits it uses. * **Your PSA applies most deterministic filters.** Status, queue or team, ticket type, priority, company, and date rules are sent to the PSA as part of the search, so only matching tickets are ever fetched. * **Neo applies the rest after fetching.** Rules prefixed with `[Extra]` (such as `# Time Entries count` or `Hours since ticket was created`) and `[AI]` are calculated by Neo, because the PSA has no equivalent field. A few PSA fields also fall into this group where the PSA's search API cannot express the comparison. Both groups always run, so your results are correct either way. The difference is volume: a filter made only of `[Extra]` and `[AI]` rules fetches every ticket the PSA-side rules allow, then narrows. <Note> **ServiceNow: one Status option can cover two ticket types.** ServiceNow stores a status as a number, and it reuses the same number across ticket types with different names. Number 2 is *In Progress* on an incident and *Work in Progress* on a request item, and number 8 is *Cancelled* against *Awaiting Approval*. Neo names every meaning in the option, so you pick **In Progress / Work in Progress**. On a **triggered** workflow the rule matches either ticket type. Add a **Ticket Type** rule beside it to keep the rule to one. A **scheduled** workflow searches incidents only, so a Status rule there matches incidents whichever meanings the option names, and an option no incident uses — such as **Pending** — matches nothing. </Note> <Tip> For scheduled workflows, add at least one narrow PSA-side rule — a status, a team, or a date range such as `# Days since Ticket was Created`. This keeps the fetch small before the `[Extra]` and `[AI]` rules run. </Tip> <Note> The ticket count shown when you verify a workflow is measured before the `[Extra]` and `[AI]` rules are applied. If your filter relies on them, expect the workflow to process fewer tickets than the verification count suggests. </Note> ## When a name appears more than once in your PSA Some PSA fields let the same name exist several times. Autotask sub-issue types are the common case: each one belongs to a parent issue type, so a name like `Problem` can exist once under every issue type you have. Company and contact names repeat too, usually when an old record was archived and a new one created beside it. The dropdown shows one entry per name, so you cannot tell them apart there. A filter naming that value **matches every entry that carries the name**. If your PSA has eleven sub-issue types called `Problem`, a rule for `Problem` selects tickets under all eleven. <Note> This is the same for `is not` and `is not in list` rules: the filter excludes every entry carrying the name, not just one of them. </Note> To narrow it to a single entry, add a rule for its parent field next to it. Filtering on both **Issue Type** and **Sub-Issue Type** selects only the sub-issue type that sits under that issue type: * `Issue Type` **is** `Hosting` **and** `Sub-Issue Type` **is** `Problem` matches only the `Problem` that belongs to `Hosting`. <Tip> If a workflow selects more tickets than you expect on a field like sub-issue type, check your PSA for repeated names before changing the rest of the filter. Pairing the field with its parent is usually the fix. </Tip> ## Filter by who created or assigned a ticket (ConnectWise) On ConnectWise you can scope a workflow by the person behind a ticket with two rules. Both show a member dropdown, so you can select one or more people with `is in list` or `is not in list`. * **`[Extra] Entered By`** — who created the ticket. * **`[Extra] Assigned By`** — who last set the ticket's owner. Use this to pick up only the tickets a named dispatcher assigned. A ticket that was never assigned has no value, so it never matches an `is in list` rule. Both are `[Extra]` rules, so Neo applies them after fetching. Pair them with a PSA-side rule (a board, a status, or a date range) on scheduled workflows to keep the fetch small. `Assigned By` also reads each ticket's audit trail, which is one more ConnectWise request per ticket. <Note> The dropdown lists your active ConnectWise members. That usually includes the accounts your integrations run as, so you can also select (or exclude) a connector or an automation user. If a name is missing — a deactivated member, or a label with no member record — match it with a `contains` rule instead. </Note> ## Filter by the company's account team (ConnectWise) On ConnectWise, **`[Extra] Company Team member`** matches the people on the Company Team of the company a ticket belongs to. It shows the same member dropdown, so `is in list` and `is not in list` take one or more people, and `is` takes one. Use it to scope a workflow to the companies a named person looks after — for example, alert only on tickets from the companies your four account managers own: * `Company Team member` **is in list** `Norbert V.`, `Zach S.`, `Kevin C.`, `Jonathan C.` A company team usually names several people, so the rule matches when **any** of them is on the team. A company with an empty team, or a ticket with no company, never matches an `is in list` rule — use `is null` to select those companies instead. <Note> The dropdown lists your active ConnectWise members. A company team can also name a contact, who has no member record and so is missing from the dropdown — match a contact with a `contains` rule, which takes part of the name and ignores capitalisation. The rule matches on the person, whatever their team role. If the same person sits on one company team as an account manager and on another as a technical contact, both companies match. To narrow it to one role today, add a rule for a field that already separates them, or reach the role through the [API](/developers/introduction) — the builder does not offer a role box yet. </Note> This is an `[Extra]` rule, so Neo applies it after fetching, and it reads each ticket's company team — one ConnectWise request per ticket, served from Neo's cache when the same company team was read shortly before. Pair it with a PSA-side rule (a board, a status, or a date range) on scheduled workflows to keep the fetch small. ## Filter by priority (Halo) Halo defines priorities per SLA, and each SLA numbers its own levels 1, 2, 3 and so on. The **Priority ID** dropdown lists every level of every SLA under the name Halo shows for it, so pick the name you see on the ticket in Halo. * A rule matches tickets whose own SLA calls their level by that name. Two SLAs that use the same name for a level match together, as in Halo's own filters. * To narrow to one SLA, add an **SLA ID** rule next to the priority rule. * Ticket details and agent instructions show the priority under the ticket's own SLA name too. ## Filter by the end user's email (Halo) On Halo you can target tickets by the email address of the end user on the ticket. The rule is called **End User Email**, and it takes any text operator — `is`, `is not`, `contains`. * Use `contains` with a domain (`@contoso.com`) to select every ticket from one customer's users. * Halo cannot filter on the address itself, so Neo applies this rule after fetching. Pair it with a PSA-side rule — a status, a team, or a date range — on scheduled workflows. * A ticket whose end user has no email address on record never matches an `is` or `contains` rule. ## Filter by category (Halo) On Halo you can target tickets by their category. The rules are called **Category 1**, **Category 2**, **Category 3** and **Category 4**, one for each category level in Halo, and they take any text operator. * Use `is null` to select tickets with no category at that level, for example an agent that fills in a missing category on closed tickets: `Status ID` **is** `Closed` and `Category 1` **is null**. * `is` and `is in list` compare the full category name as Halo shows it on the ticket, such as `Technical>User Admin>Password/MFA Reset`. Use `contains` to match part of it. * Halo categories are standard ticket fields, not custom fields, so use these rules and never a custom field condition named "Category 1". A custom field condition only reads your Halo custom fields. * Neo applies these rules after fetching. Pair them with a PSA-side rule — a status, a team, or a date range — on scheduled workflows. ## Filter by Top Level (Halo) In Halo a client can sit under a Top Level, a group of clients. **`[Extra] Client Top Level`** matches the name of the Top Level that the ticket's client sits under, so one rule covers every client in the group, including clients you add to it later. * `Client Top Level` **is** `Managed Services` matches tickets from every client under that Top Level. `is in list` takes several Top Levels, and `contains` matches part of the name. Capitalisation does not matter. * Pick the Top Level from the list. It shows the Top Levels of the clients Neo synced from Halo. The rule stores the name, so after you rename a Top Level in Halo, pick it again once Neo syncs your clients. * A client that is in no Top Level never matches `is`, `is in list` or `contains`. Use `is null` to select those clients, and `is not` or `is not in list` to keep them while you exclude a Top Level. * Neo reads the Top Level from the clients it synced from Halo, and fetches a client it has not synced yet from Halo with the ticket. A client moved to another Top Level can match its former Top Level until the next PSA sync. * Neo applies this rule after fetching. Pair it with a PSA-side rule — a status, a team, or a date range — on scheduled workflows. ## Filter by a custom field (Halo) Halo cannot filter tickets on a custom field, and its ticket list does not include custom field values. So Neo applies every custom field condition after fetching, on scheduled and triggered workflows alike. * On a scheduled workflow, Neo reads a ticket in full to get its custom fields, once per ticket. Pair the condition with a PSA-side rule — a status, a team, or a date range — to keep the fetch small. * `is not` also matches a ticket that does not have the field at all. ## Run Now and your filters When you click **Run Now** on a workflow and give it a ticket, Neo does **not** do PSA event matching — it starts that workflow directly on the ticket you chose. It does still evaluate that same workflow's own **Filter Ticket** conditions first, through a read-only pass. If the ticket does not match the filter, the run is recorded as **SKIPPED** in [Executions](/product/executions) and no actions are taken. The Run Now dialog has a **Bypass 'Filter Ticket' conditions** switch. Turn it on to run the workflow on the chosen ticket even when the ticket does not match the filter — useful for testing a workflow against a specific ticket without changing the filter. The public API does the same with `bypass_entities_filter: true` on [Run an agent now](/api-reference/agents/run-an-agent-now), so you can also ask Neo Support to run a workflow on a ticket its filter skips. <Note> Run Now checks the filter of the **workflow you are running**. It is separate from how another agent hands off to a target with the [Trigger or Schedule Workflow](/agents/tools/management/trigger-or-schedule-workflow) tool, which skips the target's filter — see that tool's page for the difference. </Note> ## Building your filters using AI We get that building filters can sometimes be a bit tricky. So to make this easier, you can get Neo to build your filters for you using the `Generate Rules` button. You'd specify, in natural language, what you want to filter for and Neo will build the filters for you. <Frame> <img alt="Modal to generate and refine AI filters" /> </Frame> # Memory Source: https://docs.neoagent.io/core/memory Durable facts, rules, and preferences Neo recalls at runtime — curated by your team and scoped MSP-wide or per company. Memory is Neo's long-term knowledge about your MSP and your clients — the durable facts, rules, and preferences that don't belong in any single ticket. Neo recalls relevant memory every time it works, so it stays consistent instead of re-asking or guessing. It applies across all of Neo's actions, ensuring a consistent approach for each company. <Note> **Automatic discovery is coming soon.** Today, every memory is one your team adds. Soon, Neo will also learn durable facts on its own — from your resolved tickets, your RMM inventory, and reviews of its own past runs — and propose them for your review. Automatic discovery is **not enabled yet**; for now, you curate memory yourself. </Note> ## What Neo remembers <Columns> <Card title="Facts" icon="circle-info"> Durable truths about a client — the apps they run, who their VIPs are, their environment's quirks. </Card> <Card title="Rules" icon="list-check"> Handling that kicks in for a specific situation — who to escalate to, where to route certain tickets, a client's exception to your usual process. </Card> <Card title="Preferences" icon="sliders"> Tone, terminology, and key contacts — how to communicate and who to notify for each client. </Card> </Columns> ## Memory vs. custom instructions Neo **retrieves** memory: at runtime it builds a query from the ticket and pulls in the memories that match. A memory only helps if something in the ticket — an app name, a symptom, the requester, the kind of request — would lead Neo to it. *"Acme runs SecureShield AV"* surfaces the moment a ticket mentions an antivirus alert. A rule with nothing to match against — *"always set the Site Code custom field"* — never surfaces, because no ticket says "Site Code." That gives you two ways to make a memory land: key it to a cue a ticket will contain (leave it **unpinned**), or, if it has no cue but always applies, **pin** it so Neo never has to find it. Standing, **org-wide** procedures that apply across every client — your documentation process, your onboarding steps, your change-approval policy — belong in the agent's [custom instructions](/core/writing-agent-instructions), not memory. Custom instructions are always in front of Neo, so it never has to retrieve them. <Tip> Quick test: is it specific to **one client**? It's a memory — pin it if every ticket needs it, leave it unpinned if a ticket will cue it. Is it how this agent works for **all** clients? It's a custom instruction. For the full decision guide across instructions, skills, memory, and intents, see [Teaching Neo](/core/teaching-neo). </Tip> ## Pinned vs. unpinned * **Pinned** memories are **always** included — Neo never misses them. Pin what's relevant on every run for a client, e.g. *"Acme's VIPs are CEO Jane Doe and CFO Mark Lee — treat their tickets as top priority."* * **Unpinned** memories are the default — Neo brings them up on its own when they're relevant to the task, so it stays informed without crowding every run, e.g. *"Peter Nguyen is the Service Desk Manager"* surfaces when a ticket needs escalation, but stays out of the way otherwise. Most memories should stay unpinned. The [Phone Agent](/core/phone-agent#giving-the-agent-a-reference-list) works differently: it reads only the MSP-wide memories you attach to its number, pinned or not, and recalls no others. Pin a memory when every ticket for that client needs it but nothing in the ticket would cue Neo to look — a VIP list, branding and tone, a custom-field convention. Leave it unpinned when the ticket's own content will surface it — an escalation contact, an environment quirk, handling for a specific kind of request. A pinned memory that names one action applies to that action only. *"When dispatching any ticket, look at the service board team"* guides dispatch; it does not change another step in an agent's instructions, such as *"Assign to Neo Administration"*. Because every pin is loaded into every run, pins are capped: up to **20 pinned memories per company** and **10 MSP-wide** (with a total-length limit per scope). If a pin is rejected, unpin something less essential — or leave the memory unpinned and let Neo recall it. **Length:** an unpinned memory is kept short (up to 500 characters) so it stays a sharp, recall-friendly fact. A **pinned** memory can be longer — because it's injected verbatim rather than recalled, its limit is the scope's pinned-length budget — so a standing instruction has room for the detail it needs. You can edit any memory's text in the dashboard (**Save** replaces the old version); editing a pinned memory keeps it pinned. ## Scope Choose who a memory applies to: * **Company-specific** — applies only when Neo works for that end-client company. * **MSP-wide** — applies across every client, e.g. your internal standards or tooling. ## Audience Choose which agents can recall a memory: * **Triggered / Scheduled agents** — the automation agents that work tickets and entities. * **Chat agents — Internal** — your technicians' dashboard chat. * **Chat agents — External** — end-user-facing chat. * **All agents** — every surface (the default). Classic [workflows](/core/workflows) benefit too: **pinned** memories are included whenever a workflow's Smart Actions run for a company — Ticket Triage, Ticket Dispatch, L1 Engineer, and Acknowledge Issue all read them, and there is nothing to switch on. Recalling unpinned memories on demand is an agent capability. ## Agents By default every agent working for a company reads that company's memories. That is usually what you want. When a fact belongs to one job and nowhere else, use **Agents** to name the agents that may read it. Reach for it when a memory helps one agent and is unhelpful — or unsafe — everywhere else: * A deployment value your EDR agent needs, which has no business in an agent that writes to customers. * A billing rule only your invoicing agent should apply. * A long runbook that would crowd every other agent's context for no gain. <Warning> **Naming agents takes the memory out of your classic workflows.** Smart Actions run inside a workflow rather than as an agent, so they cannot be named in the list. Name even one agent and Ticket Triage, Ticket Dispatch, L1 Engineer and Acknowledge Issue all stop reading that memory. Leave **All agents** selected if a workflow needs it. </Warning> The agent list works together with the audience, not instead of it. An agent must be on the list **and** its surface must be in the audience. Neo blocks a pair no agent can read — an internal chat agent with the audience set to external chat, for example — and names the agent, rather than saving a memory that never appears. Pinned memories are budgeted per agent. A memory limited to one agent uses only that agent's pin budget, so a busy agent no longer stops you pinning something for a quiet one. <Note> If you delete an agent a memory was limited to, the memory is left with no reader. The Memory list marks that row **No agent**, so check it after you remove or replace an agent. </Note> You can also ask your [Neo Support Agent](/chat-agents/neo-support-agent) to limit a memory to agents, such as "only my EDR agent should read the Huntress deployment memory". It asks first whether a classic workflow needs the memory, then makes the change after your approval. Through the [public API](/developers/introduction), set `restricted_to_agent_ids` when you create or supersede a memory. ## Add a memory <Note> Only **admins** can add, edit, pin, or delete memories — including through a chat agent (an agent saves a memory only when the person chatting is an admin). Everyone's agents still recall them. </Note> <Steps> <Step title="Open Memory"> Go to the **Memory** section in the dashboard. </Step> <Step title="Write the memory"> Select **New memory** and enter the fact, rule, or preference in plain English. </Step> <Step title="Set scope and audience"> Choose the companies it applies to (or **All companies** for MSP-wide), and which agents should recall it. </Step> <Step title="Limit it to specific agents (optional)"> Leave **All agents** unless the memory belongs to one job. Naming agents also takes it out of your classic workflows. </Step> <Step title="Pin if it's always relevant"> Pin memories Neo should apply on every run; leave the rest unpinned. </Step> </Steps> ## Delete memories Select the trash icon on a row to delete one memory. To delete several, tick the checkbox on each row, or the checkbox in the header to select every memory on the page. Then select **Delete** and confirm the count. Deleted memories stop reaching your agents, and a deleted pin frees its slot. To bring a memory back, turn on the **Deleted** filter and select the restore icon on its row. A pinned memory comes back unpinned if its pin slots have filled up since. You can also ask your Neo Support Agent to clean up memories for you, such as "delete every memory about client abbreviations". It lists them, asks you to confirm, then deletes them all after one approval. ## Examples Each example notes its **scope**, **type**, and **pin** — and what makes Neo recall it. The first three are **unpinned**: a ticket's own content cues them. The last is **pinned**: it always applies but nothing in a ticket would trigger it. ### Environment quirk **Scope:** Acme Corp · **Type:** Fact · **Pin:** Unpinned ``` Acme Corp runs SecureShield AV, not Microsoft Defender. Defender "threat detected" alerts on their machines are expected and can be ignored. ``` **Why it works:** a ticket about a Defender alert names the antivirus, so Neo recalls this and avoids the false alarm. ### Key contact **Scope:** Acme Corp · **Type:** Fact · **Pin:** Unpinned ``` Peter Nguyen is the Service Desk Manager and the escalation contact for after-hours P1 incidents. ``` **Why it works:** when Neo decides a ticket needs escalating, it looks up who to escalate to — and finds Peter. ### Special handling for a request type **Scope:** Acme Corp · **Type:** Rule · **Pin:** Unpinned ``` Acme keeps a pool of loaner laptops at their HQ. When a ticket reports broken or failed hardware, offer a loaner before ordering a replacement. ``` **Why it works:** a hardware-failure ticket cues Neo to recall the loaner option before it suggests buying new. ### Tailored ticket acknowledgments **Scope:** Acme Corp · **Type:** Preference · **Pin:** Pinned ``` - Mention that their dedicated support team, "The Acme Support Squad", is on the case. - If the ticket is P1, state that an update will be provided within 15 minutes. ``` **Why it's pinned:** nothing in a ticket would specifically trigger this, but it shapes every Acme reply — so it's pinned rather than left to recall. <Tip> Keep each memory short and specific — one fact or one rule per memory recalls better than a long block of text. Start with your most important clients and the rules you repeat most often. </Tip> # Overview Source: https://docs.neoagent.io/core/overview Index of Neo's four core concepts — triggers & schedules, ticket filters, workflows, and agents — and when to use each. Neo Agent is organized around a few core concepts. Understanding these will help you design reliable, scalable automations. ## Key concepts <Columns> <Card title="Triggers & Schedules" icon="clock" href="/core/triggers-and-schedules/intro"> Define when a workflow or agent runs—on ticket events (Triggered) or on a schedule (Scheduled) </Card> <Card title="Filter Tickets" icon="filter" href="/core/filter-tickets"> Target which tickets to process using deterministic and AI filters, with AND/OR logic </Card> <Card title="Workflows" icon="pen-to-square" href="/core/workflows"> Automated sequences of smart actions that process tickets, update data, and notify users </Card> <Card title="Agents" icon="robot" href="/core/agents"> Autonomous agents that can work a ticket from start to finish using a choice of tools/actions at it's disposal to achieve a specific objective </Card> </Columns> <Card title="Workflows vs Agents — which one to pick" icon="route" href="/core/workflows-vs-agents"> Quick decision guide: start with workflows for triage, dispatch, resolution, escalation, and merge; use agents for everything else. </Card> # Phone Agent Source: https://docs.neoagent.io/core/phone-agent Handle inbound calls with an AI agent — caller-ID lookup, natural-language information gathering, PSA ticket creation, optional call transfer. After-hours and overflow patterns included. The Phone Agent handles incoming calls for end users. It acts as the first point of contact, interacts naturally with callers, gathers necessary information, and integrates directly with your PSA to manage support tickets. ## Building Your First Phone Agent Watch the following video to get started with setting up your first Phone Agent with Neo Agent in less than 5 minutes: <iframe title="Workflows Demo" /> You choose the country of the agent's phone number when you create the agent. Neo provides numbers in the United States, Canada, the United Kingdom, the Netherlands, Australia and New Zealand. Callers in the country you choose dial a local number. ## The Call Journey 1. Call routing & pickup from your VoIP rules to the Neo number 2. Caller identification using the incoming phone number (Caller ID), on ConnectWise, Autotask and Halo: the agent looks for the one active PSA contact with that number. A number that several contacts share, such as a company's main line, identifies nobody, and neither does a Halo site's phone number; the agent then asks for the caller's name and company 3. AI interaction with professional greeting and clarification 4. Understanding the request through active listening and questions 5. Optional transfer to a person, blind or warm, when configured 6. Gathering caller information for new tickets (company name, full name). If not provided, proceed with available details and explain why information is helpful 7. Company matching against your PSA: the spoken company name is matched to your synced company list — including names spelled letter by letter or with a spelling alphabet ("V as in Victor"). Confident matches attach the ticket to that company. For an uncertain match the agent asks the caller once to repeat or spell the company name, and never reads out the names of other companies in your PSA; if the second attempt still does not match, the ticket uses the Default Company when one is set (see the warning below) 8. Ticket creation in your PSA with thorough issue details and a provided ticket ID. If the company cannot be determined, tickets use the Default Company from PSA settings When the caller goes quiet, the agent asks whether they are still there. If the caller stays silent through three of these prompts, about one to two minutes in all, the agent says goodbye and ends the call. This also ends a call where the caller never speaks, so an open line does not keep using call minutes. The count starts again whenever the caller speaks, and the agent never prompts a caller who is on hold during a warm transfer. <Info> For accurate company/contact attribution after ticket creation, pair with a Ticket Triage workflow to analyze transcripts and update fields as needed. </Info> ## PSA Ticket Settings Each Phone Agent creates tickets in your PSA using its **PSA settings** — the destination board/queue, initial status, default company, ticket source, and an optional **Priority** (leave unset to let the PSA assign its default). Edit these from the Phone Agent settings dialog on the dashboard. The Default Company field lists the first 100 companies by name; type part of a name to search the rest of the list. <Warning> **Default Company is required.** Every PSA refuses a ticket with no company on it, so a caller whose company the agent cannot match gets no ticket while this field is empty: the agent tells them someone will call them back, and Neo sends you an action item naming the phone number to fix and what the caller asked for. Choose the company you want unmatched calls filed under — many MSPs use a catch-all or triage company. On ConnectWise, a ticket for a company that was deleted in ConnectWise also goes to the Default Company. Neo drops the deleted company's contact, and after the call it may set a contact from the Default Company that matches the caller. The ticket description says which company ConnectWise rejected. If the Default Company itself was deleted, those calls get no ticket, so pick a company that still exists. </Warning> <Info> **Halo — Urgency and Impact.** Some Halo instances make **Urgency** and **Impact** mandatory when a ticket is created. If yours does, set a default **Urgency** and **Impact** in the Phone Agent's PSA settings so calls can create tickets — leave either as *"Use PSA default"* to let Halo decide. These two fields appear only for Halo tenants (ConnectWise and Autotask don't use them on create). Without them on a Halo instance that requires them, ticket creation — including the post-call transcript fallback — fails with `Impact is mandatory / Urgency is mandatory`. </Info> ## Choosing the Voice Each Phone Agent speaks with a voice you choose in the Phone Agent settings dialog, under **Voice Configuration**. Four settings decide how it sounds: | Setting | What it does | | - | - | | **Voice Engine** | Which speech service speaks — **Cartesia** or **ElevenLabs**. | | **Language** | The language the agent speaks and listens in: English, French, Dutch, German or Spanish. | | **Gender** and **Accent** | Pick the voice within that language. An accent appears for English — American, British or New Zealand — and for Spanish, which offers Latin American. | | **Speed** | How fast the agent talks, from 0.8 to 1.2. The default, 0.98, is close to normal speaking pace. | Neo picks the voice for you from the language, gender and accent you choose, so most agents need no further setup. To use a specific voice instead, enter its **Custom Voice ID** from your chosen engine's voice library. <Info> **A custom voice belongs to one engine.** A voice ID from ElevenLabs means nothing to Cartesia and the other way round, so changing the Voice Engine clears the Custom Voice ID. Set the engine first, then paste the ID. </Info> **Which engine you get by default.** Phone numbers added from September 2026 speak through Cartesia. Numbers you already had keep ElevenLabs and the voice you chose for them — nothing changes until you change it yourself. **Two combinations to know about.** Cartesia has no male New Zealand voice, so a male + New Zealand agent on Cartesia speaks with an Australian male voice instead; choose ElevenLabs if you need a New Zealand male, and the settings dialog says so at the point you choose. ElevenLabs has no Dutch female voice, so a female Dutch agent on ElevenLabs speaks with the Dutch male voice; choose Cartesia for a Dutch female. ### Hearing the voice before you save Click **Play sample** under the voice settings to hear the agent say a short greeting in the voice you have set. It plays the settings on screen, so you can try an engine, accent or speed and listen before you save. The sample uses the same engine, voice and speed as a call. On a call the voice sounds a little less clear, because a phone line carries less sound. If the engine does not accept a **Custom Voice ID**, the dialog says so under the button and marks the field, and nothing plays. A call with that ID would have no audio, so fix or clear the ID before you save. ## Transferring a Call to a Person In the Phone Agent settings dialog, under **Available Agent Capabilities**, **Transfer to a person** sets how the agent puts a caller through to someone on your team: | Setting | What the agent does | | - | - | | **Off** | Never transfers a call. | | **Blind transfer** | Hands the call to the number and leaves it. | | **Warm transfer** | Puts the caller on hold, calls the number, briefs whoever answers, and connects the two only when that person agrees. | An agent has one of the two transfer settings, never both. An agent that already transferred calls has **Blind transfer**, and keeps it until you choose another setting. ### Blind transfer The agent says a short line, such as *"One moment while I transfer you"*, and hands the call to the number. The agent then leaves the call, so it cannot hear who answers. If nobody answers or voicemail picks up, the caller stays there: the agent cannot bring them back. The technician's phone rings as an ordinary incoming call, with no introduction. A caller who hangs up while that number is still ringing never reaches anyone. Where Neo files a ticket after the call, under [what the ticket records](#what-the-ticket-records), it says they hung up before they were put through. ### Warm transfer **What the caller hears.** The agent says that it is transferring them, then the caller hears hold music. The caller hears nothing of the call to the technician. **What the technician hears and sees.** The phone shows one of your own Neo phone numbers: a Neo number with the technician's country calling code when you have one (US and Canadian numbers count as one, because they share +1), otherwise the number the caller dialled. A missed call returned to that number reaches your own agent. The phone rings for up to 30 seconds. When the technician answers, a second AI agent speaks in the agent's language. It introduces itself as the AI assistant for your company, never by the agent's name, says who is on hold and from which company, and sums up the request in two or three sentences: the problem and its details, what the caller already tried, how urgent it is, and the ticket number when the agent created one. It says how Neo identified the caller's name and company, by the caller ID or by the name the caller gave, and says so when it could not identify them. Neither one proves who is speaking, so it never calls the caller verified. The technician can ask questions, and then answers *"Can I put them through?"*: * **Yes.** The caller and the technician are connected. The agent goes silent for the rest of the call, and the connected call ends after one hour. * **No.** The technician can say why, or ask for something, such as *"I'm on another call, take a message"*. The caller does not hear it. The agent acts on a request like that one. What the technician says is never written on the ticket, where your customer might read it; the ticket says only that the transfer was declined. If the caller hangs up while on hold, the technician hears that the caller has hung up, with the ticket number when there is one, and the technician's call ends. **When the transfer does not connect.** If the technician says no, nobody answers, or voicemail or an automated menu picks up, the caller comes back to the agent. The agent says only that it could not connect the call, then offers another option: * another number, when your Custom Instructions name one for this case; * to take a message. With **Create Ticket** on, the agent puts the message in a new ticket, or in the ticket it already created on this call. Without it, the message stays in the call transcript, and Neo can create a ticket from the call after it ends. The second agent is told never to leave a voicemail message. If it does not recognise a voicemail greeting, the brief can still be recorded as a message. The ticket then says the call was answered and ended before the caller was put through. ### The number and the rules for a transfer For both settings, say in the **Custom Instructions** when to transfer and which number to use — for example *"If the caller asks for a person, transfer them to +1 555 123 4567"*. Write the number in full international format: a `+`, the country code, then the number. Local formats work too — spaces, dashes, brackets and dots are removed, and a number with no `+` gets the country code of the agent's own phone number, so `(555) 123-4567` on a US agent dials `+15551234567`. Two habits cause a transfer to reach nobody: * **Writing the country code without a `+`.** `1 555 123 4567` is read as a national number, so the country code is added on top of it and the call goes nowhere. Write `+1 555 123 4567`. * **Adding an extension.** `+1 555 123 4567 ext 12` puts the extension digits into the number itself. Give the main number only. When you save the settings, Neo reads the phone numbers in your instructions and checks each one. If a number would not reach anybody, a window opens before the save and shows what a transfer would dial for every number it found. You can go back and correct it, or save anyway — the choice is yours, and Neo never refuses the save over a number. If a transfer fails, the agent tells the caller only that it could not connect the call, then offers to take a message, or to raise a ticket when **Create Ticket** is on. It never tells the caller that the person was unavailable or did not answer. When the transfer number itself is at fault, an **Action Required** message appears in your Neo inbox naming the number to fix. ### What the ticket records The ticket says which number the agent transferred the caller to, when, and what happened: see [what lands on the ticket](/phone-agent/intro#what-lands-on-the-ticket). When the caller reached the number, Neo creates no extra ticket after the call, because the person there now has the request. After a transfer that did not connect — a warm transfer the far end did not take, or either kind the caller hung up on before they were put through — Neo treats the call like any other: when the agent created no ticket during it, Neo assesses the call afterwards and creates one, unless the call was spam or the caller asked for no ticket. This holds with **Create Ticket** off too. Neo files that ticket under the first company it can place the caller in: the company of the PSA contact whose phone number matches the caller's, then the company the caller named during the call when it matches a PSA company with confidence, then the **Default Company**. Neo never guesses from an uncertain match. When none of the three applies, the caller gets no ticket, and Neo sends you the action item described under [PSA Ticket Settings](#psa-ticket-settings). After a warm transfer, the transcript continues past the transfer. A line marks when the caller was put through, and each thing said after it is labelled **Caller** or **Technician**, in the order it was said: ``` Assistant: I'll transfer you to a technician now. --- Caller connected to technician at 19:24:55 UTC --- Technician: Hi, this is Sam from the helpdesk. Caller: Hi, my VPN has been down since this morning. ``` Call History shows this transcript, and with **Save transcription** on, the ticket note carries it too. The agent stays silent on the call and never answers what the caller and the technician say. The call's sentiment still rates only the part with the agent. The brief to the technician is in neither the transcript nor the recording. With **Save Call Recording** on, the recording on the ticket is the caller's own call, and after a warm transfer it too continues through the conversation with the technician. ## Different Instructions After Hours A number can answer differently when your office is closed. Turn on **After-Hours Instructions** when you edit the agent, and write what the agent does then. For example: *"Our office is closed. Create a ticket and tell the caller a technician will call back on the next business day."* A call that starts outside business hours, on a day you do not work, or on a holiday follows the after-hours instructions in place of the Custom Instructions, for the whole call. A call that starts at 16:58 keeps the normal instructions after 17:00. Write each set so it stands on its own: the agent reads one or the other, never both. Rules that apply at every hour can go in a [reference memory](#giving-the-agent-a-reference-list), which reaches every call. **Business hours** decide when the after-hours instructions apply: * **Workspace working hours** are the business hours and time zone in [Settings](https://dashboard.neoagent.io/settings#business-hours), Monday to Friday. * **Custom working hours** set the days and the opening and closing times for this number alone, in the workspace time zone. The hours cannot run past midnight. **Holidays** count as outside business hours all day. A number uses the public holidays of its country unless you choose **No holidays**. UK numbers use the bank holidays of England. The US list holds the federal holidays, including days many offices stay open, such as Columbus Day and Veterans Day; choose **No holidays** if you answer on those days. The agent is not told the time. Neo checks the hours when the call starts and gives the agent the matching instructions, so a caller who asks "are you open?" gets the answer your instructions give. When you save in the dashboard and the after-hours instructions name a transfer number, such as an on-call line, the dashboard checks it the same way it checks the Custom Instructions. A change through the Neo Support Agent or the API does not run this check. You can also ask the [Neo Support Agent](/chat-agents/neo-support-agent) to change a number's after-hours instructions or business hours, or call `PATCH /public-api/phone/numbers/{number}` from your own automation. ## Giving the Agent a Reference List Some call rules depend on a list, for example *"customers on our direct support plan go to a separate line"*. Keep the list in a [memory](/core/memory) and attach it to the agent's number. Keep the rule in the Custom Instructions. The agent then has the list on every call to that number. <Steps> <Step title="Write the list as an MSP-wide memory"> On the [**Memory**](https://dashboard.neoagent.io/memories) page, add a memory and choose **All companies** as its scope. For example: ``` Direct support customers: Contoso Dental Fabrikam Logistics Northwind Traders ``` </Step> <Step title="Attach the memory to the number"> Open the agent under [**Phone Agents**](https://dashboard.neoagent.io/phone-agent), search for the memory under **Reference Memories**, add it, and save. </Step> <Step title="Write the rule in the Custom Instructions"> For example: *"If the caller is from a company on the direct support list, transfer them to +1 555 123 4567."* The instruction says what to do, and the memory says who it applies to. The agent hears company names through speech-to-text, so a listed name can arrive split into two words or without a leading "The". Say how strictly to match, with an example of a name that does not count: *"Company names can come through speech-to-text slightly differently, for example split into two words or without a leading 'The'. Treat those as the same company, but a company with a different word in its name is a different company: 'Northwind Dental' is not 'Northwind Traders'. Transfer a direct support customer at once, before you ask for their name or the issue."* </Step> </Steps> Each number takes up to **10** memories and **4,000** characters in total. Only MSP-wide memories can be attached: a memory about one company would reach every caller on the number, whoever they are. The phone agent reads no other memory, so pinning a memory does not bring it into calls. A memory's audience and agent list do not apply here, because attaching it to the number is the choice. When you edit an attached memory, calls use the new text, and you do not attach it again. If an edit takes the total over 4,000 characters, calls leave out each memory that no longer fits, whole, and never cut one in half. A deleted memory drops out of calls. If Neo cannot read the memories within 1.5 seconds when a call starts, that call goes ahead without them. A reference memory does not have to be a list. Anything the agent needs on every call fits, such as your support hours or who covers a public holiday. The agent reads attached memories as part of its Custom Instructions, so your instructions decide what it does with them. Attached memories are for the agent only. It shares one with a caller only when your Custom Instructions say so, for example *"If a caller asks for our support hours, tell them. They are in memory."* If the list is also pasted into the Custom Instructions, remove that copy once the memory is attached, so an edit to one copy cannot leave the other out of date. ## Common Use Cases These are the most common scenarios where we see MSPs deploying our Phone Agent. <AccordionGroup> <Accordion title="Answering calls after hours"> Instead of routing users to an automated voicemail, Phone Agent can answer calls after hours, ensuring your clients always have access to support. Give the number [after-hours instructions](#different-instructions-after-hours) so it tells callers the office is closed and takes a ticket, or sends emergencies to an on-call line. </Accordion> <Accordion title="Answering calls during overflow"> When your technicians are busy, Phone Agent can answer calls during overflow, ensuring your clients always have access to support. </Accordion> </AccordionGroup> ## Switching an Agent Off or Deleting It Open the agent under **Phone Agents** to change its state. * **Disable** stops the agent answering. Callers reach nothing, no ticket is created, and no minutes are used. You keep the number, and **Enable** switches it back on. * **Delete agent** removes the agent from your list at once, and Neo gives the number back to the carrier within a few minutes. Use it when you no longer want the number at all, for example after spam callers find it. Deleting has two conditions: 1. **Switch an active agent off first.** You then run without the number before you give it up. A suspended agent (its add-on has stopped) needs no step: you can delete it as it is. 2. **Only an admin can delete.** Other users see the button, but it is disabled and tells them why. <Warning> Deleting cannot be undone. The number goes back to a public pool, and anyone may get it next. Before you delete, remove the number from your website, signage and VoIP rules, and from every alerting or monitoring service that calls it. The confirmation shows how many calls the number took in the last 30 days and when the last one came in, so you can see whether it still receives calls. The caller of each call is in your call history. Your call history stays. </Warning> To replace a number, add a new agent with the same greeting, instructions and PSA settings, test it with one call, repoint your routing to it, then disable and delete the old one. Only active agents count toward your limit of three. If you already have three, disable the old agent first; its line stops answering until the new agent is added and your routing points to it. ## What the Phone Agent Costs Two parts, and both appear on the invoice you already get. | | | | - | - | | **Monthly fee** | A flat fee for the add-on, charged for the days you held it in the month. It appears as a line on your normal monthly invoice, so it follows the same card and the same payment reminders as your plan. | | **Call time** | **1 credit per minute**, taken from your plan's monthly credits — the same pool your workflows and agents draw from. There is no separate phone bill. | Because minutes come out of your plan allowance, a busy phone month shows up the way any busy month does: your credits run down sooner. You can watch it under **Billing**, and see the split by workflow, agent and phone usage on the Performance & Cost page. If you have agreed a different price with us — a plan that already includes the Phone Agent, for example — that is what you are charged, and your monthly fee may be zero. ## What Happens to Your Numbers if the Add-On Stops Your phone numbers belong to your Phone Agent subscription. If that subscription ends — you cancel it, or a card fails and Stripe stops retrying — Neo pauses the numbers instead of giving them back straight away. <Steps> <Step title="The numbers are suspended"> Calls stop reaching the agent, and the numbers no longer appear as active in your dashboard. Nothing is lost: Neo keeps renting each number from the carrier, and you keep the same rows in your Phone Agent settings. </Step> <Step title="You have 14 days to come back"> Restart the add-on inside that window and every suspended number switches back on by itself, with the same digits and the same settings. You do not need to ask anyone, and there is nothing to reconfigure. </Step> <Step title="After 14 days the numbers are released"> The carrier takes each number back into its public pool, and the numbers leave your Phone Agent list. This step cannot be undone. If you restart the add-on later, you get new numbers, and you must tell your clients the old ones no longer work. </Step> </Steps> <Warning> A number you switch off yourself is treated the same way once the add-on stops. Neo pays the carrier for a paused number exactly as it does for an active one, so a paused number is suspended alongside the rest and follows the same 14-day clock. </Warning> # Reading Email and PDF Attachments Source: https://docs.neoagent.io/core/reading-email-attachments Neo reads .eml and .pdf files attached to tickets — phishing reports, forwarded messages, invoices, vendor letters — so agents can see the original sender, headers, links and text without a tool call. When a ticket carries an **`.eml` file** (a complete email saved as a file) or a **`.pdf` file**, Neo opens it and adds its content to the ticket context the agent works from. For an email the agent sees the headers, the body, the links in it, the files that were attached to it, and any email or PDF nested inside it. For a PDF the agent sees the document's title and author, the text of its first 20 pages, and the link targets on those pages (the first 60). This is what makes **phishing-report tickets** workable. When an end user reports a suspicious email through a report button (Phished, KnowBe4 PhishER, Microsoft's Report Message add-in), the reporting tool sends a notification into your PSA mailbox. Your PSA creates a ticket, keeps a message-id in the description, and drops the message body — so the ticket says almost nothing. Everything that matters is in the attachment: who reported it and from which company domain, and the reported email itself. Some tools nest the reported email as a `.eml`; Phished exports it as a `Report.pdf` of the rendered message with the link targets kept in the PDF. Neo reads both, so an agent can correct the ticket's company from the reporter's domain, judge whether the email is legitimate, and route the ticket accordingly. It also covers the everyday case: an invoice, a quote or a vendor letter attached to a ticket is read as text, so the agent can act on what is in it. ## How it works Like [image reading](/core/reading-images), this is **built in, not a tool you enable**. Reading the file happens when Neo loads the ticket with its images, so every agent that reads the ticket gets the content automatically, and so does every workflow step that loads the ticket that way, including **Ticket Triage**. The older fixed-list actions that load the ticket without images (ticket building, dispatch, escalation, merge detection, RMM verification, time tracking) do not read attachments. There is no model call involved: the file is parsed directly, so it adds no credits. The file itself is downloaded from your PSA when the ticket loads, so a ticket that carries several large files takes longer to load. The content appears in the ticket context inside a `document_attachment` block that names the file and its type (`EML` or `PDF`), marked as untrusted third-party data. The block tells the agent to read it as evidence and never as instructions. That lowers the risk from a hostile file; it does not remove it, so keep tools with side effects behind technician approval on agents that handle phishing reports. ## What Neo reads from an email file | | | | - | - | | **Headers** | From, Reply-To, Return-Path, To, Cc, Date, Subject, Message-ID, the sender's domain, and the authentication results (SPF, DKIM, DMARC) mail servers stamped on it. | | **Received chain** | The mail-server hops the message passed through, so the agent can see where it really came from. The 12 hops closest to the recipient are listed. | | **Body** | The plain-text body, or the HTML body converted to text. | | **Links** | The URLs in the body, including ones only present in the HTML (tracking pixels, hidden links). The first 60 are listed, each cut at 200 characters; a message with more links is cut at that point. | | **Attachments** | The name, type and size of every file attached to the email. | | **Nested emails** | An email attached inside the email — how most phishing-report tools carry the reported message — is opened and read the same way. Two levels of nesting are opened; an email deeper than that is named but left unopened. | | **Attached PDFs** | A PDF attached to the email is read the same way as a PDF on the ticket (below), up to 3 PDFs per email file; further ones are named but not read. When the PSA also stored that PDF as its own ticket attachment, it is rendered once. | ## What Neo reads from a PDF | | | | - | - | | **Metadata** | Title, author, subject, the software that produced the file, and the creation date. | | **Text** | The text layer of the first 20 pages, page by page. A longer document is named as cut at that point. A scanned PDF with no text layer is reported as such; Neo does not run OCR on attachments. | | **Links** | The target of each link on the pages Neo reads (the first 20) — the `href`s a rendered email keeps as PDF links — plus any URL written in that text. The first 60 are listed, each cut at 200 characters. | | **Protected files** | A PDF with print or copy restrictions is read. A PDF that needs a password to open is named but not read. | ## What's supported | | | | - | - | | **Where** | `.eml` and `.pdf` files attached to PSA tickets on every supported PSA — Autotask, ConnectWise, Halo, ServiceNow, and Syncro. Files attached to the ticket itself (the usual case for a ticket created from an email) are picked up — on ServiceNow, from the first 50 attachments on the ticket; files attached to a note are picked up too on Autotask and Halo, the PSAs that link an attachment to a note. | | **Formats** | `.eml` files (standard RFC 822 / MIME email) and `.pdf` files. A file with one of those extensions is read whatever content type the PSA labelled it with. Outlook `.msg` files and Office documents are not supported. | | **Size** | Up to 10 MB per file. The text Neo adds to the ticket is capped at roughly 32,000 characters per file; a longer file is cut at that point and marked as truncated. Up to 5 readable files are opened per ticket (and per note); further ones are named but not read. | | **Setup** | None. It's automatic for every agent that reads tickets. | ## Building a phishing-report workflow A typical agent for Phished-style tickets, in its custom instructions: 1. Read the `document_attachment` blocks on the ticket and note the reporter's address and domain. 2. Look up the end-client company whose domain matches, and correct the ticket's company if it is wrong. 3. Assess the reported email: sender domain versus display name, Reply-To and Return-Path mismatches, SPF/DKIM/DMARC failures, link destinations versus link text, urgency and payment language. When the report is a PDF, the sender and headers are not in it; assess from the text and the link targets. 4. Write the assessment as an internal note and route the ticket to the service desk queue. Filter the workflow to the tickets that come from your reporting tool (for example by subject prefix or sender) so it only runs on phishing reports. <Tip> Neo reads the file, and any email or PDF nested inside it, as text. It does not follow links, and it does not open other attachment types inside the reported email (Office files, archives, executables are named only). The assessment is made from the headers, text and link targets alone, which is what a first-pass analyst does too. </Tip> # Reading Images & Screenshots Source: https://docs.neoagent.io/core/reading-images Neo automatically reads image attachments on tickets — screenshots, error screens, spreadsheets — with a vision model, so agents can see and reason over what's in them. No OCR or extra setup needed. When a ticket has an image attached — a screenshot, an error screen, a photo of a device, a capture of a spreadsheet — Neo **reads the image and reasons over what's in it**. You don't need to OCR it first or ask the sender to retype the data: Neo sees the content of the picture as part of the ticket. ## How it works Neo automatically detects image attachments on a ticket and runs each one through a vision model. The model produces a description of what the image contains, and that description is added to the ticket context the agent works from. From there it's treated like any other ticket content — the agent can pull a figure off a spreadsheet screenshot, read an error message from a screen capture, or factor a photo into its diagnosis and dispatch decision. This is **built in, not a tool you enable**. There's no "read image" or "OCR" entry in the agent's tool list and nothing to configure — image reading happens as part of loading the ticket, so any agent that reads the full ticket gets the image content automatically, and so does the **Ticket Triage** action. A description is kept for 30 days once an image has been read, so the same image file (a signature logo, say) is described once and reused across the tickets and runs it appears on. The match is on the file's bytes: a copy that a mail gateway re-encoded is read again. (Because it isn't a tool, you won't find it on the [Tools Overview](/agents/tools/overview) page — it's a capability of how Neo reads tickets.) ## What's supported | | | | - | - | | **Where** | Image attachments on PSA tickets — ConnectWise, Autotask, Halo, and ServiceNow. Both images attached to the ticket (or to its notes / time entries) and images referenced inline in note text are picked up. On Autotask, a screenshot that the Incoming Email Processor kept only inside the ticket's `OriginatingEmail.eml` (no attachment of its own, a `[cid:...]` placeholder in the description) is read from that file. | | **Formats** | Standard screenshot / photo formats: **PNG** and **JPEG**. | | **Size** | Up to roughly **15 MB** per image. Larger images are automatically compressed to fit; anything that still can't be processed is skipped with a note in the ticket context rather than silently dropped. | | **Setup** | None. It's automatic for every agent that reads tickets — no toggle, no add-on. | ## Good to know * **Neo reads the picture's *content*, not a guaranteed pixel-perfect transcription.** For a spreadsheet screenshot Neo will read the visible figures and labels; for a very dense or low-resolution capture, exporting the underlying data (e.g. a CSV) is still the most reliable way to get every value across. * **Non-image documents.** Email files (`.eml`) and PDFs attached to a ticket are read the same automatic way — see [Reading Email and PDF Attachments](/core/reading-email-attachments). Other document types (Office files) are not read from ticket attachments; this capability is specifically for raster images (PNG / JPEG). * **It's about images on tickets.** This is the supported path for "someone sent in a screenshot": attach it to the ticket and Neo reads it. Image content pasted into other surfaces isn't read the same way — keep the image on the ticket so the agent can act on it. # Scheduled agents Source: https://docs.neoagent.io/core/scheduled-agents Run agents on a recurring schedule to perform proactive tasks without a ticket Scheduled agents run on a cron cadence — daily, hourly, weekly — and execute tasks based entirely on your custom instructions and enabled tools. Unlike triggered agents that react to a specific ticket, scheduled agents work **without any PSA entity**. They're ideal for proactive operations like compliance audits, account hygiene, and recurring M365 administration. <Tip> Think of triggered agents as reactive (something happened, go handle it) and scheduled agents as proactive (go check on things, take action if needed). </Tip> <Note> Running the same job every week and want it to come out **identical** each time — same shape, same numbers, same format? Capture the procedure as a [custom skill](/agents/skills/custom-skills) and point the agent at it. The skill freezes the exact steps so the output stops drifting run to run. </Note> ## Triggered vs scheduled agents | | Triggered Agent | Scheduled Agent | | - | - | - | | **Starts when** | A PSA event occurs (ticket created, updated, etc.) | A schedule fires (daily at 8 AM, every hour, etc.) | | **Works on** | A specific ticket or time entry | No entity — runs from custom instructions alone | | **Context** | Ticket details, end client company, contact | MSP-wide context, available tools, custom instructions | | **Use case** | Resolve issues, triage, communicate with users | Audits, hygiene, compliance, recurring admin tasks | | **Conversation** | Continues across runs on the same ticket | Fresh conversation each schedule fire | | **Credits** | Once per run, at the highest tier among the tools you chose | **Each tool call**, at its [per-call price](/agents/tools/credit-costs). A run with ten API calls pays for ten calls. | <Warning> A scheduled agent without a ticket is **not** billed like a ticket-triggered agent. The builder's **Built-in Capabilities** list (skills and always-on tools) shows no prices, and skills themselves are free to load — but every tool those skills use still spends credits. [External API Request](/agents/tools/management/external-api-request) is 3 credits per call. Test mode blocks writes; it does **not** stop billing. See [Tool credit costs](/agents/tools/credit-costs) for the full table and a worked example. </Warning> ## How it works <Steps> <Step title="Schedule fires"> At the configured cadence (e.g., daily at 6 AM), the agent starts a new execution. </Step> <Step title="Agent reads instructions"> The agent loads your custom instructions, enabled tools, and any loaded skills. There is no ticket to analyze — your instructions define the task. </Step> <Step title="Agent uses tools"> The agent executes the task: querying M365 environments, searching documentation, running RMM scripts, or any other enabled tool. </Step> <Step title="Results and approvals"> The agent can request technician approval (TIL) before sensitive actions, send notifications via Teams or email, and create tickets for issues it finds. </Step> </Steps> <Info> If the agent requests Technician-in-the-Loop approval or kicks off an RMM script, the execution **pauses** until the technician responds or the script completes. The agent then resumes with full context of what it was doing. </Info> ## Setting up a scheduled agent <Steps> <Step title="Create a new agent"> Go to **Workflows** → **Create** and select **Agent**. </Step> <Step title="Set the trigger to Scheduled"> Under **Trigger**, select **Scheduled** and configure your cadence (e.g., daily at 6:00 AM, weekly on Mondays). </Step> <Step title="There is no ticket filter to set"> A scheduled agent has no **Filters** tab. Nothing is missing: a filter narrows the tickets that start a run, and a scheduled run starts from the clock instead. The agent chooses what to work on while it runs — see [Choosing which companies a run covers](#choosing-which-companies-a-run-covers). </Step> <Step title="Enable tools"> Select the tools the agent needs. For M365 tasks, the relevant Microsoft 365 tools are auto-enabled based on your integration's permission groups. This agent bills **per tool call** — check [Tool credit costs](/agents/tools/credit-costs) before you enable write access or External API Request. Other commonly used tools for scheduled agents: * **Search tools** — Find Documentation, Find Tickets by Content/Metadata * **Communication tools** — Send Teams Message, Send Email * **Management tools** — Create New Ticket, Trigger or Schedule Workflow * **Resolution tools** — Execute RMM Script </Step> <Step title="Write custom instructions"> This is the most important step. Your custom instructions define exactly what the agent does each run. Be specific about: * What to check or audit * How the agent picks the companies to work on — see [Choosing which companies a run covers](#choosing-which-companies-a-run-covers) * What thresholds or criteria to act on * What action to take when issues are found * How to report results See [use cases](#use-cases) below for examples. </Step> <Step title="Configure safety controls"> * **Test mode**: Start with test mode on. The agent will log what it would do without taking real actions. * **Technician-in-the-Loop**: Enable TIL on your M365 permission groups for any write operations. The agent will pause and request approval before making changes. * **Access profiles**: Use the Helpdesk or IT Admin preset to ensure TIL is required on sensitive operations. </Step> <Step title="Set the schedule and enable"> Configure your schedule cadence, set execution windows if needed (e.g., only during business hours), and enable the workflow. </Step> </Steps> ## Choosing which companies a run covers **You say it in the custom instructions.** That is the whole answer, and it is where the scope belongs. There is no Filters tab for a scheduled agent and you do not need one — a filter narrows the tickets that start a run, and a scheduled run starts from the clock instead. The agent finds its own companies and works through them. ### Write the rule, not the list The instruction can name a company outright: ``` Run this for Northwind Manufacturing. ``` For a set, describe the set instead of pasting the names: ``` Run this for every client whose "Monthly Reporting" custom field is set to Yes. Read that list from the PSA at the start of each run. ``` A rule holds a few hundred companies in one sentence, and your PSA stays the list — so a client that joins or leaves is picked up on the next run with nobody editing the agent. A pasted list of names has to be maintained by hand and nothing tells you when it has gone stale. The one thing you do have to grant is the access: enable [PSA API](/agents/tools/psa/psa-api) with the **Companies** permission group so the agent can read the list. Neo injects your PSA credentials at the network layer, so nothing in the run handles them, and every call carries the permissions you granted this agent. ### Leave the method to the agent You do not have to say *how* the work gets done, and you are better off not trying. Every agent has a [sandbox](/agents/tools/built-in/sandbox) — it is on by default, with nothing to enable — and Neo tells the agent when to use it. For a report across many companies, the agent writes a script. That script pulls each company's data at once rather than one company at a time, and where the report needs written analysis it produces that inside the same script. A few hundred companies is an ordinary size for this. You do not need to break the job up on the agent's behalf. A second shape exists for a different kind of work: when each company needs its own decisions and actions in your systems, rather than a section in a report, the agent can run [parallel subagents](/agents/tools/built-in/dispatch-subagents). That one is capped at 50 companies per run, so it is worth knowing which kind of job you are describing. Reporting is almost never the second kind. A scheduled agent bills [per tool call](/agents/tools/credit-costs), so a wider scope costs more. Watch the spend on [Billing](https://dashboard.neoagent.io/billing) for the first few runs rather than estimating it. The rule tells the agent which companies to report on. It is not a permission boundary — the agent can still read any company your integration reaches. Grant Read Only unless the agent has to write, and require [Technician-in-the-Loop](/core/technician-in-the-loop) on anything that does. ### Get it working, then freeze it Ask [Neo Support](/chat-agents/neo-support-agent) to run the agent for you and read the real output before the schedule fires, instead of waiting a month to see what it produced. Once a run comes out right, save the procedure as a [custom skill](/agents/skills/custom-skills). Later runs load the skill rather than rebuilding the approach, so the output stops changing between runs. ## Use cases <AccordionGroup> <Accordion title="Scan for new admin accounts"> **Goal**: Detect unauthorized admin role assignments across M365 tenants daily. **Tools**: Microsoft 365 (Directory Roles, Audit & Reports) **Custom instructions example**: ``` For each connected M365 tenant: 1. List all current directory role assignments for privileged roles (Global Administrator, Exchange Administrator, SharePoint Administrator, Security Administrator, Privileged Role Administrator) 2. Compare against the audit log for role assignment events in the last 24 hours 3. If any new admin assignments are found, send a Teams notification to the security channel with: who was assigned, which role, when, and by whom 4. If no new assignments are found, do not send any notification ``` </Accordion> <Accordion title="Disable inactive M365 accounts"> **Goal**: Find and disable accounts with no sign-in activity for 90+ days. **Tools**: Microsoft 365 (User Management, Audit & Reports) **Custom instructions example**: ``` For each connected M365 tenant: 1. Search for user accounts where the last sign-in date is more than 90 days ago 2. Exclude service accounts and break-glass accounts (accounts containing "svc-", "breakglass", or "emergency" in the display name) 3. For each inactive account found, request technician approval before disabling 4. Once approved, block sign-in for the account 5. After processing all accounts, send a summary to the IT Admin Teams channel listing accounts disabled and any that were skipped ``` <Warning> Always enable Technician-in-the-Loop for agents that disable accounts. A misconfigured filter could lock out active users. </Warning> </Accordion> <Accordion title="Rotate admin and service account passwords"> **Goal**: Monthly password rotation for privileged accounts. **Tools**: Microsoft 365 (Security, Directory Roles), Generate Password **Custom instructions example**: ``` For each connected M365 tenant: 1. List all users with Global Administrator or Privileged Role Administrator roles 2. Also list any service accounts (accounts with "svc-" in the display name) 3. For each account, generate a new secure password and request technician approval before resetting 4. Once approved, reset the password 5. Send the new credentials securely to the designated admin contact via a secure link 6. Log a summary of all rotated accounts as an internal note ``` </Accordion> <Accordion title="Weekly documentation audit"> **Goal**: Identify outdated KB articles based on recent ticket trends. **Tools**: Find Documentation, Find Tickets by Content, Send Teams Message **Custom instructions example**: ``` 1. Search recent resolved tickets from the past 7 days for recurring topics 2. For each topic, search the documentation library for related KB articles 3. Flag any articles that haven't been updated in 6+ months but relate to a topic with recent ticket activity 4. Send a summary to the documentation-review Teams channel with article titles and the ticket topics they relate to ``` </Accordion> <Accordion title="Stale ticket report"> **Goal**: Weekly summary of tickets that haven't been updated in 7+ days. **Tools**: PSA API (Tickets: Read Only), Send Teams Message **Custom instructions example**: ``` 1. Search for all open tickets that haven't been updated in the last 7 days 2. Group by assigned technician 3. Send a summary to the service-desk Teams channel listing each technician and their stale tickets, sorted by age ``` </Accordion> </AccordionGroup> <Note> **Coming soon**: Audit enterprise applications (app registrations and service principals). This capability is on the roadmap and will unlock additional scheduled agent use cases. </Note> ## Best practices <AccordionGroup> <Accordion title="Start with test mode"> Enable test mode for your first few runs. Review the agent's execution log in Executions to verify it's doing what you expect before enabling real actions. </Accordion> <Accordion title="Enable Technician-in-the-Loop for writes"> Any agent that modifies accounts, resets passwords, or disables users should require TIL approval. Use the **Helpdesk** or **IT Admin** access profile on your M365 integration to enforce this. </Accordion> <Accordion title="Be specific in custom instructions"> Scheduled agents have no ticket to provide context — your custom instructions are the entire task definition. Include: what to check, how to select the companies, what thresholds trigger action, and how to report results. </Accordion> <Accordion title="Pick the right cadence"> Match the schedule to the urgency of the task. Security audits might run daily, password rotations monthly, documentation reviews weekly. Avoid running more frequently than needed. </Accordion> <Accordion title="State the scope as a rule, not a list of names"> The custom instructions are where you say which companies a run covers. For a set, write the rule — "every client whose *Monthly Reporting* field is Yes" — and let the agent read that list from your PSA each run. A pasted list of names has to be maintained by hand. See [Choosing which companies a run covers](#choosing-which-companies-a-run-covers). </Accordion> </AccordionGroup> # Supervised mode Source: https://docs.neoagent.io/core/supervised-mode Run an agent on real tickets and approve every change before it happens. How it differs from test mode, how to supervise one run or every run, and what each approval covers. Supervised mode is the step between testing an agent and trusting it. The agent works on real tickets, reads real data and proposes real changes, and it stops for a technician's approval before each change it makes. <iframe title="Supervised mode in 56 seconds" /> Use it for an agent you have just built, or one whose instructions you have just rewritten. You see what it decided and why, one change at a time, before anything reaches your PSA. Neo holds each change until you approve it, with the exceptions listed under [What supervision does not cover](#what-supervision-does-not-cover). That makes it the first step of the loop from a new agent to a trusted one. Run the agent in Supervised mode on a real ticket, and approve, reject or comment on each card as it works. When the ticket is done, click **Train** on the run in [Executions](/product/executions), say what should change, and send. Neo Support reviews the run and your decisions, and updates the agent when you confirm the edit it proposes. Repeat until the runs need no corrections, then let the agent run alone. ## Supervised mode is not test mode The two answer different questions. | | Test mode | Supervised mode | | - | - | - | | Does it change anything? | No. Every write is simulated. | Yes, once you approve each one. | | What is it for? | Checking the agent reads a ticket correctly and reaches a sensible plan. | Watching it do the real work before you let it run alone. | | What do you do? | Read the report afterwards. | Approve or reject each change as it happens. | | What does it cost? | A normal run. | A normal run. Approvals are free. | You can turn both on. The agent then shows its plan and asks before its changes, as on any supervised run, but every change is simulated, whether you approve it or not. The plan card starts with **Test run** to say so, and the test report arrives once, when the run ends. Supervised mode alone is the better choice. It already changes nothing until you approve, and an approved change then really happens, so you see the true result of each step. ## Supervise one run, or every run **One run.** Open the agent in [Executions](/product/executions), choose **Run now**, and turn on **Supervised run**. Pick who approves that run. Those technicians receive the cards for this run in place of the agent's own approvers, and your choice is remembered in your browser for the next one. The agent's saved settings do not change, so its scheduled and triggered runs are unaffected. A disabled agent can run supervised too, so you can test a new agent before you enable it. The [Neo Support agent](/chat-agents/neo-support-agent) can start the same run for you: say which ticket and who approves. The agent stays disabled, so it does not pick up new tickets on its own. <Frame> <img alt="The agent editor Overview tab with Supervised Mode switched on above Test Mode" /> </Frame> **Every run.** Open the agent and turn on **Supervised Mode** on its **Overview** tab. The setting stays on until you turn it off, and the agents list shows a **Supervised** label on each agent it is working on. You can also set `agent_settings.supervised` through the [public API](/developers/introduction), or ask the [Neo Support agent](/chat-agents/neo-support-agent), for example "turn on supervised runs for my onboarding agent". ## What the agent does on a supervised run 1. **It shows its plan first.** Before its first change, it sends a card with how it reads the ticket and its instructions, and every change it intends to make. Approve it, or ask for changes and it sends a revised plan. 2. **Every change asks on its own**, whatever the agent's permission groups and tool settings say, with a card in three parts: the **Action**, the instruction it follows (**Because**), and what it read to decide (**Evidence**). One card covers one record: the ticket, one user, one mailbox, one contact. So the ticket's own notes, time entries and field or status changes arrive on one card, and so do blocking a user's sign-in and revoking their sessions. A second record, a second system, an SMS or email the agent sends, and starting another agent each get a card of their own. One card does cover the same change repeated over several records when it names each one, such as a password reset for five named users. A card that reports on another change comes after that change has run. An Exchange or Active Directory PowerShell script asks even when it only reads, because Neo cannot tell from the script that it changes nothing. 3. **It works through the whole plan in one run.** After an approved change, it goes straight on to the next planned change and asks for it. The run ends when every planned change is made, rejected, blocked or no longer needed, and the run summary names each planned change it did not make, with the reason. 4. **It asks when your instructions leave a decision open**: when two instructions conflict, when one can be read two ways, or when none covers a choice on which MSPs differ. The card shows each choice, the one it will follow if you approve, and suggested wording for your instructions. Approving the plan or answering a question never approves a change. [Supervised run checkpoints](/agents/tools/approvals/supervised-run-checkpoints) has what each card shows and how the agent reads each answer. An approval covers that change for the rest of the run it was given in, and no further. Every supervised run starts clean: the agent plans again before its first change, and asks for each change again, even one you approved on an earlier run on the same ticket. A run that only reads, and finds nothing to do, sends no plan. A plan, an answer or a pending card from an earlier run does not count either. An agent that is not supervised works differently: its approval keeps covering the same change on the same ticket in later runs. ## Watch the run After you start a supervised run from **Run now**, Neo confirms that the run has started, and that it asks you before every change it makes on this run ([what that does not cover](#what-supervision-does-not-cover)). **Open the run** takes you to the run's page in [Executions](/product/executions#execution-log), where you watch the agent work. Each card appears on that page at the point in the run where the agent raised it. The same card also goes to Teams and to the [Approvals page](/core/technician-in-the-loop#approvals-in-the-dashboard). Answer it in whichever place you like: the first answer counts, and the other places show it. * **A change** offers **Approve**, **Ask for changes** and **Reject**. * **The plan** offers **Approve plan**, **Ask for changes** and **Reject and stop**. Approving the plan lets the run start. It approves no change. **Reject and stop** asks why: **Wrong steps**, **Not needed on this ticket** or **Just a test**, with optional details. The run stops whatever you pick. **Train** reads the reason to decide what to fix: the agent's instructions, the tickets it runs on, or nothing. * **A question about your instructions** offers **Use Neo's reading**, **Give another reading** and **Reject and stop**. A decision usually resumes the work as a new run. The page shows all of the runs as one flow, so the next steps and cards appear below the ones you answered. A line marks where each run starts, with its run id to copy. On the run page, a card has buttons for an admin and for the technicians it was sent to. Everyone else sees the card and who it waits for. An answered card shows the decision, who made it and their note. Executions and the run page label a supervised run **Supervised**. Once the run ends, the page counts the decisions you recorded, or says the run changed nothing when it asked for no approval. **Train** hands the run to the Neo Support agent. ## After the run: train the agent Your answers on a supervised run tell Neo what to change in the agent. When the ticket is done, open the run in [Executions](/product/executions) and click **Train**, then send, with or without a note. The [Neo Support agent](/chat-agents/neo-support-agent) reads the run and every decision on it: each change you rejected, each plan you rejected and why, each note you left, and each choice you picked for an unclear instruction. Each of your approvals split the work into a new run, and it reads all of them, so the reasoning behind the plan is in front of it alongside the last step rather than left behind in an earlier run. It proposes the exact edit to the agent's instructions, so the next run acts on its own where this one asked, and it changes nothing until you click **Apply it**. ## What supervision does not cover * **Another agent or workflow.** You approve the start, and what it runs then follows its own settings. Supervision covers the agent you switched it on for. * **[The sandbox](/agents/tools/built-in/sandbox).** You approve the command before it runs, not each change inside it, so one approval can cover several changes. * **Chat agents.** The person in the conversation already approves each change, so the setting does not apply. The agent also does all of its own work, without subagents, so every change stays in one approval stream. ## Before you turn it on **Somebody has to be able to approve.** Supervision works through the Request Technician Approval tool. A one-off supervised run adds that tool for the run and uses the approvers you pick at **Run now**, so there is nothing to set up first. The saved Supervised Mode setting does need the tool on the agent with at least one approver. You can save such an agent as disabled without one, but not as enabled. **It cannot run alongside sequential processing.** Both hold the same lock. Turning Supervised Mode on turns sequential processing off and tells you it did. Going the other way, the sequential setting stays unavailable while the Request Technician Approval tool is enabled, so turn Supervised Mode off first. **A run already under way cannot be supervised.** An agent has one run at a time on a ticket, and supervision has to be set before that run starts. If the agent is still working, wait for it to finish or stop it, then start the supervised run. <CardGroup> <Card title="Supervised run checkpoints" icon="list-check" href="/agents/tools/approvals/supervised-run-checkpoints"> What the plan card and the instruction question show </Card> <Card title="Technician-in-the-Loop" icon="user-check" href="/core/technician-in-the-loop"> The approval system supervision runs on </Card> </CardGroup> # Teaching Neo: instructions, skills, memory & intents Source: https://docs.neoagent.io/core/teaching-neo The four places to put knowledge when building agents — what each is for, how Neo uses it, and how to decide where a given fact, rule, or procedure belongs An agent has four places for what it needs to know. Each answers a different question, lives in a different place and reaches the agent in a different way. Knowledge in the right place shows up on the runs that need it. Knowledge in the wrong place either never surfaces or rides every run. | | Answers the question | Example | | - | - | - | | [Custom instructions](/core/writing-agent-instructions) | How does **this agent** do its job? | "Triage hardware tickets to the Field Services board. Never change priority on VIP boards." | | [Memory](/core/memory) | What is true about **this client**, or about our MSP? | "Acme Corp runs SecureShield AV, so Defender alerts on their machines are expected." | | [Skills](/agents/skills/overview) | How do we run **this repeatable job**? | The exact steps and code behind the weekly open-ticket report. | | [Intents](/chat-agents/intents) | What do we collect for **this type of request**? | New starter: full name, start date, who to copy access from, 2FA number. | ## Start here: adopt them in order Nobody sets all four up on day one. Most of the value sits on the first two rungs. 1. **Custom instructions, always first.** Every agent needs them, and for many agents they are enough. Give the agent its job, its boundaries and its tone. 2. **Memory, as the quirks surface.** One fact at a time, usually captured from a real run: this client runs SecureShield AV, that client's VIPs are these two people. Scope each to the [company](/core/memory) it is true for, or MSP-wide for something true everywhere. No technical setup. 3. **Skills and intents, when a recurring need shows up.** A report you run every week, an intake that keeps coming back half-answered. The easiest way in is to [capture a good run](#improving-them-from-real-runs). <Tip> A new or non-technical owner gets real value from custom instructions and memory alone. Custom instructions carry the agent's real behaviour; a thin pointer like "resolve tickets using relevant skills" is not enough on its own. </Tip> ## How each one reaches the agent * **Custom instructions** are in front of the agent on every run, for the one agent you wrote them on. They suit anything that must apply every time that agent works. They do not suit a long procedure or a fact true for one client. * **Memory** is retrieved when relevant. Neo keeps one memory library for your tenant. An unpinned memory surfaces when something in the ticket or conversation cues it; a [pinned](/core/memory#pinned-vs-unpinned) memory is always included for its scope. A memory is scoped to one company or MSP-wide, and its [audience](/core/memory#audience) and any agent filter decide which runs can recall it. * **Skills** are loaded when the task matches. Every triggered, scheduled and internal chat agent sees a short menu of skill names; when a task matches one, the agent loads the full procedure and can run the skill's tested code in its sandbox. Custom skills are tenant-wide. An end-user Chat Agent has no skill loader. * **Intents** are loaded when a request matches. An agent that receives requests sees the intents in scope; when someone asks for a "new starter", it loads that intent's questions and collects only what is missing. Intents apply to end-user chat agents, internal chat agents and ticket-triggered agents. <Note> Custom instructions and pinned memories are in the prompt on every applicable run, so keep both short. Unpinned memories, skills and intents load on demand: the agent carries a small menu and pulls the full content when it matches, so your 30th unpinned memory or 10th skill does not slow other runs. </Note> ## Where does this belong? Run whatever you are about to write through these questions, in order, and stop at the first yes. 1. **Is it a password, token, key or other secret?** None of the four. It belongs in your password manager or documentation platform. When an agent needs a stored password, it reads it from a documentation platform you have connected with that permission. 2. **Is it a fact true for one client, or a durable fact about your MSP?** A client fact names one company, person, site, device or product: a contact, an approver, a naming convention, the identity provider, the tools they run, an exception to your usual handling. An MSP fact is your support hours, your dispatch coordinator, the documentation tool you use. Either is a **memory**, scoped to that company or MSP-wide, when it is one fact or a short rule that Neo cannot already read from a ticket, your PSA or your documentation. A client-only procedure of roughly five or more steps goes to question 3. One fact per memory. Pin it only if every run needs it and nothing in a ticket would cue it. 3. **Is it a procedure of roughly five or more ordered steps that applies to only some of the agent's runs, or a scheduled agent's whole job?** A report, a reconciliation, a routine you follow only when a condition holds ("when a user is travelling abroad"). That is a **skill**. A scheduled agent keeps one line in its instructions that names the job and the skill to load. Ask Neo Support to [build it](/agents/skills/creating-skills), ideally from a run that already did the job well. 4. **Is it "for requests of type X, ask for A, B and C", a form, or "don't ask about D on X requests"?** That is an **intent**, on an agent that receives requests. List the questions once; every in-scope agent runs the same intake. 5. **Otherwise it is how this one agent behaves, on every run, for every client.** Its job, the order of work, what it may and must not do, when it hands back, its tone, its status conventions. That is a **custom instruction**. Keep them short; the more they carry, the less each line weighs. One exception: an end-user Chat Agent cannot load a skill or recall an unpinned memory. For that agent, a procedure stays in its custom instructions, and a client fact becomes a pinned memory with the external-chat [audience](/core/memory#audience). Two rules settle most gray areas. * **One client: memory. Your MSP itself: MSP-wide memory. Every client: instructions.** Client-by-client exceptions written into instructions are the most common misplacement; they apply to the wrong clients and get duplicated across agents. An MSP-wide memory ("our dispatch coordinator is Sam Lee") is available across all your client companies, to the agents its audience and any agent filter allow. A rule about what the agent does, true for every client, stays in the instructions even when it names a product ("for RMM alerts that auto-resolved, add an internal note"). * **How to do it: skill. What to collect first: intent. What is true: memory.** A memory can become false. A skill's saved procedure stays fixed until you edit it. An intent ends at one outcome. When guidance conflicts, your custom instructions win over a built-in skill's defaults. ## What does not belong where **Not a memory** * A secret. It belongs in your password manager or documentation platform. * A rule for the agent's own behaviour ("never reboot without approval"). That is a custom instruction. * A procedure of roughly five or more steps. That is a skill. * A copy of an agent's instruction block, or a line addressed to one agent by name. That is that agent's instructions. * A fact Neo can already read from a ticket, your PSA or your documentation, such as a contact's email on the PSA contact record. **Not a skill** * The agent's own main loop. An L1 agent's "check history, gather details, diagnose, fix, verify, document" is its instructions, however long. * A one-off job. * A single fact or preference. * A how-to a built-in skill already teaches, such as your PSA's API. * A copy of another agent's instructions, or a cheat sheet that repeats an existing skill. **Not an intent** * A body that is the agent's whole job ("act as a friendly triage agent that understands the issue and hands off"). * A catch-all for requests that fit nothing. That is the agent's default behaviour. * Two intents that differ only by a value. "Hardware: laptop", "Hardware: desktop" and "Hardware: tablet" are one Hardware intent with a device-type field. * A procedure hidden in the intake. The intent keeps the questions; the steps go to a skill. * A policy that applies whatever the requester asked ("never reply to a personal Gmail address"). That is an instruction, or a memory when it is one client's rule. * An intent on a scheduled agent. A scheduled run has no requester. ## What good ones look like **Custom instructions**: the agent's job and boundaries, true for every client. * *"You handle the Service Desk board. Only work tickets in New or Unassigned; never reassign a ticket a technician has already picked up."* * *"If you can't resolve after two attempts, escalate to the ticket owner with a summary of what you tried."* **Memory**: one fact each, scoped to the client it is true for. * *"Acme Corp runs SecureShield AV. Defender 'threat detected' alerts on their machines are expected and can be ignored."* (unpinned: an antivirus ticket cues it) * *"Contoso's file shares live on CNT-FS01; mapped drives are pushed by the 'Contoso Drive Maps' GPO."* (unpinned: a missing-drive ticket cues it) * *"Acme's VIPs are CEO Jane Doe and CFO Mark Lee. Treat their tickets as top priority."* (pinned: it always matters, and no ticket says "VIP") **Skills**: whole procedures with a start and an end. * The weekly open-ticket summary, grouped by client and priority, the same shape every Monday. * The monthly Microsoft 365 licence reconciliation against actual headcount. * Your leaver procedure: the exact steps, in the exact order. **Intents**: request types where complete intake is the hard part. * **New Starter**: full name, start date, who to copy access from, whether they need RDS, 2FA mobile number. * **Hardware Request**: device type, who it is for, needed-by date, whether budget approval is attached. * **Mailbox Access**: which mailbox, who gets access, read-only or send-as, sign-off from the mailbox owner. ## Improving them from real runs The fastest path is to react to real runs from [Executions](/product/executions). * A run went wrong: use [Train Neo](/product/train-neo). The run opens in a Neo Support conversation; describe what should have happened, or just send, and Neo investigates the run and its approval decisions and proposes the one change that fixes it — usually an edit to the agent's custom instructions, sometimes a tool, an integration permission or a memory it was missing — applied once you confirm. * A run went right and you want it repeated identically: click **Skillify** on it to [capture it as a skill](/agents/skills/creating-skills). * A run stumbled on a client quirk: add what it was missing as a memory, and every future run for that client knows it. * Starting a new agent: apply a [template](/building-automations/managing-workflows/templates), or ask Neo Support to set it up with you. It asks the few questions the template cannot answer about your workspace, then creates the workflow or agent disabled for your review. ## They compose: a new-starter example A well-built setup uses the four together. Take employee onboarding. 1. An office manager emails: *"We've got someone starting in the Bristol office."* The ticket triggers your service-request agent, whose **custom instructions** define its job and boundaries on that board. 2. The agent recognises your **New Starter intent** and replies asking only for what the email did not answer: the start date and the 2FA number. 3. When the reply lands, it re-triggers the agent, which loads your **user-onboarding skill** and follows your exact provisioning procedure step by step. 4. Throughout, **memory** fills in what is true for this client: *"Bristol office users get the RDS access template"*, *"new-starter tickets go to Priority 2"*. Intake is consistent because of the intent, execution is consistent because of the skill, client specifics are right because of memory, and the agent stays inside its lane because of its instructions. ## Manage them in the dashboard Memory, intents and skills are tenant-wide libraries under **Data** in the left navigation. Custom instructions live on each agent. <CardGroup> <Card title="Writing agent instructions" icon="pen" href="/core/writing-agent-instructions"> How to write instructions that hold up: structure, specificity, and what to leave out </Card> <Card title="Memory" icon="brain" href="/core/memory"> Facts, rules and preferences: pinned vs. unpinned, scope, and audience </Card> <Card title="Skills" icon="screwdriver-wrench" href="/agents/skills/custom-skills"> Capture a proven procedure so it runs the same way every time </Card> <Card title="Intents" icon="clipboard-list" href="/chat-agents/intents"> Consistent intake for the requests you see over and over </Card> </CardGroup> # Technician-in-the-Loop Source: https://docs.neoagent.io/core/technician-in-the-loop Pause Neo before risky actions (emails, scripts, PSA edits) and require technician approval via Teams card or Neo Inbox. Set up approvers, flag sensitive tools, and review the approve / reject / feedback flow. Technician-in-the-Loop (TIL) pauses Neo before risky actions—sending emails, running scripts, editing PSA records—and waits for a technician to approve, reject, or comment. Every decision is logged on the ticket. <Frame> <img alt="Approval card showing ticket context and Approve / Reject buttons" /> </Frame> ## Quick setup 1. **Add approvers** – Enable the *Request Technician-in-the-Loop* tool and pick who receives cards: technicians, Teams channels and group chats, or both. A technician shows up in the picker once they add the **Neo Agent** app in Microsoft Teams, or a Teams admin installs it for everyone ([Install the app](/integrations/teams/intro#install-the-app)). If someone who installed the app still does not appear, they send it one message. A channel or group chat shows up once the app is added to it ([Approvals in a Teams channel or chat](#approvals-in-a-teams-channel-or-chat)). 2. **Flag tools** – Toggle **Require technician approval** on sensitive tools (Send Message, Execute RMM Script, etc.). ### Approvers from another workspace For the agent's approval tool, you can select a technician from another Microsoft directory once they have accepted an invitation to the workspace and registered the **Neo Agent** app in their own Microsoft Teams account. They do not need a second Microsoft account in your directory. Approval cards arrive in their own Teams chat, and their decisions apply to the workspace that raised the request. Removing their workspace access stops further delivery and approval of its cards. Ordinary Teams notification recipients and legacy action pickers still use your connected directory. The approver pickers on the Ticket Dispatch, Find RMM Script and L1 Engineer actions list only the people in that directory who use the **Neo Agent** app in Teams, because only that app delivers approval cards. To add someone who is missing, ask them to open the Neo Agent app in Teams and send it one message. ### When an approver gets no card Every person who receives approval cards needs the **Neo Agent** app in Microsoft Teams, whether they are in your own directory or another one. Someone who has only chatted with another Neo bot in Teams, such as your internal or white-label bot, gets no card. Dashboard access alone does not change this. To fix it, they open the Neo Agent app in Teams and send it one message. If an admin removed them from Neo in Teams, a message does not bring them back: ask the Neo Support Agent to restore them (see [Remove someone from Neo in Teams](/integrations/teams/intro#remove-someone-from-neo-in-teams)). Later approvals then reach them. The fix does not resend a card that already failed, so approve that request on the **Approvals** page. When no approver gets a card, Neo alerts your admins and names each person who can't receive cards. ### Approvals in a Teams channel or chat When several people share one approval queue, such as a team of dispatchers, send the card to a Teams channel or group chat instead of to each person. Pick it in **Teams channels & chats that can approve** on the approval tool, or in **Teams channels & chats** on the Ticket Dispatch action. * Neo posts one card in each channel or chat you pick. Anyone who can see it can answer it, and the first answer wins. Neo records the person who answered. * When the request is answered, the card changes to show the outcome for everyone in the channel. * The Neo app must be in the channel or chat first. See [Post to a Teams channel or chat](/integrations/teams/intro#post-to-a-teams-channel-or-chat). * If you remove a channel from the picker in the dashboard, Neo stops sending cards to it, and its pending cards can no longer be answered there. The dashboard Approvals page still works. * A supervised run started with **Run Now** asks only the approvers you pick for that run, never the tool's channels. You can mix people and channels. Each person still gets their own card in their own chat. ## Where approval can be required There are four separate places approval gets switched on, and they differ in how wide they reach: | Where | Scope | | - | - | | **A tool** – *Require technician approval* on Send Message, Execute RMM Script, etc. | That one tool. | | **An integration permission group** – *Require technician approval* on a group like Autotask **Tickets** or **Client-Facing Ticket Notes** | **Every write the group covers.** | | **The agent's own instructions** – "ask for approval before you email a customer" | Exactly what the instruction describes. | | **A supervised run** – the agent's [supervised runs](#supervised-runs) setting | **Every change the agent makes**, each with its own approval. One card covers one record, so the ticket's own notes, time entries and field changes share a card. | <Warning> A permission group is the smallest unit the integration toggle can set — there is no create-only or close-only setting. The **Tickets** group covers creating a ticket, updating its fields, changing its status **and closing it**. So turning approval on to review new tickets also means the agent must be approved to close one. This matters most for an agent whose last step is a ticket write. If the approval you grant describes creating tickets and sending notifications, it does not cover the close at the end of the run — that step stops and waits, and the run finishes without it. Either approve the closing step too, or put the narrower rule in the agent's instructions and leave the group flag off. </Warning> If an agent quietly stops doing its final step some days after you changed a setting, check the agent's **version history** for a permission change around that date. ## What happens next * **Approve** – Neo immediately executes the action. Before each approved call runs, Neo checks it against what the card describes. The check also reads the calls the agent made since the run last started or resumed (in a chat, since the last message), so a value one of those calls looked up for the approved target can count as the one you approved: the status you named, sent as its id, or the user a search returned. A lookup made before the agent asked for your approval is not part of the check. These calls never add to what you approved. * **Reject** – The workflow stops and logs the rejection. * **Add a note** – Opens a comment box with two options: * *Ask for changes* – Neo does **not** execute the action. It reads your comment and either sends you a new approval request that reflects the change, or — when your comment rules the action out, or the ticket has moved on while Neo was reading it — writes what it concluded in the run and sends no further request. Nothing runs until you approve a new request. Use this when the plan is close but wrong in a way you can name. A card identical to the one you commented on is not an expected answer — report it if you see one. * *Approve with note* – Neo incorporates your comment and executes the action now, without showing you the revised version first. This authorizes the action. * **Open run** – When you can open the run this request belongs to, the card links to it in the dashboard, so you can see what the agent read and did before it asked. On an agent's approval card the link stays after you answer, because that is when you most want it; a dispatch or script card keeps it only while it waits. On the run page, **Run now** starts the agent again, on the same ticket and already filled in when the run had one — use it when Neo stood down and you want it to look again. When the ticket is done, click **Train** on the run's row in [Executions](/product/executions) and say what should change. Neo Support proposes an edit to the agent, and applies it when you confirm. You can edit the agent while a run waits for you. If the plan shows the agent lacks a permission, grant it in the agent's settings, then approve or comment. The run picks up where it stopped, with the new permissions, tools and instructions. Later runs on the same ticket use them too. ### If nobody answers A request waits until someone answers it. Neo has no approval timeout, and the run does nothing while it waits: an instruction such as "if nobody approves in 30 minutes, ask Sam; use Delay to wait" never reaches its second step. To bring in a second approver after a set time, have the agent schedule a check-back on the same ticket. The agent needs the [Trigger or Schedule Workflow](/agents/tools/management/trigger-or-schedule-workflow) tool with self-scheduling allowed (the default), and the [Send Teams Message](/agents/tools/communication/send-teams-message) tool with Sam allowed under **Users**. That list holds people in your own workspace who use the Neo app in Teams, so the recipe does not reach an approver from another workspace. Add to its instructions: > Before you send the approval request, use Trigger or Schedule Workflow to schedule this agent on > the same ticket for 30 minutes later, with the instructions "Escalation check only for this > ticket's approval request. Use Get Technician-in-the-Loop Approval Status. If it is still pending, > use Send Teams Message to Internal Team to ask Sam to approve or reject it on the Approvals page. > Do nothing else." Schedule the check-back before the request: once the request is pending, the agent finishes its turn. The check-back does not work for an agent with [supervised runs](#supervised-runs) on: each of its runs reads only the approval requests it raised itself. The check-back is a full run of the agent, so keep "Do nothing else" in its instructions. It runs, and uses credits like any other run of the agent, for every request, also one answered in time. When Sam answers the first request, the original run continues with its plan. Sam can answer it on the Approvals page when Sam is one of its approvers or a dashboard admin. Approval cards show the **ticket number** you recognise (e.g. `T20260319.0091`), not an internal id. When an agent asks you to approve a change that sends or writes a password, API key, token or one-time code, the agent is instructed to show a placeholder in place of the value, such as `<initial password set on jane@contoso.com in the approved user creation>`. The change still uses the real value. This is an instruction, not a filter: reject a request that shows a secret. ## Requests with a list of calls When an agent must make the same kind of change many times, such as deleting 77 memories that a search returned, it can put the exact list of calls in the request. Each call has a short label, such as the name of the memory it deletes. You approve the list, not only a sentence that describes it. If Neo cannot put a call on the list, such as a script, it leaves that call off and still sends the request; the request text describes it. * **On the Teams card** – the card shows the number of planned calls and the first 10 labels. **Show all** opens the rest on the card when the list fits. **Open the full plan** opens the request on the dashboard **Approvals** page. A very long list, or a long request text, can leave room on the card for fewer labels; the count and the link always stay. * **In a Teams or Slack chat with the agent** – the card shows the count, the first 10 labels and the **Open the full plan** link. In Teams, a long request text can leave room for fewer labels; the count and the link always stay. * **On the dashboard** – the **Approvals** page lists every call: its label, the exact method and path for an API call or the tool name for a dedicated tool, and any other input that decides the call, such as the customer. After you approve without a note, each call shows how many times it passed the approval check (**Used 2×**) or **Not used yet**, when you can view the agent that asked. The run shows each call's result. Filter the list to see only the calls that are used, or only those that are not. The run page and the chat card show the first 10 labels, with a link to the full list. When you approve the request without a note, Neo can make each listed call with no further check, and make it again if it must (for example, to retry after an error). A call that matches no listed item goes through the usual approval check. *Approve with note* uses no item: each call goes through the usual check, which reads your note. Reject the request if any call on the list is wrong, or use *Ask for changes* and say which calls to drop. ## Supervised runs A supervised run is a live run of an agent in which every change waits for a technician's approval, one change at a time. The agent works on real tickets and reads real data, and nothing changes until you approve it, so it sits between test mode and letting an agent run on its own. Supervise a single run from **Run now**, or every run from the agent's **Overview** tab. [Supervised mode](/core/supervised-mode) has the whole picture: how it differs from test mode, what each approval covers, and what supervision does not reach. ## Approvals in the dashboard Beyond the Teams card and Neo Inbox, the dashboard has a dedicated **Approvals** page that lists every request waiting on a decision, so you can act on them in one place instead of hunting through chats. * **Queue at a glance** – header cards show how many requests are waiting on a decision, how many were resolved in the last 7 days, and the median time a request waits for its decision. * **Pending / Resolved / All** tabs, with the agent, ticket, and request detail for each. * **Approve** or **Reject** inline, with an optional note (a note on an approval is recorded as a comment, the same as the card's *Approve with note*). * **Open run** – A request links to its run when you can open it, the same as the card's **Open run** button. * **Planned calls** – A request that lists its calls shows every call and, when you can view the agent that asked, how many times it passed the approval check. See [Requests with a list of calls](#requests-with-a-list-of-calls). * **Bulk decisions** – Select individual pending requests or all loaded pending requests, then approve or reject up to 50 at once. Review the confirmation summary and optionally apply the same note to every selected request. A request with a list of calls cannot be selected: open it and decide on it alone, where its list is shown. * **Who sees what** – Technicians see and decide the requests they're an eligible approver on; admins see and decide every request for the team, including who is eligible to approve each one. If you are not an admin, a link to a request that went to someone else opens as "not found". The same rule applies when you ask the Neo Support agent to approve or reject a request, and to the public API. A request raised in your own chat stays yours to answer there. Decisions made here resolve the request everywhere — the Teams card updates and the agent resumes — exactly as if you'd clicked the card. ## Dispatch approval modes The **Ticket Dispatch** action has its own human-in-the-loop setting with three modes — dispatch autonomously, ask before every assignment, or ask only when Neo hits a genuine dilemma (an SLA it can't meet, a needed double-booking, conflicting instructions). Dispatch questions come with concrete options to pick from, or you can tell Neo what to do in your own words. See [Human in the loop on Ticket Dispatch](/building-automations/actions/ai/ticket-dispatch-suggest-technician#human-in-the-loop-approvals). # Advanced: Time entry triggers and processing Source: https://docs.neoagent.io/core/triggers-and-schedules/advanced-time-entry-triggers Configure workflows that respond to and process time entries Set a workflow's entry point to react when a new time entry is posted. Filters can narrow entries by queue, company, work type, or content. <Frame> <img alt="Time entry trigger configuration" /> </Frame> # Triggers and schedules Source: https://docs.neoagent.io/core/triggers-and-schedules/intro Understand event-based vs time-based automation and when to use each ## Overview Automation in Neo Agent runs in two ways: event-based triggers and time-based schedules. Triggers react to PSA events as they happen. Schedules run at set cadences. <Tip> Use triggers when you need immediate reactions to changes. Use schedules for periodic reviews, cleanups, or batched processing. </Tip> <Frame> <img alt="Trigger configuration options for ticket, time entry, and other PSA events" /> </Frame> ## Triggered vs scheduled * **Triggered workflows**: Start instantly when a defined event occurs (for example, ticket created, ticket closed, time entry posted). * **Scheduled workflows**: Start on a fixed cadence (for example, every 5 minutes, hourly, daily) and evaluate matching items at run time. <Tip> Favor triggered workflows for near-real-time actions (assignment, notifications, escalations). Favor scheduled workflows for periodic grooming (SLA sweeps, stale ticket cleanup, backlog reviews). </Tip> ## Example scenarios * **Triggered**: Auto-assign new P1 incidents from specific queues. * **Triggered**: Comment on tickets when end users reply after hours. * **Scheduled**: Close tickets in "Pending Customer" older than 14 days. * **Scheduled**: Recalculate priorities for open requests each morning. * **Scheduled agent**: Scan for new M365 admin role assignments daily and alert on unauthorized changes. * **Scheduled agent**: Disable accounts inactive for 90+ days across connected tenants. <Info> Scheduled agents run on a cadence **without processing a specific ticket**. They're ideal for proactive M365 administration, compliance audits, and recurring maintenance. See [Scheduled Agents](/core/scheduled-agents) to learn more. </Info> ## Design guidelines <AccordionGroup> <Accordion title="Choosing the right entry point"> If the action must happen immediately after an event, use a trigger. If you need to scan a set of items (for example, all open tickets) on a cadence, use a schedule. </Accordion> <Accordion title="Controlling scope with filters"> Both triggers and schedules support deterministic and AI-assisted filters. Start with deterministic criteria for predictability, then layer AI filters to reduce noise. </Accordion> <Accordion title="Avoiding duplicate work"> For scheduled runs, write actions idempotently and track markers (labels, custom fields, comments) to prevent repeating the same change. </Accordion> </AccordionGroup> # Scheduled workflows Source: https://docs.neoagent.io/core/triggers-and-schedules/scheduled-workflows Run workflows on a cadence (every N minutes, hourly, daily) to scan and act on items — SLA sweeps, stale-ticket cleanup, end-of-day reviews, weekly audits. ## What it is Scheduled workflows run at defined intervals (for example, every 5 minutes, hourly, daily). At each run, they evaluate items using your filters and then execute actions for matching items. <Tip> For agents that don't process tickets — like proactive M365 audits or recurring compliance checks — see [Scheduled Agents](/core/scheduled-agents). Those agents bill **per tool call**, not 1 credit per ticket; the table is on [Tool credit costs](/agents/tools/credit-costs). </Tip> <Frame> <img alt="Schedule configuration showing cadence selection" /> </Frame> ## Scheduling patterns * Hourly housekeeping for queues with high volume * Morning reviews to triage stale tickets * End-of-day cleanup to close resolved items awaiting confirmation * Weekly audits to enforce policy compliance ## Cadence tips <Tip> Pick the slowest cadence that still meets your objectives. Faster cadences can increase API load and duplicate work if actions are not idempotent. </Tip> <Note> Use updated-time windows in filters to avoid reprocessing the same items every run. </Note> ## Verification <Steps> <Step title="Set a narrow scope"> Target a specific queue or label to limit impact while testing. </Step> <Step title="Run one cycle"> Manually wait for the next run and review Executions for the schedule. </Step> <Step title="Confirm item counts"> Compare the number of matches with your expectations. Adjust filters until counts align. </Step> </Steps> ## Troubleshooting <AccordionGroup> <Accordion title="No items processed"> Loosen filters or widen the time window. Verify source integration permissions and data visibility. </Accordion> <Accordion title="Duplicate actions on the same items"> Make actions idempotent and add markers (labels, status comments) to detect prior runs. </Accordion> <Accordion title="Cadence too fast or too slow"> Adjust frequency and window size together. For example, hourly runs with a 70-minute updated window provide overlap without gaps. </Accordion> </AccordionGroup> # Triggered workflows Source: https://docs.neoagent.io/core/triggers-and-schedules/triggered-workflows Trigger a workflow on PSA events (ticket created, status changed, time entry posted), and how custom fields / UDFs work in triggers and filters. Covers multiple triggers via OR, run-once-per-ticket, sequential processing, and business-hours / weekend execution windows. ## What it is Triggered workflows start automatically when a specific event occurs in your PSA, such as a ticket being created, updated, or closed, or when a time entry is posted. They enable near-real-time automation. <Frame> <img alt="Ticket created trigger configuration" /> </Frame> ## Common use cases * Auto-assign new incidents by queue, priority, or keywords * Route after-hours requests to on-call channels * Add comments when tickets lack required information * Enforce required fields when closing tickets ## How it runs <Steps> <Step title="An event occurs"> Your PSA emits an event (for example, ticket created). NeoAgent receives the event. </Step> <Step title="Filters apply"> Deterministic rules run first, then optional AI filters. If an item matches, the workflow proceeds. </Step> <Step title="Actions execute"> Actions run in order. Use safe ordering (validate, comment, then modify fields) to reduce risk. </Step> <Step title="Results recorded"> Outputs and any errors appear in Executions for traceability. </Step> </Steps> ## Verification <Check> Create a test ticket that matches your filters. Confirm the workflow appears in Executions, and the expected actions completed in sequence. </Check> ## Configuration options Beyond selecting the trigger event, you have several options to fine-tune when and how your triggered workflow executes: ### Multiple triggers You can define multiple trigger conditions for a ticket using the `+ OR` button. For example, a workflow could run if: * A ticket is created, OR * Its status changes to "Pending Customer" ### Run once per ticket Enable this option to ensure a workflow runs only once for each unique ticket, even if the trigger condition is met multiple times for that same ticket. This prevents repeated executions for the same underlying cause on the same ticket. ### Process entities sequentially Enable this option to process entities (tickets, time entries, etc.) in the order they are received, one by one. This is crucial for workflows where the outcome of processing one entity can affect how subsequent entities should be handled, or where simultaneous processing could lead to conflicts. <Tip> Sequential processing is especially important for ticket dispatch and merge operations where timing and order matter. </Tip> Here are some examples where sequential processing is beneficial: <AccordionGroup> <Accordion title="Ticket dispatch"> When multiple new tickets arrive around the same time, processing them sequentially ensures that the dispatch logic has the most up-to-date information about technician availability and current workload. This prevents scenarios where multiple tickets are assigned to the same technician simultaneously because the system hasn't yet registered the first assignment. </Accordion> <Accordion title="Ticket merge"> If two tickets (Ticket A and Ticket B) are created very close in time and are candidates for merging, sequential processing prevents a race condition. Without it, the system might try to merge Ticket A into Ticket B, and simultaneously merge Ticket B into Ticket A, leading to errors or an inconsistent state. </Accordion> </AccordionGroup> ### Execution window * **Exclude weekends**: Prevent the workflow from running on Saturdays and Sundays * **Only run during these hours**: Define a specific time window (e.g., 9:00 AM to 5:00 PM) during which the workflow is allowed to execute. If a trigger event occurs outside these hours, it will be ignored * **Timezone**: Specify the timezone that the "Exclude Weekends" and "Only run during these hours" restrictions should adhere to. This ensures consistent behavior across different geographical locations ## Supported trigger events A triggered workflow fires on one of a fixed set of PSA events. When you configure a trigger, you choose from: * **Ticket created** * **Ticket updated** — any change, or narrowed to a change of one **standard field**: status, priority, board / queue, or ticket type * **Customer replied** to the ticket * **Technician replied** to the customer * **Note added** to the ticket — any note (public or internal) from any non-Neo author, including customer notes and system/automation notes * **Technician added a note** — a **human technician** added a note (public or internal). Unlike **Note added**, this skips customer notes and system/workflow/automation notes (e.g. Autotask workflow rule notes), so it's the credit-efficient choice for "react when a tech documents work" agents such as automatic time entry. On ServiceNow, only internal **work notes** fire this trigger — ServiceNow doesn't record who authored a public comment, so those are left to **Technician replied to customer** to avoid firing on customer comments * **Time entry created** on the ticket (see [Time entry triggers](/core/triggers-and-schedules/advanced-time-entry-triggers)) On HaloPSA, **Ticket created** fires on the ticket's own creation only. When you merge a ticket into another one, HaloPSA copies the merged ticket's opening entry onto the target, and a new sender's first email on an existing ticket is logged the same way. Neither fires **Ticket created** on the ticket they land in. On Autotask, a time entry or an internal note changes only the ticket's **Last Activity Date**. Neo therefore subscribes your Autotask ticket webhook to that field when a workflow uses **Time entry created**, **Note added** or **Technician added a note**. Autotask then sends Neo a webhook for every change to a ticket. Neo adds the field at the next scheduled PSA sync, about once a day. Until then a time entry or an internal note fires such a trigger only when another change to the ticket arrives; a customer-visible note fires it as before. **Note added** and **Technician added a note** run the workflow at most once per change Neo processes, like every other trigger. Neo records each note it has seen on a ticket, so a later change to the same ticket does not run the workflow again for that note; notes that arrive together share one run. On the first change Neo sees for a ticket, it looks back 24 hours for notes, the same window it uses for every other ticket event. * **Another workflow finished** — chain one workflow off another This list is exhaustive: if an event isn't on it, Neo can't trigger on it. **What the agent is told about its trigger.** Each run tells the agent which of these events started it, for example "a technician added a note to the ticket" or "the customer replied on the ticket". It does not say which note or reply started the run, and does not quote it. **A trigger that matches while the agent is still running on that ticket.** An agent has one run at a time on a ticket, and Neo starts no second run while it runs. Two triggers reach the running agent instead: **Customer replied**, and **Ticket updated** narrowed to a field, such as Status changing to a value you picked. The running agent takes one more pass when its current pass ends, reads the ticket again, and sees the reply or the new field value. So a ticket that leaves a status and comes back while the agent waits still gets handled. Executions shows this as the same run, which ends later. A field change gives a run at most one extra pass. On ConnectWise, Autotask, HaloPSA and Syncro, a field change the agent made itself through its PSA tool gives none; a change from a script the agent ran, or any change on ServiceNow, can still give that one pass. An agent with **Run Agent only once per ticket** on takes no extra pass, and a workflow of fixed actions takes none for a field change. Any other trigger that matches while the agent runs on the ticket starts nothing, and the running agent sees that change only if it reads the ticket after it. With [Process entities sequentially](#process-entities-sequentially) on, none of this applies: each match queues a new run, which starts after the current run ends. ### Narrowing a Ticket updated trigger to specific values When you narrow **Ticket updated** to a standard field, **From value** and **To value** limit the trigger to specific values of that field. Leave either blank to match any value. Add more than one value to match any of them. Pick from the dropdown, or type a value and press Enter. Type the value exactly as your PSA shows it; matching ignores upper and lower case. Type it in when your PSA uses a value the dropdown does not list. On ServiceNow, the **Status** dropdown covers the states of every ticket type — incident, request, request item (RITM), task, change request and problem. Request items use their own states, such as **Work in Progress** and **Awaiting Approval**. <Note> **What counts as a customer reply on ConnectWise.** ConnectWise records a customer's reply and a technician's own client-facing note in the same way, so Neo pairs the event with the note behind it before firing. The note has to be one ConnectWise attributes to a **contact**. A reply from an address that is also a ConnectWise **member** is attributed to that member, which makes it a technician note, so **Customer replied** does not fire for it. That is ConnectWise's own classification, and it is what keeps a technician's note — and Neo's own reply — from starting the agent again. It surprises people testing from their own work mailbox: see [Testing an agent before you trust it](/core/agents#testing-an-agent-before-you-trust-it). Replies from senders ConnectWise holds as neither a contact nor a member, such as a colleague copied into the thread, are a separate setting: **Replies from unregistered contacts**. It is on the trigger, not on the ConnectWise integration page. Open the agent's **Triggers & Filters** tab, or a workflow's **Schedule/Select** step, and add a **Customer replied** condition. Below the conditions, next to "In ConnectWise, a reply only counts when the sender is a registered contact", click **Configure**, turn on **Let these replies trigger your agents and workflows**, and save. You can also ask the Neo Support Agent to turn it on or to edit the **Exceptions** list for you. The switch and its **Exceptions** list are account-wide: they apply to every ConnectWise agent and workflow, not only the one you opened them from. Turning the switch on also lets other mail on a ticket count as a reply, such as a supplier's helpdesk auto-acknowledgement, so add those senders to **Exceptions**. Neo applies the switch when it processes a reply, so a reply it already skipped does not start an agent later. The email that opens a ticket is not a reply. ConnectWise records a ticket's first note in the same way as a reply, so when a customer's note is the ticket's first and was written within 15 seconds of the ticket's creation, Neo leaves it out and **Customer replied** does not fire for it. A first customer note written later counts as a reply. To start an agent on new tickets, use a **Ticket created** trigger. </Note> <Note> **The trigger event and Filter Ticket settings gate PSA events, not direct hand-offs from another agent.** When another agent invokes this workflow with the [Trigger or Schedule Workflow](/agents/tools/management/trigger-or-schedule-workflow) tool, the hand-off skips this workflow's configured trigger event, its Filter Ticket conditions, and its execution window. Only **Enabled**, **Triggered type**, and **entity type** still apply. A workflow set to **Manual only** can therefore still be invoked by another agent. To control which tickets get handed off, control it on the source agent — see [Which target settings apply to a direct invocation](/agents/tools/management/trigger-or-schedule-workflow#which-target-settings-apply-to-a-direct-invocation). </Note> ### Custom fields and UDFs are not trigger events There is no "custom field changed" trigger, and a custom field / UDF cannot be the standard field that narrows a **Ticket updated** trigger — that is limited to status, priority, board / queue, and type. To act on a custom field, trigger on **Ticket created** or **Ticket updated** and add a **filter condition** on it. Filter conditions match any PSA field by its exact name, including custom fields and UDFs — see [Filter tickets](/core/filter-tickets) and the [Configuration reference](/core/configuration-reference). <Warning> A filter condition checks a custom field's **current value** (for example, `My UDF equals "Yes"`) — it does not detect that the field just changed. A **Ticket updated** trigger with a UDF filter runs whenever the ticket is updated and the UDF currently matches, not only when the UDF itself was the field that changed. </Warning> ## Gotchas and tips <AccordionGroup> <Accordion title="Avoid race conditions"> When multiple workflows target the same field, set clear ordering and use conditions to prevent ping-pong updates. </Accordion> <Accordion title="Idempotency matters"> Design actions so re-running them is safe. Use markers like labels or comments to detect previous runs. </Accordion> <Accordion title="Narrow filters before expanding"> Start with a tight scope (specific queue or company) to validate. Expand only after consistent results. </Accordion> <Accordion title="Handling missing data"> If required fields are absent, prefer commenting and requesting info rather than failing silently. </Accordion> </AccordionGroup> ## Visual confirmation <Frame> <img alt="Event history showing a completed triggered workflow" /> </Frame> # Workflows Source: https://docs.neoagent.io/core/workflows Automated sequences of actions that process tickets, update data, and notify users Workflows execute a sequence of [actions](/core/actions) that can be triggered or scheduled to run on a regular basis. It's a great way to automate repetitive tasks that always need to happen regardless of an incoming ticket's context (i.e ticket triage, dispatching tickets to technicians, etc.) <Tip> Not sure whether your use case belongs in a workflow or an [agent](/core/agents)? See [Workflows vs Agents](/core/workflows-vs-agents). </Tip> ## Building Your First Workflow Watch the following 1-min video to get started with setting up your first workflow with Neo Agent: <iframe title="Workflows Demo" /> To get an email on a day a workflow uses far more credits than usual, switch on **Daily Credit Alert** on the **Review & Launch** step. [A daily credit alert for one agent](/product/billing-and-credits#a-daily-credit-alert-for-one-agent) explains how Neo sets its cap. ## Best Practices <CardGroup> <Card title="Start simple" icon="vial"> Setup a workflow with a single action (i.e Ticket Triage) so you can see how Neo works in your environment </Card> <Card title="Review the workflow's decisions" icon="eye"> Monitor workflow decisions closely when first deployed to ensure quality on the Executions page. </Card> <Card title="Iterate based on feedback" icon="pen-to-square"> Refine the workflow's filters and actions so it's aligned with what you want it to do. </Card> </CardGroup> # Workflows vs Agents Source: https://docs.neoagent.io/core/workflows-vs-agents When to build a workflow (smart actions) versus an agent — start with workflows for the jobs Neo has optimized smart actions for, use agents for everything else. Both [workflows](/core/workflows) and [agents](/core/agents) run automatically when a ticket arrives (or on a schedule). The choice is *which one fires*: a fixed sequence of [smart actions](/core/actions) or an agent that picks tools at runtime. <Note> There's a third kind: [chat agents](/chat-agents/overview), which don't fire on events at all — a person messages them. This page compares the two automatic kinds; if a human initiates the work, you want a chat agent. </Note> ## The rule of thumb **Default to a workflow when Neo ships a smart action for the job.** Smart actions like [Ticket Triage](/building-automations/actions/ai/ticket-triage), [Dispatch Ticket](/building-automations/actions/ai/ticket-dispatch-suggest-technician), [Suggest Resolution](/building-automations/actions/ai/suggest-resolution), [Escalate Ticket](/building-automations/actions/ai/ticket-escalation), and [Find Ticket to Merge With](/building-automations/actions/ai/find-ticket-to-merge-with) carry prompting and guardrails Neo has tuned across many MSPs. An agent built to do the same job inherits none of that — you'd be teaching it the same task from scratch through custom instructions, and quality typically drops. **Use an agent for everything else** — jobs where no smart action exists, or where runtime tool-picking is the actual value (open-ended L1 troubleshooting, multi-step Microsoft 365 ops, documentation, QA audits, scheduled cross-system reports). A [scheduled agent](/core/scheduled-agents) with no ticket bills **per tool call**, not once per run — see [Tool credit costs](/agents/tools/credit-costs) before you iterate by re-running it. ## Decision table | Job | Default | When to switch | | - | - | - | | **Triage** — classify type / subtype / priority / queue | Workflow — [Ticket Triage](/building-automations/actions/ai/ticket-triage) | Switch to an agent only if the routing logic becomes too complex for the smart action's settings to express | | **Dispatch** — pick the right technician | Workflow — [Dispatch Ticket](/building-automations/actions/ai/ticket-dispatch-suggest-technician) | Switch to an agent only if the routing logic becomes too complex for the smart action's settings to express | | **Resolution suggestion** — one-shot: search KB + similar tickets, write an internal note | Workflow — [Suggest Resolution](/building-automations/actions/ai/suggest-resolution) | Switch to an agent if you want **end-user communication, RMM script invocation, or follow-up loops** (anything beyond writing a single note to the technician) | | **Escalation** — route urgent / SLA-breach tickets | Workflow — [Escalate Ticket](/building-automations/actions/ai/ticket-escalation) | Switch to an agent only if the routing logic becomes too complex for the smart action's settings to express | | **Merge duplicates** — detect dupes, merge into parent | Workflow — [Find Ticket to Merge With](/building-automations/actions/ai/find-ticket-to-merge-with) + Merge Ticket | Switch to an agent only if the routing logic becomes too complex for the smart action's settings to express | | **Everything else** — L1 troubleshooting, M365 ops, documentation, QA / audits, scheduled reports | Agent | n/a — no smart action exists; the agent's runtime flexibility is the point | ## Why workflows win for the first five Neo's smart actions are tuned **across every MSP using Neo** — every prompt improvement Neo ships to Ticket Triage benefits every MSP running Ticket Triage. They're also: * **Cheaper** — a single deterministic call per ticket, not an LLM choosing between tools. * **More predictable** — same input, same output structure, every time. * **Easier to debug** — a linear trace, not a branching agent transcript. An agent built to do the same job has to be re-taught the rules through `custom_instructions`, runs without Neo's guardrails, and tends to either over-explain or under-decide. ## Why agents win for everything else For open-ended jobs, the agent's value *is* picking tools at runtime: * **L1 troubleshooting** — read the ticket, check RMM device state, search past tickets, optionally run a script, reply to the user. * **Microsoft 365 operations** — user offboarding, license reconciliation, mailbox permission audits, environment documentation. * **Documentation** — write SOPs into IT Glue or Hudu, audit existing records for staleness. * **QA and audits** — review past tickets or time entries against a policy. * **Scheduled reports** — pull data across PSA, M365, and RMM, summarize for the team. For these, no workflow path exists — there's no smart action for "offboard a Microsoft 365 user" or "write an SOP". The agent picks the tools it needs and chains them. # Writing effective agent instructions Source: https://docs.neoagent.io/core/writing-agent-instructions How to write custom instructions that make a Neo agent behave the way you need — what to put in, what to leave out, and the patterns power users rely on. Custom instructions are the biggest lever you have on how well a [Neo agent](/core/agents) performs. They're the free-text guidance you write in the agent editor, and Neo loads them as the agent's **highest-priority** direction — they outrank Neo's built-in skills and default behavior. Good instructions are the difference between an agent that works tickets like your best technician and one that guesses. This page applies to every agent driven by your instructions: [ticket and scheduled agents](/core/agents) and [chat agents](/chat-agents/building-a-chat-agent). They all share the same custom instructions field. <Tip> In a hurry? Click **Adjust with Neo** (inside the instructions box while it still holds the short starter line, next to the Custom Instructions title otherwise) and tell Neo what the agent should do. It drafts the instructions with you, following everything on this page, and on a new agent it works out the trigger, filter and tools too. See [Let Neo draft them for you](#let-neo-draft-them-for-you). </Tip> ## Start with what's unique to you The most common mistake is telling the agent things it already knows. Neo ships with built-in [skills](/agents/skills/overview) — diagnosis methodology, end-user communication, PSA and Microsoft 365 know-how — and sensible defaults. Your instructions sit *on top* of those and win wherever they conflict. So spend your words on what's specific to **your** MSP: your processes, your decision rules, your guardrails, your tone. Don't restate things Neo already does: | Already handled by Neo | So don't write… | | - | - | | Searching documentation and past tickets | "Search the knowledge base for the answer" | | Adding notes and logging time | "Remember to log your time" | | Professional tone and plain language | "Be professional and polite" | | Keeping customer data safe | "Don't leak personal information" | | Not promising specific timelines | "Don't over-promise on timing" | | Choosing which tool to use for a task | "Call the ticket-update tool, then the note tool" | Everything you *don't* have to write is room for the guidance that actually matters. <Note> Custom instructions are per-agent and apply to every company that agent serves. To add rules for one **specific client** — their escalation contact, their preferred tone, their custom-field conventions — use [Memory](/core/memory) instead. Both are "your instructions" and both override skills. </Note> ## Say what to do and where the limits are — usually not how This is the most important default to get right — it's where most instructions go astray. Your agent already has its tools, and it picks the right one at runtime from each tool's description. **As a default — especially when you're starting out — describe the outcome and the guardrails, and leave the mechanics to the agent.** Reaching for specific tools, API endpoints, HTTP methods, PowerShell cmdlets, or raw system field names tends to make instructions more brittle, can box the agent in, and is easy to get subtly wrong. Saying *what you want* is usually shorter and survives product changes, PSA differences, and new tools. <CodeGroup> ```text ✅ Do theme={null} Create the new user in Microsoft 365, assign the standard license for their department, and add them to the right distribution groups. If the ticket doesn't say which department, ask before creating the account. ``` ```text ❌ Don't theme={null} Call POST /users to create the account, then run New-Mailbox, set userPrincipalName to first.last@..., and use "Get Field Options" to read the license SKU field before PATCHing the user. ``` </CodeGroup> You **can** name a system when it helps routing — "make the change in Microsoft 365", "via the Exchange integration", "in ConnectWise" — and refer to *kinds* of identifiers like email address, UPN, license type, or department group. **This is a guideline, not a hard rule.** If you know exactly what you want and why, getting specific is fair game — pin a particular endpoint, cmdlet, or field when you have a concrete reason the agent should take *that* path instead of choosing for itself. It's a legitimate power-user move; just go in knowing the trade-off, and keep those specifics current as the underlying systems change. Start by describing outcomes, and reach for the details when they earn their place. <Tip> A good rule of thumb when you're starting out: could a brand-new technician follow your instructions without you naming a single button or command? If yes, the agent can too. Once you know the systems well, it's fine to get more prescriptive where it pays off. </Tip> <Note> **Don't ask an end-user chat agent to log the conversation onto the ticket.** Once a chat is linked to a ticket, Neo records every message from both sides on it automatically — the user's as customer replies, the agent's as internal notes — turn by turn, with retries, and each message goes to the ticket it is actually about rather than whichever one the chat last touched. When that check can't run — your PSA won't return the ticket it compares against, or the check itself errors — the message is recorded on the ticket the chat was already on (see [What the ticket records](/integrations/teams/end-user-bot#what-the-ticket-records)). An instruction like "log the full conversation" or "add all replies as a note" only confuses the agent — no tool posts a note whose text you dictate, so it either does nothing or files a ticket it shouldn't. What *is* the agent's decision — and worth an instruction — is when a ticket is needed, when to escalate, and when to mark it resolved. Watch for an instruction that answers both questions in one line, such as "wait until the conversation is finished, then add it all as a note". The timing half is a real policy worth keeping; the logging half is the part to drop. [Choose when the bot opens a ticket](/integrations/teams/end-user-bot#choose-when-the-bot-opens-a-ticket) has the three shapes to paste in its place. </Note> ## A structure that works Most strong agents follow the same simple skeleton. You don't need every section, but this order reads well to the model: <Steps> <Step title="Goal — one line"> Open with what this agent accomplishes. Many of the best instructions literally start with `Goal:`. </Step> <Step title="Role — who it is"> Especially for chat agents: "You are a friendly first-line IT support assistant for end users." This frames everything that follows. </Step> <Step title="Steps or decision rules"> The ordered work, as bullets. Keep them short. For branching logic, state the condition, then the action. </Step> <Step title="Guardrails — what never to do"> The hard limits. Be at least as explicit here as in the steps. </Step> <Step title="Escalation — when to hand off"> The conditions that send a ticket to a human, and what to leave behind for them. </Step> <Step title="Output — what to leave behind"> What the agent should record: an internal note, a status change, a customer message. </Step> </Steps> Here's the whole skeleton in one short, tool-agnostic example: ```text theme={null} Goal: resolve password-reset tickets for verified end users. - Verify the requester's identity before any reset. - Reset the password and require a change at next sign-in. - If identity can't be verified, do not reset — add an internal note and escalate to the service desk. - Record what was done on the ticket and let the requester know it's done. ``` That's a complete, effective agent instruction. It names no tools, fits in a few lines, and still covers the goal, the happy path, the guardrail, the escalation, and the output. ## Format your instructions The instructions editor renders formatting as you type, like a document editor — headings look like headings, lists like lists — and structure helps the model follow long instructions. Use the toolbar (headings, bold, lists, quotes, links, code blocks, tables) or type Markdown directly: `## ` starts a heading, `- ` starts a list, `**bold**` bolds, and **⌘B**/**Ctrl+B** and **⌘I**/**Ctrl+I** work as you'd expect. * Pasting from Word, Google Docs, a web page, or a Markdown file keeps your bold text, headings, lists, and tables — nothing is flattened to plain text. * To indent a list item, press **Tab** — **Shift+Tab** moves it back out. Typing `- ` or `1. ` at the start of an item indents it too, so you can type a nested list straight through. The first item of a list has nothing to sit under, so it can't be indented. * Use headings to separate sections (steps, guardrails, escalation) and lists for rules. Bold the words that carry the rule: "**Never** reset without verifying identity." * A line of `=`, `-`, `*` or `_` characters stays exactly as you type it — length and character included. Frame a section header with one if you want the agent's output to carry it. * Prefer to write the Markdown yourself? Switch the box to **Markdown** with the control in its top-right corner and edit the raw text. It is the same text the agent reads, and it saves exactly as you type it — switch back to **Editor** to see it rendered. * The left margin numbers your instructions: the **Markdown** view numbers every line, and the **Editor** view marks the line a heading, paragraph, list item or table starts on. Every number is a line of the saved text, so "change line 14" means the same line in either view and in the Neo Support chat. A block the **Editor** view cannot match to the saved text — a paragraph written with `_italic_`, which the editor writes back as `*italic*`, for example — carries no mark from there down, and the **Markdown** view still numbers it. * Under the hood the instructions are stored as Markdown — the same text the agent reads — so anything you already saved keeps working unchanged. ## Write decision rules, not vibes "Handle urgent tickets quickly" tells the agent nothing it can act on. Give it the actual rule — a threshold, a list, a condition. Specific instructions produce consistent agents. A security-triage agent, for example, classifies every alert with explicit bands instead of "use your judgment": ```text theme={null} Rate each alert and act on the rating: - Red (active compromise — confirmed malware, live lateral movement, data exfiltration): escalate to an engineer immediately and notify the on-call channel. - Amber (suspicious but unconfirmed — repeated failed logins from an unusual location, privilege-escalation attempts): assign to first line with a suggested customer update. Do not page anyone. - Green (expected activity, vendor noise, informational): add an internal note explaining why it's benign, then close. If the evidence is contradictory or the impact is high, don't guess — mark for human review and escalate. ``` The agent can follow that the same way every time. "Be careful with security tickets" it cannot. ### How the agent reads a rule A ticket or scheduled agent reads each rule for what it is meant to achieve, so a rule that does not clearly fit a case is applied the way its author would want. Approvals, holds, what goes to a client, and security rules are followed exactly as written. When a case must always go one way, name it in the rule. A ticket agent also has defaults, and each one gives way to custom instructions that say otherwise. It writes an internal note on each substantive action. It closes a ticket when the end user says the issue is resolved or asks to close it, and sets any other status only when your instructions say so. It stands down when a technician already did the work, takes the ticket over or asks it to stop. ## Guardrails and escalation State the limits as clearly as the work — the best instructions often write the "never" list more emphatically than the "do" list. Cover: * **Hard prohibitions** — "Never make tenant-wide, network-wide, or security-impacting changes." "Don't provide account or password support for the client's line-of-business app (e.g. their accounting or HR system) — only help with installation and updates." * **Security basics for anything customer-facing** — never ask a user to type a password, MFA code, or PIN into the chat; reframe ("can you sign in?", not "what's your password?"). Don't perform account or permission changes yourself — log a ticket and let a technician handle them through a secure channel. * **When to escalate** — the conditions that send a ticket to a human, named concretely: the issue persists after basic checks, it needs configuration access, or it involves safeguarding or sensitive data. Name the route too (a status, a Teams message to a named person). With no route, the agent leaves the open step in its internal note, or in its dashboard summary when it cannot or may not write a note, and messages no one. * **What to leave for the human** — an internal note with what was checked, what's still needed, and the suspected cause, so the technician has full context. ### Wording a hold-until rule A common guardrail holds everything back until some condition is met — an approver has signed off, or the ticket has reached a given status. Word it by what it blocks, because that is what the agent can check. The agent sees each of its tools labelled **writes to client systems** — it can change a PSA record, an identity or RMM object, a mailbox, or send a message to a person — or **read-only**, which changes none of that, or **reads or writes, depending on your request** for the tools that do both, where the agent classifies each call instead of the tool. So a rule phrased in those terms needs no interpretation: ```text theme={null} Do: Make no changes until an authorised approver's approval is recorded on the ticket. You may still search past tickets and documentation. Don't: Before any system lookup, confirm approval is recorded. ``` The second version reads as a stricter rule, but "system lookup" is a category the agent has to map onto its own tools, and a search of Neo's synced ticket data is not obviously in or out. Name writes, or name the changes in your PSA's terms (a status change, a client-facing note), and say which reads stay allowed. Avoid naming tools: tools are renamed and retired, and a rule that names one that is gone sends the agent looking for it. ### Wording a start-of-work step Many agents take ownership first: they assign the ticket to the agent's own PSA resource and set a working status. A step you tie to the start of work runs once per ticket. A later run on the ticket takes only the part that no earlier run did and the ticket still needs, and never replaces an owner someone else set. The step runs before the agent replies to the customer, asks them a question, sets a waiting status or hands the ticket off. A reply that waits for the customer still counts as work on the ticket. A check you attach to the step is its condition: when the check passes, the agent takes the step, and when it fails, the agent skips it. ```text theme={null} Read the ticket with the PSA API tool. Before any ownership or status change, make that same PSA API request again. If the ticket is open and no technician owns it, assign it to Neo Agent and set In Progress. A later handoff to a technician replaces Neo Agent as the owner. ``` When the [PSA API](/agents/tools/psa/psa-api) tool repeats a request it already made in the run, it sends that request to your PSA, so the repeat sees an owner a person or another system set after the first request. Its first request for a record can return a copy from Neo's cache, and [Get Ticket](/agents/tools/search/get-ticket) returns the ticket as the run first read it, so neither one is a live re-read. Name any other case where the agent should skip the step. <Warning> For risky writes — account changes, bulk operations, anything hard to undo — don't rely on instructions alone. Require [Technician-in-the-Loop](/core/technician-in-the-loop) so a human approves before the action runs. Instructions guide the agent; approvals are your safety net. </Warning> ## Tone and customer-facing language For chat agents and any agent that messages end users, write for the *reader* — the end user, not your technicians — and control two things separately: * **Voice** — how it sounds: "Friendly, warm, plain language, no jargon. Brief over verbose." * **What it may and may not claim** — the part teams forget. Tell the agent not to imply work it didn't do, not to commit to specific dates or ETAs, and not to expose internal process: ```text theme={null} Don't: - Say you've "asked the team" or "flagged it" — describe work as in progress, not as something you personally dispatched. - Give specific dates, times, or ETAs. Point timing questions to the support line. - Claim to have emailed, called, or done anything you didn't do. Do: - Acknowledge the request and give the next step in neutral terms. - Be honest if you can't do something, and offer to log a ticket. ``` **Be honest about being an agent.** Don't volunteer it unprompted, but if a user asks directly whether they're talking to a bot, answer truthfully — "I'm an automated support assistant; I handle first-line questions and pass anything hands-on to our techs." Never claim to be human; never deny being automated. ## Keep it concise Aim for the shortest instructions that fully capture your intent. Prefer a tight set of bullets over a long numbered playbook, and cut anything that restates a Neo default or pads the page. Most agents need about a page — a few thousand characters is a good ceiling for everyday agents. Long, sophisticated agents do exist — a senior-technician agent handling a whole queue might run to several pages of decision tables. That's fine *when every line earns its place.* Length should come from real complexity, not from boilerplate. ## Advanced patterns Once the basics are solid, these are the techniques Neo's most advanced customers rely on. Reach for them when an agent's logic is genuinely complex. <AccordionGroup> <Accordion title="Decision tables for multi-factor logic"> When an outcome depends on two or more variables — queue × priority, business hours × severity — a small table is clearer to the model (and to you) than nested prose. List the conditions and the action for each row. </Accordion> <Accordion title="Name the model's failure modes and rule them out"> LLMs can talk themselves into almost anything. If your agent keeps rationalizing the wrong call, legislate against it in plain language. Power users write lines like: *"The bar is 'can the agent finish this end-to-end with no human needed' — not 'does this seem reasonable.' If a technician has to do anything later, escalate instead."* Naming the failure mode is often more effective than adding another rule. </Accordion> <Accordion title="Disambiguate rules that interact"> When two rules could collide, say which wins — explicitly. *"The quiet-hours rule suppresses customer messages, but it does NOT stop escalation: if the ticket needs a human, hand it off regardless."* One sentence here prevents a whole class of wrong decisions. </Accordion> <Accordion title="State the why, not just the rule"> A short rationale helps the agent generalize to cases you didn't list. *"Escalating a ticket that turns out simple costs little; failing to escalate one that needed a human costs a lot — so when in doubt, escalate."* </Accordion> <Accordion title="Re-run safety for agents that fire repeatedly"> An agent that can trigger on its own notes can loop. Sophisticated setups stamp each note with a marker and tell the agent to check for a recent one before acting again — "if you've already processed this ticket in the last few minutes and nothing new has happened, do nothing." If you build multi-step or multi-agent automations, design for repeat runs. </Accordion> <Accordion title="One persona across a fleet"> Running several agents on the same accounts? Give them a shared persona name so every note, time entry, and customer message reads as one consistent technician rather than a committee. </Accordion> <Accordion title="Send a notification only in some cases"> Notification instructions can be conditional. Tell the agent when to stay silent and it sends nothing at all — no blank message, no empty email: *"Post only for P1 and P2 tickets. If the priority is P3 or lower, do not post any message."* Write the silent case explicitly, as its own rule. "Only generate a message if…" works equally well. </Accordion> <Accordion title="Change a field only in some cases"> A triaged field such as Status is decided on every ticket. A rule that only says when to set it, such as "set the status to Complete when …", names no status for the other tickets, so on those Neo still decides the status itself, and can change it. Say what to do with the rest, as its own line: *"When a ticket is a backup success alert, set the status to Complete. For every ticket that matches none of the rules above, keep the current status. Do not change it."* "Only follow these instructions for status" is not enough on its own: it limits which rules apply, and names no status for the other tickets. </Accordion> </AccordionGroup> ## Let Neo draft them for you You don't have to start from a blank box. In the [agent editor](https://dashboard.neoagent.io/agents), **Adjust with Neo** sits inside the instructions box while it still holds the short starter line ("Goal: Resolve the ticket" or "Help the user"), saved or not, and next to the Custom Instructions title otherwise. An end-user chat agent starts with a full policy in the box, so its button is next to the title from the start. One click opens the Neo Support chat, which reads what the agent already holds and opens on options you can click. What it offers depends on where you are: * **A new agent you have not written anything into** — a short intake opens first, in the dashboard rather than the chat, so there is nothing to wait for. It asks what kind of work the agent takes on, shows you the templates in that category in case one already does the job, takes one line about what you want, and asks what starts it. The trigger you pick is written into the builder straight away. Neo then opens with your answers already in hand and asks only what they leave open. * **A new agent you have already started** — Neo reads your draft, names the kind of agent you are building, and offers what to do next for that kind of work. If the draft already reads like working instructions, a review is one of the options. * **A saved agent** — Neo offers three options: * **Add or change a rule**: describe the change. Neo shows the edit, and applies it after you confirm. Before that, it checks the change against the agent's instructions and the MSP-wide [pinned memories](/core/memory#pinned-vs-unpinned) that reach it, plus one company's pinned memories when the change concerns that company, and tells you what it finds: a rule the change contradicts (quoting both), an exception added to an exception, a duplicate, a rule so absolute it blocks common tickets, or a rule that leaves a ticket where nobody sees it when a step fails. Where rules can merge, it proposes one rule instead. You choose which version to apply. * **Check my instructions**: Neo looks for contradictions, including with the MSP-wide pinned memories the agent reads, missing rules and unclear formatting, and changes nothing. If the instructions are fine, it says so, and offers to format them when the formatting could be clearer. * **Turn on the tools it needs**: Neo reads the instructions and proposes the tools and permissions they need, with the line that needs each one. Nothing is turned on until you confirm. On a new agent, Neo proposes the whole thing: the instructions, a name, what it runs on, what starts it, a ticket filter where it knows your real values, the tools the work needs, and the Microsoft 365, Active Directory, Exchange or PSA permissions those tools need to reach anything. Neo ends with a button that sets up the builder you have open. It fills the form without saving it, so anything you configured yourself survives and the save stays yours. Review every part before you save, and fill in any tool setting Neo left for you. Read the permissions row with care: it says which areas the agent may read and which it may change, and which changes ask a technician to approve them first. Whether Neo can also create the agent outright depends on how far you have got in the builder: * **Nothing set up beyond the instructions and the tools you picked** — Neo can create the agent for you, **disabled**, so nothing runs until you review it and switch it on. If you accept, the agent exists: leave the builder without saving, or you will end up with a second copy. * **You have already set a schedule, filters, integration permissions, or settings on a tool** — Neo offers the button and nothing more. Those settings live only in the builder, and an agent created from the chat would not have them. <Note> The button waits for a saved agent to have no unsaved edits, because Neo works from what is stored. Save, then click it. On the Neo Support Agent itself only **Check my instructions** is offered — Neo owns that agent, so its instructions can't be changed from here. </Note> Read what Neo produces, then edit. And browse the [template gallery](/building-automations/managing-workflows/templates): every template ships with well-written instructions you can clone and adapt. ## Test, then iterate Instructions are never one-and-done. The fastest way to improve them is to watch real runs: <Steps> <Step title="Start in test mode"> Turn [test mode](/core/agents#best-practices) on so the agent describes what it *would* do instead of doing it. Read those decisions against what you'd want. </Step> <Step title="Watch real executions"> Review the agent's runs in [Executions](/product/executions) — where did it hesitate, over-reach, or misread a ticket? Each miss points at a missing rule or an ambiguous line. </Step> <Step title="Refine one thing at a time"> Add the rule that would have prevented the miss, then re-test. Small, specific edits beat rewrites. Neo can also [learn from your feedback](/product/train-neo) and suggest instruction refinements automatically. </Step> </Steps> <CardGroup> <Card title="Agents" icon="robot" href="/core/agents"> What agents are and how they work end-to-end </Card> <Card title="Memory" icon="brain" href="/core/memory"> Durable per-client and MSP-wide facts that layer on top of your agent instructions </Card> <Card title="Skills" icon="book-open" href="/agents/skills/overview"> The built-in expertise your instructions sit on top of </Card> <Card title="Technician-in-the-Loop" icon="user-check" href="/core/technician-in-the-loop"> Require human approval before sensitive actions </Card> </CardGroup> # Invite people from another company Source: https://docs.neoagent.io/customizing/external-users Invite external colleagues with their Microsoft work account and grant access to a specific Neo workspace. A workspace admin can invite someone from another company with their name, work email, and workspace role. The recipient does not need to provide Microsoft directory or object IDs. <Steps> <Step title="Open the destination workspace"> Switch to the workspace the person should access, then open its Users page. </Step> <Step title="Send the invitation"> Enter their name and work email, select their role, and send the invitation. Only a workspace owner can invite another owner. </Step> <Step title="Accept with Microsoft sign-in"> The recipient opens the emailed link, signs in with the invited Microsoft work or school account, and selects **Accept invitation**. Personal Microsoft accounts are not supported. </Step> </Steps> Invitation links expire after seven days and work once. Use **Resend invitation** on a pending invitation if needed; the previous link stops working. Cancelling a pending invitation prevents acceptance. People with one workspace membership open it directly. People with several active memberships can use **Switch workspace…**. Their role can differ between workspaces. Revoke access in the destination workspace's Users page. Removing a guest from Microsoft Entra alone does not remove an explicit Neo membership. An invitation grants access to one workspace. It does not place either company under the other's [organization](/customizing/organizations). # Overview Source: https://docs.neoagent.io/customizing/intro Tailor Neo Agent to your unique business needs with custom instructions, external access, and multi-language support <Card title="Memory" icon="brain" href="/core/memory"> Durable facts, playbooks, and preferences Neo recalls at runtime, set per company or MSP-wide for communication tone, procedures, terminology, and escalation points. </Card> <Card title="External Users" icon="user-plus" href="/customizing/external-users"> Learn how to provide Neo Agent access to external users and manage access controls. </Card> <Card title="Multi-Language Support" icon="globe" href="/customizing/multi-language"> Enable automatic translation of customer notifications into French, Dutch, German, Spanish, and more. </Card> # Multi-Language Support Source: https://docs.neoagent.io/customizing/multi-language Serve global clients in their preferred language with AI-powered translation for customer communications ## Supported Languages Neo Agent can translate messages sent to end-users via the "Notify Ticket's Contact" and other Notify Users actions. Currently, the following languages are supported for translation: * **English** (default for all communications if no translation is selected) * **Any other language**. Our AI model supports all languages. <Info> The Neo Agent platform interface itself is currently available in English. Multi-language support primarily applies to communications generated by specific actions. </Info> ## How to Enable for Notifications When configuring the "Notify Ticket's Contact" (or other) action in a workflow: <Steps> <Step title="Enable Translation Option"> Enable the **"Use custom instructions"** option in the action configuration </Step> <Step title="Select Target Language"> In the **"Custom instructions"** field, enter the language you want to use, like "Translate the message to French". </Step> </Steps> <Tip> The same **Custom instructions** field shapes the message in other ways too — tone, length, structure, or which details to include. Translation is one use. </Tip> # Organizations and subsidiary workspaces Source: https://docs.neoagent.io/customizing/organizations See the workspaces that belong to your organization, create subsidiary workspaces, appoint organization administrators, and grant access separately in each workspace. An organization groups the Neo workspaces owned by an MSP. For example, Acme Corp MSP can manage its own workspace and an acquired MSP's workspace under one organization. Each workspace keeps its own members, roles, agents, integrations, data region, and billing. Every workspace belongs to exactly one organization. Neo creates the organization with the first workspace at signup and names it after the company; nobody creates an organization on its own. Active workspace owners became organization owners during the initial migration. Workspace admins do not automatically become organization administrators. If your workspace has no owner, contact Neo to assign an organization owner. ## Open your organization Open [**Organization**](https://dashboard.neoagent.io/organizations) from the account menu. The page shows the organization of the workspace you have open, with its workspaces on the **Workspaces** tab. Any member of the workspace can view this list. The organization is the root of the tree, and each workspace shows its status, data region, and your access. The **Administrators** and **Activity** tabs, the **Create workspace** button, and access grants need an organization role. To look at another organization, open one of its workspaces first. This applies to Neo staff too. ## Organization roles | Role | Permissions | | - | - | | Owner | Create workspaces, grant workspace access, rename the organization, and appoint or remove organization administrators | | Admin | Create workspaces and explicitly grant workspace access up to Admin | | Workspace member without an organization role | View the organization name and its workspaces | Organization administration does not itself grant access to workspace data. On the **Workspaces** tab, use the workspace's three-dot menu and select **Grant workspace access…** to give yourself or another existing member an explicit workspace role. A workspace you cannot open also shows a **Grant access…** button. Only organization owners can grant the workspace Owner role. The person who creates a new workspace becomes its workspace owner. Removing an organization role leaves that person's workspace memberships unchanged. To remove all access, remove the organization role and revoke each workspace membership. Neo prevents removal or demotion of the last organization owner. ## Create a subsidiary workspace <Steps> <Step title="Open the parent workspace"> Switch to a workspace of the organization that will own the subsidiary, then open [**Organization**](https://dashboard.neoagent.io/organizations) from the account menu and stay on the **Workspaces** tab. </Step> <Step title="Create the workspace"> Select **Create workspace** at the top of the **Workspaces** tab. Enter the workspace name and its workspace ID, then pick the timezone, PSA, and data region. The workspace ID is the unique lowercase identifier Neo uses for the workspace, as at signup: letters, digits, and hyphens. Neo fills it in from the name; edit it if you want a different one. The ID is permanent; the name can change later. An ID that another workspace already uses is rejected. You can use the Microsoft directory connected to another workspace in this organization or connect a separate directory later. Under **Invite owners**, you can add the email addresses of up to 10 people who should own the new workspace. Neo skips your own address, because you own the workspace already. Each other person gets an email invitation, valid for 7 days, and accepts it by signing in with Microsoft. After Neo creates the workspace, it shows which invitations it queued. Neo sends the emails in the background. If a person gets no email, or an invitation could not be queued, invite that person again from the new workspace's Users page; the workspace is created either way. </Step> <Step title="Start a trial or choose a plan"> Neo opens the new workspace. It can start its own free trial, or you can choose a paid plan for it from the start. A new workspace gets no Teams support chat of its own; its people get help from the Neo Support agent in the dashboard. Its integrations and credentials start separately; Neo does not copy another workspace's PSA or RMM credentials. </Step> <Step title="Invite its team"> Invite everyone else from the workspace's Users page with their name, work email, and role. They accept the email invitation using Microsoft sign-in. Invitees gain access only to this workspace. </Step> </Steps> ## Microsoft directories and sign-in A workspace can have its own Microsoft directory or share one with other workspaces. Sharing a directory does not give its employees access to every connected workspace. Neo checks each person's active workspace memberships after sign-in. One accessible workspace opens directly. People with several memberships can switch workspaces, with their role shown separately in each. The switcher also shows the workspace's organization. For a separate directory, a workspace owner from that company opens **Microsoft directory** in the account menu and selects **Connect my Microsoft directory**. Neo uses the directory of their verified sign-in; nobody needs to enter directory or object IDs. Each Microsoft integration still needs its own consent and setup. Contact Neo to change an existing directory connection. Workspaces connected to the same directory use the same external Microsoft resources. Neo keeps its workspace records and credentials separate. The existing limit of one branded Teams bot installation per Microsoft directory still applies; use the dashboard to select among multiple workspaces. ## Add organization administrators Invite a person to a workspace first. After they accept, an organization owner can open the [**Administrators** tab](https://dashboard.neoagent.io/organizations?tab=administrators) and select **Assign administrator**. Choose the person and their Owner or Admin role, then select **Save organization role**. A pending invitation cannot receive organization authority. ## Bring an acquired MSP into the organization Contact Neo to move an existing workspace into your organization. Neo verifies ownership and makes the change. Existing workspace memberships and billing remain unchanged. Your organization's administrators can then explicitly grant access. An invitation between companies does not move a workspace or establish an ownership relationship. A shared email domain, Microsoft directory, or Stripe customer does not establish ownership either. ## Billing Each new subsidiary has its own free trial and its own paid plan. Moving a workspace does not combine Stripe customers, subscriptions, credit balances, or invoices. Existing billing arrangements remain in place. Consolidated organization billing is outside this release. ## Audit and API access The [**Activity** tab](https://dashboard.neoagent.io/organizations?tab=activity) records creation, role changes, workspace access grants, and directory connections. It displays the latest 100 events. The public API provides organization administration for signed-in Microsoft users under `/public-api/organizations`. `GET /public-api/organizations/current` returns the organization of the workspace in `X-Client-Id`; the other routes accept only that organization's ID. Workspace API keys can read only their current parent organization; they cannot create subsidiaries, change organization roles, or grant cross-workspace access. Neo Support can explain these actions and direct an administrator to the dashboard. # Authentication Source: https://docs.neoagent.io/developers/authentication Create a Neo API key in the dashboard and authenticate your requests with a bearer token. The Neo API authenticates with an **API key** — a long-lived secret you create in the dashboard and send as a bearer token on every request. A key belongs to the tenant that created it and carries that tenant's access, so you never pass a client or tenant id yourself. ## Create an API key API keys are created in the dashboard, by an admin, under **Roles & Access**. <Steps> <Step title="Open the API Keys tab"> Go to [**Roles & Access** → **API Keys**](https://dashboard.neoagent.io/rbac?tab=api-keys). You'll need the **Admin** role — only admins can manage keys. </Step> <Step title="Create the key"> Click **Create API key**, give it a recognisable name (e.g. *Billing export script*), and optionally set an expiry. Leave the expiry blank for a key that never expires. </Step> <Step title="Copy it now"> The key is shown **once**, right after creation. Copy it and store it somewhere safe — you can't retrieve it again later. </Step> </Steps> <Warning> Your API key is shown only once and can't be recovered. If you lose it, [rotate or revoke](#rotating-and-revoking-keys) it and issue a new one. Anyone with the key can act on your tenant through the API, so treat it like a password. </Warning> A key looks like this — `neo_sk_`, the environment, then a random secret: ``` neo_sk_prod_AbCdEf0123456789AbCdEf01 ``` ## Authenticate a request Send the key in the `Authorization` header as a bearer token: ```bash theme={null} curl https://api.neoagent.io/public-api/agents \ -H "Authorization: Bearer neo_sk_prod_AbCdEf0123456789AbCdEf01" ``` That's the only credential a request needs. The key resolves to your tenant on Neo's side — there is no separate tenant or client header. ## Rotating and revoking keys Manage existing keys from the same [**API Keys**](https://dashboard.neoagent.io/rbac?tab=api-keys) tab: | Action | What happens | | - | - | | **Rotate** | Issues a fresh key immediately and keeps the current key working for **24 hours**, so you can roll it out without downtime. After 24 hours the old key stops working. A key that has expired, or has less than 24 hours left, can't be rotated: create a new key instead. | | **Revoke** | Disables the key **immediately and permanently**. Any integration still using it stops working at once. | <Tip> Use one key per integration and name it for that integration. That way you can rotate or revoke a single consumer without touching the others, and the **Last used** column tells you which keys are still live. </Tip> ## Security best practices * Store keys in a secrets manager or your platform's environment configuration — never commit them to source control. * Don't embed keys in browsers, mobile apps, or anything a customer could inspect — the API is for server-to-server use. * Rotate on a schedule, and immediately if a key may have leaked. * Set an expiry on keys meant to be short-lived. <Info> Keys can't create other keys — minting and rotating keys is an admin-only dashboard action. The dashboard itself signs in with your Microsoft account rather than an API key; API keys are for your own scripts and integrations. </Info> ## What's next <Card title="Make your first request" icon="rocket" href="/developers/quickstart"> List your agents and read the response envelope. </Card> # Errors Source: https://docs.neoagent.io/developers/errors How the Neo API reports errors — the error envelope, status codes, and the request id to quote to support. When a request fails, the API returns a non-2xx HTTP status and a consistent error envelope. Read the HTTP status for the category and the `error.code` for the specific, stable reason. ## Error envelope ```json theme={null} { "error": { "code": "FORBIDDEN", "message": "API-key management requires admin role.", "details": { "...": "..." } }, "meta": { "request_id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d" } } ``` | Field | Description | | - | - | | `error.code` | Stable, machine-readable code — branch on this, not on the message. | | `error.message` | Human-readable explanation, safe to surface in logs. | | `error.details` | Optional object with extra context (e.g. which field failed validation). | | `meta.request_id` | Unique id for this request. Quote it when contacting support. | ## Status codes | Status | Meaning | What to do | | - | - | - | | `400` Bad Request | Malformed request or invalid parameters. | Fix the request shape or values. | | `401` Unauthorized | Missing, malformed, expired, or revoked credential. | Check the `Authorization` header and [your API key](/developers/authentication). | | `403` Forbidden | Authenticated, but the key lacks access to this resource or action. | Confirm the action is allowed for your tenant. | | `404` Not Found | The resource doesn't exist, or isn't yours. | Check the id; the API never reveals other tenants' resources. | | `409` Conflict | The request conflicts with current state. | Re-read the resource and retry. | | `422` Unprocessable | The request was well-formed but semantically invalid. | See `error.details` for the offending field. | | `429` Too Many Requests | You've hit the [rate limit](/developers/rate-limits). | Back off and retry after `Retry-After`. | | `5xx` Server Error | Something went wrong on Neo's side. | Retry with backoff; if it persists, contact support with the `request_id`. | ## Nested config fields on agent writes Wherever `POST /public-api/agents` or `PUT`/`PATCH /public-api/agents/{id}` accepts a config object, it is a **top-level, sibling field** of the agent body and never a child of another: `agent_settings`, `agent_settings_edits`, `toolbox`, `integrations`, `schedule`, `callback_settings`, `actions`, `ticket_conditions` and `time_entry_conditions`. Which of them a given body accepts is a separate question, answered by that body's schema. `agent_settings_edits` is `PUT`/`PATCH` only, so send the full `agent_settings` on create; and the `POST` body is a discriminated union on `autonomy_type`, so each variant declares its own subset — a `CONVERSATIONAL` create takes no `actions`, a `CHAINED_ACTIONS` create no `toolbox`. Check the schema for your route and `autonomy_type` under **Endpoints** in the sidebar. A field the schema does not declare is ignored rather than rejected. A tool that reaches an agent only at run time is dropped from `toolbox` on a create or update, and the rest of the write goes through. `GET /public-api/schemas/tools` never lists such a tool, under any filter: a permission group grants it and holds its settings, or Neo adds it by its own rule. To give an agent a tool a permission group grants, grant that group in `integrations`. A tool Neo adds by its own rule cannot be requested; Neo adds it wherever it applies. Putting one config object directly inside another returns `400 validation_error` and writes nothing. The check reads the immediate keys of each top-level config object, and of each `actions` entry. A container buried deeper than that — inside `agent_settings_edits.custom_instructions`, say — is ignored rather than rejected, which is why you read the agent back after a write. The message names both the field and the depth: ```json theme={null} { "error": { "code": "validation_error", "message": "Config field nested one level too deep: `toolbox` inside `agent_settings`. These are top-level fields of the agent body — send them as siblings of the field they are nested in, not inside it. Nothing was written." } } ``` Move the named field out to the top level and resend. This is easiest to get wrong when `custom_instructions` is long, so the closing brace is far from where the object opened. <Note> The update response is the lean agent summary — id, name, state, timestamps — and carries no config. A `200` does not by itself prove a config field was applied; `GET /public-api/agents/{id}` to confirm. </Note> <Tip> Treat any `4xx` as a bug in the request to fix, not to retry blindly — except `429`, which you should retry after the `Retry-After` delay. Retry `5xx` with exponential backoff. </Tip> ## What's next <Card title="Rate limits" icon="gauge-high" href="/developers/rate-limits"> How much you can call, and how to stay under the limit. </Card> # Neo public API Source: https://docs.neoagent.io/developers/introduction Call Neo programmatically — manage agents, read executions and analytics, and automate your MSP from your own scripts and tools. The Neo public API lets you do from your own code what you'd otherwise do in the dashboard: list and configure agents, read execution history and analytics, pull billing and usage, manage technician approvals, and more. It's the same API the Neo dashboard, the Teams bot, and partner integrations are built on. <CardGroup> <Card title="Authentication" icon="key" href="/developers/authentication"> Create an API key and authenticate your requests. </Card> <Card title="Quickstart" icon="rocket" href="/developers/quickstart"> Make your first request in a couple of minutes. </Card> <Card title="Endpoints" icon="code" href="/developers/quickstart#explore-the-endpoints"> Browse every endpoint with live request and response schemas. </Card> <Card title="Errors & rate limits" icon="triangle-exclamation" href="/developers/errors"> Error codes, the response envelope, and rate limits. </Card> </CardGroup> ## Base URL All requests go to a single global host. Neo routes your request to the right region (US, UK, EU, AU, or CA) under the hood, based on your tenant — there are no per-region URLs. ``` https://api.neoagent.io ``` ## The response envelope Every response uses the same envelope, so your code can handle success and failure consistently. **Success** — the payload is in `data`, with request metadata (and pagination, for lists) in `meta`: ```json theme={null} { "data": { "...": "..." }, "meta": { "request_id": "a1b2c3d4-...", "pagination": { "has_more": false, "next_cursor": null } } } ``` **Error** — a stable `code`, a human-readable `message`, and a `request_id` to quote to support: ```json theme={null} { "error": { "code": "FORBIDDEN", "message": "API-key management requires admin role." }, "meta": { "request_id": "a1b2c3d4-..." } } ``` See [Errors](/developers/errors) for the full list of codes and statuses. ## Finding exact paths Pick the source that matches what you're doing — you shouldn't have to guess a path: | You're… | Use | | - | - | | Reaching for a common endpoint | The [quickstart endpoint table](/developers/quickstart#explore-the-endpoints) — method and path for the everyday ones. | | Looking up a single endpoint | Its page under **Endpoints** in the sidebar — exact method, path, parameters, and response schemas, with a request console. Each page is small, so this is the lightweight lookup (and the right one for an AI agent making an ad-hoc call). | | Generating a client or SDK | The full OpenAPI 3.1 spec at [`https://api.neoagent.io/public-api/openapi.json`](https://api.neoagent.io/public-api/openapi.json) — the complete contract. It's large (\~440 KB), so fetch it once for tooling rather than per request. | ## "Agent" means workflow In the API, **agent** is what the dashboard and the rest of these docs call a workflow or agent — the `/agents` endpoints cover triggered workflows, scheduled agents, and chat agents alike. The public name is `agent_id`. <Info> The API is **additive and versioned**. New fields and endpoints can appear at any time, so write your client to ignore unknown fields. Breaking changes ship under a new version path with an overlap window — they never change an existing response shape underneath you. </Info> ## What's next <CardGroup> <Card title="Get your API key" icon="key" href="/developers/authentication"> Create a key in the dashboard and start authenticating. </Card> <Card title="Make your first call" icon="rocket" href="/developers/quickstart"> A copy-paste request that lists your agents. </Card> </CardGroup> # Quickstart Source: https://docs.neoagent.io/developers/quickstart Make your first Neo API request — create a key, list your agents, and read the response. This walks you from zero to a working API call in a couple of minutes. <Steps> <Step title="Create an API key"> In the dashboard, open [**Roles & Access** → **API Keys**](https://dashboard.neoagent.io/rbac?tab=api-keys), click **Create API key**, and copy the key — it's shown only once. See [Authentication](/developers/authentication) for the details. </Step> <Step title="Make your first request"> List your agents. Swap in the key you just copied: ```bash theme={null} curl https://api.neoagent.io/public-api/agents \ -H "Authorization: Bearer neo_sk_prod_AbCdEf0123456789AbCdEf01" ``` </Step> <Step title="Read the response"> A successful response wraps the result in the standard envelope — your data in `data`, request metadata and pagination in `meta`: ```json theme={null} { "data": [ { "agent_id": "1042", "agent_name": "Ticket Triage", "autonomy_type": "AGENTIC", "enabled": true } ], "meta": { "request_id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d", "pagination": { "has_more": false, "next_cursor": null } } } ``` Every list response carries `meta.request_id` (quote it if you contact support) and `meta.pagination`. </Step> </Steps> ## Paginate through a list List endpoints return up to `page_size` items (default 50, max 200). When `meta.pagination.has_more` is `true`, pass the `next_cursor` back as the `cursor` query parameter to fetch the next page: ```bash theme={null} curl "https://api.neoagent.io/public-api/agents?page_size=100&cursor=eyJpZCI6MTA0Mn0" \ -H "Authorization: Bearer neo_sk_prod_AbCdEf0123456789AbCdEf01" ``` Keep following `next_cursor` until `has_more` is `false`. ## Explore the endpoints The full, always-current API reference — every endpoint with its parameters, request and response schemas, and a built-in request console — lives under **Endpoints** in the sidebar. A few common starting points: | Resource | Endpoint | | - | - | | List your agents | `GET /public-api/agents` | | Inspect one agent | `GET /public-api/agents/{agent_id}` | | Edit an agent's instructions in place | `PATCH /public-api/agents/{agent_id}` with `agent_settings_edits.custom_instructions` | | Change one triage field's instructions | `PATCH /public-api/agents/{agent_id}` with `fields_to_triage_edits` on the `TRIAGE_TICKET` / `TRIAGE_TIME_ENTRY` action — keyed by `field_name` (a custom field also needs `custom_field_name`), so the other triage fields stay untouched | | Remove one triage field | Same `fields_to_triage_edits` entry with `"remove": true` — no need to resend the whole array. Removing a field that isn't configured, or the last remaining field, returns `400` | | Run an agent now | `POST /public-api/agents/{agent_id}/run-now` | | List executions | `GET /public-api/executions` | | Every action your agents took (Audit Log) | `GET /public-api/audit-log/tool-calls?search={ticket number}` | | Read credit usage | `GET /public-api/billing/usage` | | Credits per ticket for a period | `GET /public-api/billing/usage-by-ticket?since={ISO 8601}&until={ISO 8601}` | | What a credit costs you | `GET /public-api/billing/subscription` → `credit_unit_price` | | Time saved, its value and Neo's cost | `GET /public-api/performance/summary?from={ISO 8601}&to={ISO 8601}` → `credits_cost`, `labor_value_saved`, `fx` | | Read or set your cost of technician time | `GET` / `PUT /public-api/settings/value` | ### Money fields Credit and hours figures carry what they are worth, as the dashboard shows them: * `credit_unit_price` (`amount_minor` per credit in your billing currency, and its `source`) on `/billing/subscription`. `credits_cost` (`amount_minor`, `currency`) beside credits on `/billing/usage`, each `/billing/usage-by-agent` row, `/performance/summary` and each `/performance/workflows` row. Both are `null` when no price is known, such as on a trial; treat that as unknown, not free. A past month is priced at today's rate. * `labor_value_saved` (`amount`, `currency`, `hourly_cost`, `source`) on `/performance/summary` and each `/performance/workflows` row: hours saved times your cost per technician hour. `source` is `SET_BY_USER` for your own rate and `DEFAULT_BY_REGION` for the typical rate of your region. Hours saved are estimates, and so is their value. * `fx` converts `credits_cost` into the currency of `labor_value_saved` when the two differ, at the European Central Bank rate of `as_of`; `null` otherwise. * `estimated_manual_minutes` on each execution: the technician minutes a successful run is estimated to have saved, `null` for any other status. * `PUT /public-api/settings/value` takes `{"hourly_cost": 65, "currency": "usd"}` (usd, eur, gbp, cad or aud, above 0 and at most 10,000). Admins and owners only; a key with no acting user counts as the tenant. Generating a client or SDK? The full OpenAPI 3.1 spec is at [`https://api.neoagent.io/public-api/openapi.json`](https://api.neoagent.io/public-api/openapi.json) — fetch it once for tooling (it's \~440 KB), not per request. ## What's next <CardGroup> <Card title="Authentication" icon="key" href="/developers/authentication"> Key creation, rotation, revocation, and best practices. </Card> <Card title="Errors" icon="triangle-exclamation" href="/developers/errors"> The error envelope and what each status means. </Card> <Card title="Rate limits" icon="gauge-high" href="/developers/rate-limits"> How much you can call, and the headers that tell you. </Card> <Card title="Neo API agent tool" icon="robot" href="/agents/tools/management/neo-api"> Let an agent call this same API from inside a workflow. </Card> </CardGroup> # Rate limits Source: https://docs.neoagent.io/developers/rate-limits The Neo API rate limit, the headers that report it, and how to handle 429 responses. The API is rate limited per tenant to keep it responsive for everyone. The limit is shared across all of a tenant's API keys and dashboard sessions — it's not per key. | | | | - | - | | **Limit** | 1,200 requests | | **Window** | per 60 seconds (sliding) | | **Scope** | per tenant | ## Rate-limit headers Every response carries your current budget, so you can pace requests without guessing: | Header | Description | | - | - | | `X-RateLimit-Limit` | Maximum requests allowed in the window. | | `X-RateLimit-Remaining` | Requests left in the current window. | | `X-RateLimit-Reset` | When the window resets (Unix epoch seconds). | ## Handling 429 When you exceed the limit, the API responds `429 Too Many Requests` with a `Retry-After` header (seconds to wait). Pause for that long, then retry. Build this into your client rather than hammering the endpoint: ``` HTTP/1.1 429 Too Many Requests Retry-After: 12 ``` <Tip> Watch `X-RateLimit-Remaining` and slow down before you hit zero, and prefer fewer large pages over many small ones — request up to `page_size=200` and follow the [pagination cursor](/developers/quickstart#paginate-through-a-list) instead of polling tight loops. </Tip> ## What's next <Card title="Explore the endpoints" icon="code" href="/developers/quickstart#explore-the-endpoints"> Browse the full API reference with live schemas and a request console. </Card> # Opinionated Approach Source: https://docs.neoagent.io/getting-started/opinionated-approach Why Neo is AI-native instead of RPA — Neo's thesis on the future of MSP automation and how agents replace deterministic scripts. Most MSPs automate using RPA tools today. But we believe that by 2028, no one will be automating using RPA. Instead, we believe MSPs will be able to deploy powerful AI agents that behave like human technicians, to work tickets from start to finish, perform deep data analysis and take intelligent actions to resolve tickets entirely. The Neo Agent platform is the first step towards this future. It is built to be AI-native from the start and designed for even non-technical users to be able to deploy powerful AI agents to resolve tickets from start to finish. <Tip>Neo Agent “thinks for you” about safe, effective ways to use AI in MSP workflows—so you can start fast and scale with confidence.</Tip> # Starting a Trial Source: https://docs.neoagent.io/getting-started/starting-a-trial Get started with Neo Agent in just a few simple steps <Card title="Ready to get started?" icon="rocket" href="https://dashboard.neoagent.io"> Sign up for your free trial and start automating your MSP operations today. </Card> This guide covers the only steps you need to complete **before your trial setup call** with a Neo Account Manager, who will reach out to you directly to help you get the most out of your trial. It takes about **5 minutes** to complete the pre-trial steps. After that, allow **up to 2 hours** for Neo to sync your data so we can go straight into **building your first workflows on the trial call** and start showing value immediately. <Info> **When does your 14-day trial start?** The countdown begins the first time you **enable** an automation — a workflow or agent that runs on your tickets or on a schedule — or the first time one runs, including a **Run Now** by hand. Signing up does not start it, and neither does building an automation and saving it with **Save as Disabled**, so you can prepare as much as you like before the clock starts. Setting up a **chat agent** (an internal assistant your team messages) never starts it. Your Billing page shows the exact start date and which automation started it. </Info> <Steps> <Step title="Sign up with Microsoft"> Use your Microsoft login email to create your Neo Agent account. This ensures secure authentication and easy integration with your existing Microsoft ecosystem. <Tip> Make sure to use your work email address associated with your MSP for the best onboarding experience. </Tip> </Step> <Step title="Enter Your MSP Details"> Enter some basic details about your MSP including: * Company name and size * Primary PSA tool you use * **Teams support chat contact** — the person we invite to your private Microsoft Teams chat with the Neo team. It's pre-filled with your sign-in email; feel free to change it to whoever on your team should be in that chat (someone who uses Microsoft Teams day-to-day). <img alt="Image" title="Image" /> <Info> This information helps us customize your trial experience and prepare relevant examples for your setup. </Info> </Step> <Step title="Set Up Your Integrations"> Neo needs your integrations connected to sync data and prepare your environment before the trial call. Please connect: * **Your PSA** (for example: ConnectWise, Autotask, or Halo) * **Your RMM** (for example: NinjaOne, Datto RMM, or N-central) * **Your documentation tool**, if you use one (for example: IT Glue or Hudu), plus any other relevant tools <Check> After connecting your integrations, allow **up to 2 hours** for Neo to complete the initial sync. </Check> </Step> <Step title="You're Ready for the Trial Setup Call"> Once your integrations are connected and syncing, there's nothing else you need to do! On the call, we'll: * Confirm your integrations are working * Set up your first workflows * Tailor Neo to how your MSP operates 👉 Completing these steps in advance ensures your trial call is focused on configuration and value for you. </Step> </Steps> # Welcome Source: https://docs.neoagent.io/getting-started/welcome What Neo Agent is — AI platform for MSPs to speed up ticket resolution and automate PSA/RMM workflows. Start here if you're new. Neo Agent is your AI platform for MSP automation. You use it to speed up ticket resolution, automate PSA/RMM workflows, and keep your communications on-brand and consistent. <Frame> <img alt="Neo Agent overview" /> </Frame> ## What you can expect A powerful AI platform for MSPs that can help you automate various aspects of your service desk including routine manual tasks and other tasks which require deep data analysis. Neo Agent should feel & act like a human L1 technician that joins your service desk. ## Where to start <CardGroup> <Card title="Teams bot for your clients" icon="microsoft" href="/teams-bot"> Put a branded support bot in your clients' Microsoft Teams — the fastest way to get Neo in front of end users. </Card> <Card title="Automate your service desk" icon="robot" href="/core/overview"> Build triggered and scheduled workflows and agents that triage, resolve, and communicate on tickets. </Card> <Card title="Connect your tools" icon="plug" href="/integrations/intro"> Link your PSA, RMM, Microsoft 365, and documentation so agents can act on real data. </Card> </CardGroup> # Our Community Source: https://docs.neoagent.io/guides/getting-started/community Join the Neo Agent community on discord! Our Discord is where Neo Agent users, MSP leaders, and the core team collaborate. Inside the community, you can: * Ask questions and get real answers from the team * Share automation ideas and workflows * Learn how other MSPs are scaling with Neo * Get early previews of new features 👉 [Join the Neo Agent Discord](https://dashboard.neoagent.io/discord-verify) ### How to join <Steps> <Step title="Verify your account"> Head to Neo Agent's [verification page](https://dashboard.neoagent.io/discord-verify) to verify your account. <img alt="Screenshot 2026 01 25 At 19 35 57" /> </Step> <Step title="Authenticate with Discord"> <img alt="Screenshot 2026 01 25 At 19 36 58" /> </Step> <Step title="Ready to go!"> If you're verified, you'll get a link to open the discord channel <img alt="Screenshot 2026 01 25 At 19 38 01" /> </Step> </Steps> # Connecting AutoElevate to Neo Source: https://docs.neoagent.io/integrations/autoelevate/connecting-to-neo Save your AutoElevate API key in Neo, and decide what each agent can do You connect AutoElevate once at the MSP level, then turn it on per agent. <Info> AutoElevate uses a single API key per MSP. Save it once and every agent that has AutoElevate permissions can use it. </Info> ## 1. Create an API key in AutoElevate <Steps> <Step title="Open a service user"> In the AutoElevate admin portal, open a **service user** and add an **API Key**. </Step> <Step title="Pick the API Token (AE-BEARER) scheme"> AutoElevate offers two schemes at creation. Pick **API Token (AE-BEARER)** — the value starts with `aeb_`. <Warning> Do not pick **HMAC (AE-HMAC-SHA256)**. That scheme signs every request with a separate key held on your side, and Neo cannot use it. Its values start with `aeh_`. </Warning> </Step> <Step title="Give the key its scopes"> An AutoElevate key carries an explicit scope list. **Grant `companyView`.** Neo reads the company list on every PSA sync to keep the client mapping current, so this one is needed whatever your agents do. Then grant the view scopes for each area your agents read, and `requestEdit` as well if any agent will approve or deny. <Tip> Copy the key somewhere safe once it is generated — AutoElevate shows it only once. </Tip> </Step> </Steps> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the AutoElevate card, under Security. </Step> <Step title="Save the API Key"> Paste the key and click **Save**. Neo checks it against AutoElevate before saving, so a wrong or mistyped key is rejected straight away. </Step> </Steps> ## 3. Turn AutoElevate on per agent Each agent decides whether it uses AutoElevate and which areas it can touch. Open the agent, go to the Integrations section, and configure the AutoElevate block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area set to read only. The agent can find elevation requests, read the evidence behind them, and report — but never decides one. </Card> <Card title="Helpdesk" icon="headset"> Elevation Requests set to read and write — still requires technician approval on every decision. Everything else read only. Fits a helpdesk agent working the "I need admin rights to install this" ticket. </Card> </CardGroup> There is no Full Automation profile for AutoElevate. The only write this API has is the one that can never go through unattended. ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Elevation Requests** | Disabled, Read Only, Read and Write | Pending and historic requests. Approving and denying always wait on a technician. | | **Elevation Events** | Disabled, Read Only | The file, path, hashes, publisher, signing state and user behind a request. | | **Elevated Sessions** | Disabled, Read Only | Just-in-time admin sessions: who, when, how long. | | **Elevation Rules** | Disabled, Read Only | Auto-approval and auto-denial rules and their scope. | | **Computers** | Disabled, Read Only | Machine name, OS, elevation mode, last check-in. | | **Companies & Locations** | Disabled, Read Only | Your client hierarchy, used to scope every other lookup. | | **Account & Audit** | Disabled, Read Only | Partner usage figures and the admin audit log. | Every area except Elevation Requests is read only, because AutoElevate's Partner API has no write endpoint for it. ## Safety controls * **Approving and denying always wait on a technician.** This holds regardless of the agent's automation level or the access profile you picked. It is not a setting you can turn off. A decision is final: once a request leaves `PENDING` AutoElevate refuses any further decision on it, and there is no un-approve. * **Neo does not create rules on its own.** Both approve and deny can also create an auto-approval or auto-denial rule, and at account scope that rule decides every future matching elevation across every client you manage. Neo's agents are told to leave that off unless a technician asked for it in so many words, and the technician sees it in the approval either way. * **Every other area is read only.** Neo cannot change a rule, a computer, a company or a location through this integration, whatever the agent is set to. * **Path safety.** Suspicious URL paths (anything containing `..`, for example) are rejected before they reach AutoElevate. * **Neo sets the authentication itself.** The API key and AutoElevate's required beta header are added by Neo on every call. An agent cannot set, replace or read either one. ## If AutoElevate refuses Neo's requests | What comes back | Cause | Fix | | - | - | - | | `401` | The key was revoked or deleted, or it was created with the HMAC scheme instead of AE-BEARER | Create a new key on a service user with the **API Token (AE-BEARER)** scheme and save it in Neo. A key starting `aeh_` will never work | | `403` | The key's scope list does not cover the operation | Widen the key's scopes in AutoElevate. Reading requests, reading events and deciding a request are separate scopes, so a key that lists requests fine can still be refused on approve | | A failed **AutoElevate Company Mapping** row saying the key's scope list does not include `companyView` | Exactly that | Add `companyView` to the key in AutoElevate. The next PSA sync rebuilds the mapping | | A failed **AutoElevate Company Mapping** row saying AutoElevate rejected the key | The key was revoked or deleted, or created with the HMAC scheme | Recreate it on a service user with the AE-BEARER scheme and save it in Neo. Widening scopes cannot help — the key never authenticated | | A failed **AutoElevate Company Mapping** row saying anything else | A rate limit, an AutoElevate outage, or an error inside the mapping itself | Read the row's detail before changing anything. The next PSA sync retries on its own | | `409` on an approve or deny | The request is no longer pending — a technician, or a rule, already decided it | Nothing to fix. The agent re-reads the request and reports its current state | | `429` | The hourly limit for that operation is spent | Wait. AutoElevate allows 100 requests per hour per operation during beta and the wait can be up to a full hour. Neo paces its own calls to stay inside the limit, so this normally means something else is also calling the API with the same key | Until a `401` or `403` is fixed, agents that use AutoElevate report the failure on the ticket they were working. The rest of Neo keeps running. ## Disconnecting AutoElevate <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the AutoElevate card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault. </Step> </Steps> Your Organization Mapping is kept, including any mapping you set by hand, so reconnecting later picks up where you left off. Agents that use AutoElevate stop working until you connect it again. ## Security * The API key lives in Azure Key Vault. It is never stored in plaintext. * All traffic to AutoElevate goes over HTTPS, to `partner-api.autoelevate.com`. * Write access is opt in per agent, and it is only ever available on Elevation Requests. Once your key is saved and an agent has permissions, the AutoElevate tool is added to that agent automatically. # Overview Source: https://docs.neoagent.io/integrations/autoelevate/overview What the AutoElevate integration brings to your Neo Agent setup AutoElevate, from CyberFOX, removes local admin rights and puts each elevation behind an approval. When a standard user runs something that needs admin rights, their machine raises an elevation request and a technician approves or denies it. Connect AutoElevate to Neo and your agents can pull that request onto the ticket, gather the evidence behind it, and decide it with a technician's sign-off. Nobody opens the AutoElevate portal. <Info> AutoElevate uses a single API key per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with AutoElevate <CardGroup> <Card title="Elevation Requests" icon="circle-check"> Find the pending request behind a ticket, read its state, and approve or deny it. Approving and denying always wait on a technician. </Card> <Card title="Elevation Events" icon="file-magnifying-glass"> The evidence a decision rests on: the file name and path, its size and hashes, whether it is digitally signed, the publisher and the signing certificate, and the user who ran it. </Card> <Card title="Elevated Sessions" icon="clock"> The temporary admin sessions granted on a machine — who held one, when it started, and how long it was scheduled for. </Card> <Card title="Elevation Rules" icon="list-check"> The rules that resolve elevations automatically, and the scope each applies at — computer, location, company, or your whole account. </Card> <Card title="Computers" icon="desktop"> Managed machines with their OS, elevation mode, and last check-in, so a computer id on a request becomes a machine your technician recognises. </Card> <Card title="Companies & Locations" icon="building"> Your AutoElevate client hierarchy, used to scope every other lookup to the right client. </Card> </CardGroup> Account & Audit is also available, read only: partner usage figures for licence reconciliation, and the audit log of user and settings changes. ## Your clients are mapped automatically Neo matches your AutoElevate companies to the companies in your PSA and keeps the mapping on the AutoElevate card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Matching is by name: exact first, then after stripping a legal-form suffix (Ltd, Inc, LLC), then a last-resort AI match for the long tail. AutoElevate exposes no PSA identifier and no website, so name is all there is to match on. `managementSystemCompanyId` looks like a PSA id but is free text that defaults to the company name, so Neo does not use it. **A name match, or one you confirm, is handed straight to your agents**, so they know which AutoElevate company the ticket's client is without looking it up. A match from the AI rung is only a suggestion. It waits on the Organization Mapping tab until someone confirms it. Anything Neo could not match at all stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. Everything except Elevation Requests is read only. AutoElevate's Partner API has no write endpoint for them. ## Why connect AutoElevate * **The elevation queue stops waiting for someone to notice it.** An agent can watch for pending requests and hand a technician a ready decision, with the file and publisher already checked, instead of the technician finding the request themselves. * **The decision rests on evidence the request itself does not carry.** The request record holds almost nothing: no file name, and usually no user. The detail lives on the matching elevation event, and Neo's agent knows to go and read it. * **Approving and denying always require a technician's sign-off**, whatever the agent's automation level. The [AutoElevate API tool](/agents/tools/security/autoelevate-api#safety-controls) reference lists what that covers. ## How agents reach AutoElevate When you enable any AutoElevate permission group on an agent, Neo adds the AutoElevate tool to that agent's toolbox. There is nothing to install. The agent uses the API key you saved in the dashboard, and every call stays inside the areas and access levels you allowed. ## A note on the beta AutoElevate's Partner API is in beta, and CyberFOX may change it without notice. * **The elevation events feed is short.** It holds recent events only — on a live account it covered about nine hours. Neo reads the event while it works the request. Come back to a request days later and its event may be gone. * **Requests are limited to 100 per hour per operation.** Neo paces its own calls to stay inside that. This covers ticket work comfortably. It is not a budget for bulk reporting. ## Where to go next <Card title="Connecting AutoElevate to Neo" icon="plug" href="/integrations/autoelevate/connecting-to-neo"> Setup steps for the API key, per-agent access levels, and the safety controls that stay in place. </Card> # Connecting Auvik to Neo Source: https://docs.neoagent.io/integrations/auvik/connecting-to-neo Save your Auvik region, user email and API key in Neo You connect Auvik once at the MSP level, with one Auvik user's email and API key. ## 1. Prepare an Auvik user <Steps> <Step title="Pick or create the user"> Auvik recommends a user made for API access. Give it the built-in **API Access Only** role, or a role with API access, and access to your clients. The built-in role covers devices, interfaces, networks, alerts, notes, tenants and billing. To let agents read statistics, SNMP pollers or SaaS Management, add those API permissions to the role, or use a custom role. To let agents dismiss alerts, the role may need **Access and Edit** on **API - Alerts**. The built-in role gives View there. </Step> <Step title="Generate the API key"> Sign in to Auvik as that user, open the user's profile, and click **Generate API Key**. Copy the key: Auvik shows it once. </Step> <Step title="Note your region"> Your region is in your Auvik address. If you sign in at `https://acme.us1.my.auvik.com`, the region is `us1`. </Step> </Steps> <Warning> Do not regenerate the key in Auvik after you connect it. Regenerating replaces the key at once, and Neo loses access until you save the new key here. </Warning> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Auvik**](https://dashboard.neoagent.io/integrations?open=auvik), under Networking. </Step> <Step title="Save the key"> Enter the region (or paste your Auvik address), the user's email and the API key, then click **Save settings**. Neo checks them against Auvik before saving, so a wrong key or a wrong region is rejected straight away, and the error names the right region when Auvik reports one. </Step> </Steps> ## 3. Turn Auvik on per agent Open the agent, go to the Integrations section, and configure the Auvik block. Agents read only the clients the Auvik user can see. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Read devices, alerts, statistics, tenants and billing. Nothing is changed. </Card> <Card title="Helpdesk" icon="headset"> Read the same. Dismissing an alert waits on a technician. </Card> <Card title="IT Admin" icon="user-gear"> Read the same. Dismissing an alert waits on a technician. </Card> <Card title="Full Automation" icon="bolt"> Read the same and dismiss alerts without approval. </Card> </CardGroup> Notes and Audit stays off in every profile. Auvik notes are free text, and they can hold passwords. Turn it to Read Only by hand only if your notes hold no passwords or keys. ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Inventory** | Disabled, Read Only | Devices, interfaces, networks and components, with online status, last seen time, connected devices, warranty, lifecycle and configuration backup times. | | **Alerts** | Disabled, Read Only, Read/Write | Alert history. Write dismisses an alert. | | **Statistics** | Disabled, Read Only | Device, interface, component and service statistics, outage history, and SNMP pollers. | | **Tenants and Billing** | Disabled, Read Only | Your Auvik tenants and billing usage per client. | | **Notes and Audit** | Disabled, Read Only | Technician notes on devices and networks, and the audit log. | | **SaaS Management** | Disabled, Read Only | Auvik SaaS Management apps, users and licenses per client. | Alerts also has its own technician approval setting. ## Example: a network device is down Give an agent that runs on your device-down tickets the **Helpdesk** profile and instructions like these: > When a ticket says a network device is down, check the device in Auvik: its online status, when Auvik last saw it, and the switch port it connects to, and write what you found in an internal note. See [Auvik API](/agents/tools/networking/auvik-api) for what the agent can read. ## Safety controls * **Read only, apart from one write.** Neo sends Auvik reads and one write, dismissing an alert. Nothing Neo sends to Auvik changes a network device. * **You decide whether dismissing waits on a technician.** Helpdesk and IT Admin ask first; Full Automation does not. * **Notes stay off.** Notes and Audit is off in every profile, because Auvik notes can hold passwords. * **Only Auvik hosts.** Neo sends the key only to the Auvik API host of your region. * **Path safety.** A URL path with a `..` segment is rejected before it reaches Auvik. ## If Auvik moves your account Auvik can move an account to another region. Neo then stops and tells the technician the new region. Open **Integrations** → **Auvik**, set the region, enter the API key again and save. # Overview Source: https://docs.neoagent.io/integrations/auvik/overview What the Auvik network monitoring integration brings to your Neo Agent setup Auvik monitors the networks at your clients' sites: it finds the switches, routers, firewalls and access points, maps how they connect, and raises alerts when a device goes offline. Connect Auvik to Neo once, at the MSP level, with the email and API key of an Auvik user. ## What Neo can do with Auvik <CardGroup> <Card title="Device down" icon="network-wired"> Find the device from the ticket by name, IP address, serial number or MAC address. Tell whether it is really down, when Auvik last saw it, and how long its outages lasted. </Card> <Card title="Uplinks" icon="sitemap"> See the switches, routers and firewalls the device connects to, on which ports, and whether each port is up. When the device has more than one such neighbour, Neo lists each as a possible uplink. </Card> <Card title="Alerts" icon="bell"> Read the open Auvik alerts on the device or its uplink, and dismiss an alert once the condition has cleared and the ticket is resolved. </Card> <Card title="Inventory and billing" icon="list-check"> Read device details, warranty and end of life, networks and statistics, and the billable device days for each client. </Card> </CardGroup> Auvik's published API reads only, apart from dismissing an alert. It has no operation that runs a command on a device, pushes a configuration, or exports a configuration backup, and Auvik says configuration backups cannot be exported through the API. So Neo cannot do these through Auvik. ## Your clients are mapped automatically Neo matches each Auvik site to a company in your PSA and keeps the mapping on the Auvik card's **Organization Mapping** tab. It refreshes the mapping when you save the API key, and again on each nightly PSA sync. A client with several sites maps each site to the same company. Matching starts with the name of the multi-site the site sits under, when it is not your own top-level account. Then comes the site's display name, then its domain prefix: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the rest. **A name match, or one you confirm, is handed straight to your agents**, so they start from the client's sites without looking them up. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Neo sees only the sites the Auvik user can access. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Auvik" icon="plug" href="/integrations/auvik/connecting-to-neo"> Generate an API key in Auvik and save it in Neo with your region. </Card> # Connecting BeyondTrust EPM to Neo Source: https://docs.neoagent.io/integrations/beyondtrust-epm/connecting-to-neo Create a BeyondTrust EPM API account and save it in Neo You connect BeyondTrust EPM once at the MSP level. ## 1. Create an API account <Steps> <Step title="Open API Settings"> Sign in to BeyondTrust EPM and open **Configuration** > **Settings** > **API Settings**. </Step> <Step title="Create the account"> Click **Create an API Account** and enter a name, such as `Neo`. Copy the **Client ID** and the **Client Secret**. The secret is shown only once. </Step> <Step title="Set the permissions"> Set **Read Only** on the **Audit**, **JIT** and **Management** endpoints, then save. </Step> </Steps> ## 2. Find your API host Your API host is `https://<your-subdomain>-services.pm.beyondtrustcloud.com`. It is the host of your Management API Swagger page, for example `https://yourcompany-services.pm.beyondtrustcloud.com/management-api/swagger/index.html`. ## 3. Add the account in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the BeyondTrust EPM card, under Security. </Step> <Step title="Save the account"> Paste the API host, the Client ID and the Client Secret and click **Save**. Neo checks them against BeyondTrust before saving, so a wrong host, a wrong secret or a missing permission is rejected straight away. </Step> </Steps> ## 4. Turn BeyondTrust EPM on per agent Open the agent, go to the Integrations section, and configure the BeyondTrust EPM block. Pick a profile, or set each area: | Area | Access levels you can pick | Notes | | - | - | - | | **JIT Application Access** | Disabled, Read Only, Read / Write | Elevation requests and their audit trail. This is the area an elevation-email agent needs. | | **JIT Admin Access** | Disabled, Read Only, Read / Write | Admin access requests. | | **Computers** | Disabled, Read Only, Read / Write | The computer behind a request, its group, domain and policy. | | **Groups** | Disabled, Read Only, Read / Write | Computer groups. | | **Policies** | Disabled, Read Only, Read / Write | Policies and application groups. | | **Console Users and Access** | Disabled, Read Only, Read / Write | Console users, roles and API accounts. | | **Activity and Events** | Disabled, Read Only | Console activity and endpoint events. | | Profile | Writes | | - | - | | **Read Only** | Not allowed | | **Helpdesk** | Every write asks a technician | | **IT Admin** | Computer and group changes run on their own; policy and console-user changes ask a technician | | **Full Automation** | Run on their own | Under every profile, approving or denying a request, deleting or deactivating a computer, clearing a group's policy, and deleting a group or policy ask a technician. ## Example: move elevation tickets to the right client Give the agent that triages your BeyondTrust elevation emails the **Read Only** profile and an instruction like this: > When a ticket is a BeyondTrust JIT application access request, look up the request and its computer in BeyondTrust EPM and move the ticket to that computer's client. See [BeyondTrust EPM API](/agents/tools/security/beyondtrust-epm-api) for what the agent can read. # Overview Source: https://docs.neoagent.io/integrations/beyondtrust-epm/overview What the BeyondTrust EPM integration brings to your Neo Agent setup BeyondTrust Endpoint Privilege Management for Windows and Mac (EPM-WM) controls which applications your end users may run with admin rights. Connect your EPM API account to Neo once, at the MSP level. ## What Neo can do with BeyondTrust EPM <CardGroup> <Card title="Elevation requests" icon="shield-check"> Find the JIT request behind a BeyondTrust elevation email from its ticket number, with the user, computer, application, publisher and reason. </Card> <Card title="Computers and groups" icon="laptop"> Read the computer behind a request, its group, domain and policy, and move the ticket to the client the computer belongs to. </Card> <Card title="Policies and console users" icon="user-shield"> Read policies, application groups, console users and roles. Manage computers, groups and policies when you allow it. </Card> <Card title="Activity and events" icon="list"> See who changed what in the console, and search a computer's or user's endpoint events. </Card> </CardGroup> Approving or denying a request, removing a computer, and clearing or deleting a policy always ask a technician first. ## Your groups are mapped to clients Neo matches your BeyondTrust EPM computer groups to the companies in your PSA and keeps the mapping on the BeyondTrust EPM card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Matching uses the group name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **A name match, or one you confirm, is handed straight to your agents**, so they find the computers of the ticket's client. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. A group Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. A group that is not a client, such as a policy tier like "Mac Workstations", stays unmapped; you can ignore it. ## Next steps <Card title="Connect BeyondTrust EPM" icon="plug" href="/integrations/beyondtrust-epm/connecting-to-neo"> Create an API account in BeyondTrust EPM and save it in Neo. </Card> # Connecting CentralReach to Neo Source: https://docs.neoagent.io/integrations/centralreach/connecting-to-neo Get a client's CentralReach API credentials and save them in Neo You connect CentralReach once for each client that uses it, with three values for that client's organization: an API Key, a Client ID and a Client Secret. ## 1. Get the API credentials from CentralReach <Steps> <Step title="Ask CentralReach for API access"> The CentralReach Implementations team issues API credentials for each organization. Ask the practice's CentralReach representative for API access for the organization, on behalf of the practice. </Step> <Step title="Give the API user the permissions it needs"> CentralReach API calls run as an API user, with that user's CentralReach permissions. Every connection needs permission to read employee contacts: Neo checks the credentials with that read when you save them. For onboarding and offboarding, the API user also needs to edit employee contacts. Add permissions for labels, tasks, schedules or other areas you want agents to use. </Step> <Step title="Copy the three values"> You receive the **API Key**, the **Client ID** and the **Client Secret**. Keep them for the next step. </Step> </Steps> ## 2. Add the credentials in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **CentralReach**](https://dashboard.neoagent.io/integrations?open=centralreach), under Other. </Step> <Step title="Pick the client"> In **Customer**, choose the client this CentralReach organization belongs to. The client must be on your **Companies** tab. For a second client, click **Add customer**. </Step> <Step title="Save the credentials"> Paste the API Key, the Client ID and the Client Secret, and click **Save settings**. Neo checks them against CentralReach before saving, so a wrong value is rejected straight away. </Step> </Steps> <Warning> If CentralReach issues new credentials for the organization, save them here. Neo loses access to that client's organization until you do. </Warning> ## 3. Turn CentralReach on per agent <Tip> An agent you create from the **M365 User Onboarding** or **M365 User Offboarding** template after you connect CentralReach already has it: Employees with the Helpdesk access, and a step that creates the employee for a new hire or deactivates them when they leave. Add the name of your employee contact form, and where the HR system id comes from, to the onboarding agent's instructions. For an agent you already run, follow the steps below, or ask your Neo Support Agent to add CentralReach to it. </Tip> <Steps> <Step title="Open the agent's integrations"> Open the agent in the Neo Dashboard and go to its **Integrations** tab. </Step> <Step title="Pick an access profile"> Under **CentralReach**, pick an access profile, or set each permission group by hand. | Profile | What it does | | - | - | | **Read Only** | Reads employees; changes nothing | | **Helpdesk** | Creating, changing or deactivating an employee asks a technician | | **IT Admin** | Creates, updates and deactivates employees on its own | | **Full Automation** | Every supported call without approval, in every group, except recording or voiding a payment and deleting a file, which always ask a technician | Read Only, Helpdesk and IT Admin turn on Employees alone. Every other group can reach patient health information or staff pay, because labels, custom fields and tasks take any contact, a client's included. Turn a group on only for an agent that needs it, such as Contact Labels & Custom Fields to set a new hire's labels. </Step> </Steps> # CentralReach Source: https://docs.neoagent.io/integrations/centralreach/overview Let Neo agents set up and remove staff accounts in your clients' CentralReach practices CentralReach is the practice management and EMR platform many ABA and autism-care providers run on. Each of your clients that uses it has its own CentralReach organization. Connect CentralReach for those clients, and Neo agents can work in it while they handle a ticket. ## What Neo can do with CentralReach * Create the CentralReach employee account for a new hire, after the Microsoft 365 account, from the same onboarding ticket * Deactivate an employee with a termination date when they leave * Find an employee and check their status, labels and custom fields * Give a new hire the labels and custom field values their role needs * Assign CentralReach tasks to a new hire or their team With the matching permission groups on, agents can also work with schedules, files, patient records, billing and payroll. See [CentralReach API](/agents/tools/management/centralreach-api) for the permission groups and profiles. ## One connection per client CentralReach issues API credentials per organization, so you connect it once for each client that uses it, and the connection belongs to that client's company in Neo. An agent working a ticket for that company uses that company's CentralReach organization. ## Next steps <Card title="Connect CentralReach" icon="plug" href="/integrations/centralreach/connecting-to-neo"> Get the CentralReach API credentials for a client and save them in Neo. </Card> # Connecting CIPP to Neo Source: https://docs.neoagent.io/integrations/cipp/connecting-to-neo Create a CIPP API client, save it in Neo and turn CIPP on for the agents that work Microsoft 365 tickets You connect CIPP once at the MSP level, then turn it on per agent. ## 1. Create an API client in CIPP <Steps> <Step title="Open CIPP-API"> In CIPP, open **CIPP** > **Integrations** and click **CIPP-API**. </Step> <Step title="Create the client"> Click **Actions** > **Create New Client** and name it "Neo". Turn **Enabled** on. * **Role:** a role that allows what you want Neo to do. CIPP's `readonly` role is enough for an agent that only reads; an agent that makes changes needs `editor` or a custom role. * **Allowed IP Ranges:** leave it at Any, or add [Neo's IP addresses](/integrations/ip-whitelisting). Submit the form and copy the **Application Secret**. CIPP shows it only once. </Step> <Step title="Save to Azure"> Click **Actions** > **Save to Azure**. CIPP restarts, so give it a few minutes before the next step. </Step> <Step title="Copy the connection details"> The CIPP-API page now shows the **API URL** and the **Tenant ID**. Copy them, and the client's **Application ID** from the table. </Step> </Steps> ## 2. Add the credential in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the CIPP card, under Identity & Workspace. </Step> <Step title="Save the credential"> Paste the API URL, the Tenant ID, the Application ID and the Application Secret, and click **Save**. Neo signs in to Microsoft with them and lists your CIPP tenants before it saves, so a wrong value is rejected straight away with the reason. The **Organization Mapping** tab fills after the save, and again on each nightly PSA sync. </Step> </Steps> <Note> The API URL is the address on the CIPP-API page, like `https://cippabcde.azurewebsites.net`. The address you open CIPP in is a different one and does not work here. </Note> ## 3. Turn CIPP on per agent Open the agent, go to the Integrations section, and configure the CIPP block. Pick an access profile, or set each area: | Area | Notes | | - | - | | **Tenants & Licences** | Read only. Lets the agent find the customer's tenant. | | **Users & Groups** | Account changes: sessions, sign-in, MFA, passwords, groups, onboarding and offboarding. | | **Mailboxes** | Mailbox and calendar access, out of office, forwarding, message trace. | | **Email Security** | Quarantine and the Tenant Allow/Block List. | | **Devices** | Intune device actions. A wipe or retire, and deleting a device from Entra ID, always ask a technician first. | | **Security & Sign-ins** | Defender alerts, sign-ins, business email compromise checks and containment. | | **SharePoint & Teams** | Site membership and OneDrive access. | | **Passwords & Keys** | LAPS passwords, BitLocker keys, password resets and Temporary Access Passes. Turn it on only for agents whose answers go to your team. | | **Raw Graph & Exchange** | Any Graph read or Exchange cmdlet, as a last resort. Every call asks a technician. | ## Example: unblock a user who is locked out Give an agent that runs on your Microsoft 365 tickets the CIPP **Helpdesk** profile and instructions like these: > When a user cannot sign in, look the user up in CIPP. If sign-in is blocked, check the sign-in log for a reason. If there is no sign of compromise, allow sign-in again and add a note with what you found. If the sign-ins look suspicious, run a business email compromise check and assign the ticket to the security queue with the result. With Helpdesk, the account change waits for a technician's approval. ## Troubleshooting | Error on save | Fix | | - | - | | Microsoft refused the secret | Reset the client's secret in CIPP and paste the new one. | | Microsoft does not know the API scope of this client | In Entra ID, open the CIPP API client's app registration, open **Expose an API**, and add the Application ID URI (the default is fine). | | CIPP did not accept the token (HTTP 401) | Check the client is enabled, click **Save to Azure**, wait a few minutes and save again. | | CIPP refused the client (HTTP 403) | Give the client's role permission to read tenants, and set Allowed IP Ranges to Any or add Neo's addresses. | # Overview Source: https://docs.neoagent.io/integrations/cipp/overview What the CIPP integration brings to your Neo Agent setup [CIPP](https://cipp.app) (the CyberDrain Improved Partner Portal) manages the Microsoft 365 tenants of an MSP's customers from one place. Connect it to Neo and your agents can work Microsoft 365 tickets in those tenants through CIPP: unblock a user, reset MFA, grant mailbox access, release quarantined mail, check a suspicious sign-in, sync a device. <Info> CIPP connects once per MSP, with an API client you create in your own CIPP instance. Every agent you enable uses it, with permissions you control per agent. </Info> ## What Neo can do with CIPP <CardGroup> <Card title="Users & Groups" icon="users"> Find a user, revoke sessions, block or allow sign-in, reset MFA, set a password, change group membership, onboard and offboard. </Card> <Card title="Mailboxes" icon="envelope"> Trace a missing email, grant mailbox or calendar access, set out of office or forwarding, convert a mailbox to shared. </Card> <Card title="Email Security" icon="shield"> Find quarantined mail and release it, and manage Tenant Allow/Block List entries. </Card> <Card title="Devices" icon="laptop"> Check a device's compliance and Defender state, and sync, restart or scan it. </Card> <Card title="Security & Sign-ins" icon="user-shield"> Read Defender alerts and sign-ins, run a business email compromise check and contain the account. </Card> <Card title="SharePoint & Teams" icon="share-nodes"> Give a user access to a site or a departed user's OneDrive. </Card> </CardGroup> See [CIPP API](/agents/tools/m365/cipp-api) for the full list, and for what Neo never does through CIPP. ## CIPP or Neo's own Microsoft 365 connection Neo can also reach your customers' tenants with its own access, through [GDAP](/integrations/m365/gdap). If CIPP already reaches your tenants through GDAP, connecting Neo the same way takes a few clicks, and the connection runs in the background. Use CIPP when your team already manages customers there and you would rather not grant Neo a second route. An agent can use either one. ## Your customers are mapped automatically Neo matches your CIPP tenants to the companies in your PSA and keeps the mapping on the CIPP card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Matching starts with the Microsoft 365 tenant id: a CIPP tenant with the same tenant id Neo has on a company is an exact match. Then comes the tenant's domain against the company's website, then the name. Last comes an AI match for the long tail. **A tenant id or name match, or one you confirm, is handed straight to your agents**, so they act in the right customer's tenant without looking it up. A domain or AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. ## Next steps <Card title="Connect CIPP" icon="plug" href="/integrations/cipp/connecting-to-neo"> Create an API client in CIPP and save it in Neo. </Card> # Connecting ConnectWise CPQ to Neo Source: https://docs.neoagent.io/integrations/connectwise-cpq/connecting-to-neo Create a ConnectWise CPQ API key pair and save it in Neo with your access key You connect ConnectWise CPQ once at the MSP level. Neo needs three values: your CPQ access key and an API key pair. ## 1. Find your access key Sign in to ConnectWise CPQ. The address in your browser contains `accesskey=` followed by your access key. Copy that value. ## 2. Create the API key pair <Steps> <Step title="Use an API user"> The key pair belongs to a CPQ user marked as an API user. Create one for Neo, or ask your CPQ administrator to mark an existing user as an API user. What that user may do in CPQ is what Neo may do. </Step> <Step title="Create the keys"> In CPQ, open **Settings > Organization Settings > API Keys** and create a key pair for that user. </Step> <Step title="Copy both keys"> Copy the public key and the private key. CPQ shows the private key only once. </Step> </Steps> <Warning> Do not delete the key pair in CPQ after you connect it. Neo loses access until you save a new pair here. </Warning> ## 3. Add the keys in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the ConnectWise CPQ card, under Sales & Quoting. </Step> <Step title="Save the keys"> Paste the access key, the public key and the private key, and click **Save**. Neo checks them against CPQ before saving, so a wrong key is rejected straight away. Keys whose CPQ user may not read tax codes still save; that user's rights limit what the agent can do. </Step> </Steps> ## 4. Turn ConnectWise CPQ on per agent Open the agent, go to the Integrations section, and configure the ConnectWise CPQ block. Pick a profile, then adjust any area: | Area | Access levels you can pick | Notes | | - | - | - | | **Quotes** | Disabled, Read Only, Read/Write | Quotes, lines, tabs, terms and the customer records on them. This is the area a quote-drafting agent needs. | | **Quote Approval Decisions** | Disabled, Read/Write | Recording an approver's decision on a quote, or whether it needs approval. It also needs **Quotes** at Read Only or above, because CPQ answers with the whole quote. Leave it off on an agent that drafts quotes. | | **Users** | Disabled, Read Only, Read/Write | Your CPQ users. Read Only lets the agent find a rep's approver. | | **Templates and Lookups** | Disabled, Read Only | Templates, tax codes and billing periods. A drafting agent needs it to pick a template. | To draft quotes from ConnectWise PSA opportunities, also give the agent the PSA **Opportunities**, **Documents** and **Products** groups. [ConnectWise CPQ API](/agents/tools/sales/connectwise-cpq-api#drafting-from-a-psa-opportunity) lists the levels and what the agent does with each. # Overview Source: https://docs.neoagent.io/integrations/connectwise-cpq/overview What the ConnectWise CPQ integration brings to your Neo Agent setup ConnectWise CPQ (formerly ConnectWise Sell) holds your quotes. Connect your CPQ API keys to Neo once, at the MSP level. ## What Neo can do with ConnectWise CPQ * Draft a quote from a ConnectWise PSA opportunity: Neo reads the opportunity's notes, product lines and files, prices each line from your PSA catalog, copies your template and links the quote to the opportunity * Change an expiry date, a quantity or a price on a quote * Ask the rep's approver to approve a quote, and note the request on the opportunity * Answer "where is my quote?" with the quote's status, total and expiry date See [ConnectWise CPQ API](/agents/tools/sales/connectwise-cpq-api) for the permission groups. ## Next steps <Card title="Connect ConnectWise CPQ" icon="plug" href="/integrations/connectwise-cpq/connecting-to-neo"> Create an API key pair in CPQ and save it in Neo. </Card> # Custom API Source: https://docs.neoagent.io/integrations/custom-api/overview Connect any external API once and let your agents call it by name Custom API connections give every external HTTP API — a shipping tracker, an alerting webhook, an internal tool — one home on the Integrations page. You configure the endpoint and credential once; any agent you allow can then call it by name through the [External API Request](/agents/tools/management/external-api-request) tool. <Info> Connections are how you give an agent an external API in the dashboard — the old per-agent configuration editor was retired after every existing setup was migrated to connections. Agents still running an inline API configuration set up through the API keep working during the deprecation window; new setups use connections. One definition and one credential, shared by every agent: rotating a key updates all of them at once. </Info> ## Add a connection Open [**Integrations**](https://dashboard.neoagent.io/integrations), find **Custom API** under **Other**, and click **Add API**. The wizard walks through five steps: <Steps> <Step title="Point Neo at the API"> Name the connection, paste the web address, and pick what Neo does there — **GET**, **POST**, **PUT**, **PATCH**, or **DELETE**. A `{placeholder}` segment in the address (e.g. `.../track/{trackingNumber}`) becomes a value the agent fills in on every call. </Step> <Step title="Prove who Neo is"> Pick how the API authenticates: | Option | When to use | | - | - | | **API key** | The service gave you a single code, sent in a custom header | | **API key in the web address** | The docs put the key in the address itself, such as `?key=YOUR_KEY` (Google Maps works this way) | | **Access token** | The docs say `Authorization: Bearer` | | **Username & password** | HTTP Basic authentication | | **Client ID & secret (OAuth 2.0)** | The API issues short-lived tokens from a token endpoint; Neo fetches and refreshes them automatically | | **No key needed** | Public endpoints and pre-authenticated webhook URLs | Keys and secrets are stored in a secure vault, shown masked afterwards, and never appear in logs or event history. With **API key in the web address**, enter the parameter name from the docs (for Google Maps, `key`) and the key. Neo adds the key to every request, so it never goes in your agent instructions. Do not also define that name under **Query parameters**: the agent never fills it, and the stored key always wins. For OAuth 2.0 providers that need more than a client ID and secret, expand **Advanced OAuth options**: add custom token request parameters (when any are set, that list becomes the whole token request — include `grant_type` and everything else the provider's docs list, marking passwords as secret) and, if the provider wants credentials in a header on the token request, token-endpoint Basic auth. </Step> <Step title="Teach Neo the blanks"> Optional. Define **Query parameters** and, for requests with a body, **Information Neo sends** — each field gets a name, a type, a description, and whether it's required. The agent reads the descriptions to fill fields correctly, so write what the value means, not just its name. Pick **List** when the API wants a JSON array — a recipients field that takes `["3546618111"]` rather than `"3546618111"`. Neo sends a List body field as an array, and a List query parameter as repeated `?name=value` pairs. </Step> <Step title="Try it out"> Send one real request before saving. The result is recorded on the connection, so you can see at a glance which connections have been verified. </Step> <Step title="Review & save"> A plain-words summary of what you built. Save, and the connection appears under **Connected APIs** on the tile. </Step> </Steps> ## Test a saved connection On the Custom API tile, every connection has a **Test** button (▶). It opens a dialog asking for any parameters the API needs, sends one real request with the stored credential, and records the outcome next to the connection. For a **List** field, separate the sample values with commas: the test sends `3546618111, 3546618112` as a two-item array. The result names the HTTP status the API answered with. Some APIs report an error inside a successful answer: Google Maps answers a bad or missing key with status 200 and `"status": "REQUEST_DENIED"`. So read **What the API sent back** before you trust a green result. ## Use a connection from an agent In the agent builder, enable the **External API Request** tool and pick the connection under **Connected APIs**. The agent calls it by its connection name, so use names your instructions can reference naturally — `DHL_Tracking`, `slack_alert`. ## Update a credential Edit the connection and type the new value over the masked one — a masked field left untouched keeps what's stored. Every agent that references the connection uses the new credential immediately; nothing needs re-saving on the agents. For an OAuth 2.0 connection, Neo caches the access token and reuses it across runs. Saving the connection discards that token. If the API rejects a cached token with `401 Unauthorized`, Neo gets a new token and sends the request once more. A second `401` goes back to the agent with its real status code, which usually means the API client lost access to that endpoint. # Connecting CyberQP to Neo Source: https://docs.neoagent.io/integrations/cyberqp/connecting-to-neo Create CyberQP API credentials and save them in Neo You connect CyberQP once at the MSP level. The connection reaches what the CyberQP technician who creates it can see, so use a technician with the Primary or Super role. ## 1. Create the API credentials <Steps> <Step title="Use a dedicated technician"> We recommend a dedicated **System User** technician in CyberQP with the Primary or Super role, so the connection does not depend on a person's account. Sign in to the CyberQP dashboard as that technician. </Step> <Step title="Open the API login page for your data centre"> In the same browser, open the page for the data centre you sign in to: | You sign in at | Open | | - | - | | admin.getquickpass.com | [https://us.getquickpass.com/api/v1/auth/login](https://us.getquickpass.com/api/v1/auth/login) | | eu-admin.getquickpass.com | [https://eu.getquickpass.com/api/v1/auth/login](https://eu.getquickpass.com/api/v1/auth/login) | | ca.admin.cyberqp.com | [https://ca.cyberqp.com/api/v1/auth/login](https://ca.cyberqp.com/api/v1/auth/login) | </Step> <Step title="Accept and copy the credentials"> Click **Accept**. CyberQP shows an Access Token, a Refresh Token and a Client ID. Copy the **Refresh Token** and the **Client ID**. CyberQP shows them once. </Step> </Steps> <Warning> A CyberQP refresh token works once. Neo exchanges it when you save and keeps the new one CyberQP returns each time. Do not use the same refresh token in a script or another tool, or Neo's connection stops working. To give another tool access, open the API login page again for a new set of credentials. </Warning> ## 2. Add the credentials in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the CyberQP card, under Security. </Step> <Step title="Save the credentials"> Pick your **Data Centre**, paste the **Client ID** and the **Refresh Token**, and click **Save**. Neo exchanges the token with CyberQP before it saves, so wrong credentials are rejected straight away. </Step> </Steps> <Note> A refresh token expires after six months without use. Neo uses it at least once a day while your PSA syncs, so the connection stays alive. If CyberQP refuses it, Neo tells you in the dashboard and by email; repeat the steps above to reconnect. </Note> ## 3. Turn CyberQP on per agent Open the agent, go to the Integrations section, and configure the CyberQP block. Pick a profile, then change any area: | Area | Access levels you can pick | Notes | | - | - | - | | **Customers & Accounts** | Disabled, Read Only | Customers, agent GUIDs and accounts. | | **Agent Deployment** | Disabled, Read Only | The agent install token. It installs the agent for any of your customers. | | **Identity Verification** | Disabled, Read / Write | Sends a push to the end user. | | **Just-In-Time Accounts** | Disabled, Read Only, Read / Write | Creating, enabling, disabling and deleting JIT admin accounts. Creating or enabling one always asks a technician. | | **Passwords & OTP** | Disabled, Read Only, Read / Write | Every call always asks a technician, reading a password or an OTP code included. Turn it on only for agents that hand credentials to your team. | | **Events** | Disabled, Read Only, Read / Write | CyberQP's audit events. | See [CyberQP API](/agents/tools/security/cyberqp-api) for what each profile does. # CyberQP Source: https://docs.neoagent.io/integrations/cyberqp/overview Let Neo agents verify end users, manage just-in-time admin accounts and read your CyberQP customers CyberQP (formerly Quickpass) is a privileged access platform for MSPs: end-user identity verification, admin and service account password rotation, and just-in-time (JIT) admin accounts. Connect it, and Neo agents can use it while they work a ticket. ## What Neo can do with CyberQP * Verify the end user before a password reset or an account change: Neo sends the end user a CyberQP push, and CyberQP adds the result to the ticket. With the **Events** area on, Neo reads the result itself, and makes the change only after a successful verification * Verify every account-change request as it arrives: the **CyberQP Identity Check** agent template sends the push when a new ticket asks for a password reset, an MFA reset or another account change. Available on ConnectWise, Autotask and Halo * Give a technician temporary admin rights at a customer for a ticket: Neo creates or enables a JIT account under your JIT policy, for the duration you allow, and disables it when the work is done. A local admin account goes on the ticket's computer, found through your RMM. Creating or enabling a JIT account always asks a technician first * Install the CyberQP agent through your RMM: Neo runs your own CyberQP install script, in the RMM that manages each device, on the devices you name. A script that asks for the install token and the customer's GUID as variables gets them from CyberQP. When Neo cannot see how a script gets them, it asks a technician before it runs it * Read an account's password or a JIT account's OTP code for a technician who asks in chat. Each read always asks a technician first * Check CyberQP's audit events: who verified, elevated or read a password, and when See [CyberQP API](/agents/tools/security/cyberqp-api) for the permission groups and profiles. ## Your customers are mapped to companies Neo matches your CyberQP customers to the companies in your PSA and keeps the mapping on the CyberQP card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Agents then read a customer's accounts and JIT accounts by its CyberQP id, with no search by name. Matching uses the customer name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **An exact name that matches exactly one of your PSA companies, or a match you confirm, is handed straight to your agents.** A mapping gives an agent that customer's accounts and passwords, so every other match waits for you on the Organization Mapping tab: a match after stripping a legal-form suffix, a name two of your PSA companies share, two CyberQP customers on one company, and an AI match. Confirm or correct each there. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect CyberQP" icon="plug" href="/integrations/cyberqp/connecting-to-neo"> Create CyberQP API credentials and save them in Neo. </Card> # Connecting Datto BCDR to Neo Source: https://docs.neoagent.io/integrations/datto-bcdr/connecting-to-neo Create a Datto Partner Portal API key and save it in Neo You connect Datto BCDR once at the MSP level. ## 1. Create an API key <Steps> <Step title="Open API Keys"> Sign in to the Datto Partner Portal and open **Admin** > **Integrations** > **API Keys**. </Step> <Step title="Create the key"> Click **Create API Key**. Leave the **Client** and **Vendor** fields blank, so the key sees the appliances of every client. Copy the **Public Key** and the **Secret Key**. </Step> </Steps> <Note> Datto allows two API keys per partner organization. If both are already in use by other tools, delete or regenerate one of them first. </Note> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the Datto BCDR card, under Backup & Recovery. </Step> <Step title="Save the key"> Paste the Public Key and the Secret Key and click **Save**. Neo checks them against Datto before saving, so a wrong or deactivated key is rejected straight away. </Step> </Steps> ## 3. Turn Datto BCDR on per agent Open the agent, go to the Integrations section, and configure the Datto BCDR block. Pick a profile, or set each area: | Area | Access levels you can pick | Notes | | - | - | - | | **BCDR Appliances** | Disabled, Read Only | Appliances, their agents and shares, backups, screenshot verification and alerts. This is the area a Datto alert agent needs. | | **Endpoint Backup** | Disabled, Read Only, Read / Write | Endpoint Backup for PCs and Direct-to-Cloud agents. Read / Write lets the agent set an agent's bandwidth limit. | | **Activity Log** | Disabled, Read Only | The Partner Portal activity log. | | **SaaS Protection** | Disabled, Read Only, Read / Write | Microsoft 365 and Google Workspace customers, seats and backups. Read / Write lets the agent license, pause or unlicense seats. | | Profile | Bandwidth limit change | License a SaaS Protection seat | Pause or unlicense a seat | | - | - | - | - | | **Read Only** | Not allowed | Not allowed | Not allowed | | **Helpdesk** | Asks a technician | Asks a technician | Asks a technician | | **IT Admin** | Asks a technician | Runs on its own | Asks a technician | | **Full Automation** | Runs on its own | Runs on its own | Asks a technician | Neo starts at most 20 new Datto requests every 10 seconds for your account. Datto allows 10,000 calls an hour per partner organization, shared by every tool that uses a key of that organization. ## Example: close Datto alerts that have recovered Give an agent that runs on your Datto alert tickets the **Read Only** profile and instructions like these: > For a Datto alert ticket, take the appliance serial from the title and check the appliance in Datto BCDR. For a backup or screenshot alert, read the last backups of the machine named in the ticket. If a backup newer than the alert succeeded and its screenshot verification passed, add a note with the backup time and both results, and close the ticket. For Device Not Seen, close it if the appliance has checked in since the alert. Otherwise, assign the ticket to the backup queue with the error and the time of the last good backup. See [Datto BCDR API](/agents/tools/backup/datto-bcdr-api) for what the agent can read. # Overview Source: https://docs.neoagent.io/integrations/datto-bcdr/overview What the Datto BCDR integration brings to your Neo Agent setup Datto BCDR covers Datto's SIRIS, ALTO and NAS backup appliances and SaaS Protection for Microsoft 365 and Google Workspace. Connect your Datto Partner Portal API key to Neo once, at the MSP level. <Info> Datto BCDR is a different product from Datto RMM, with its own API key. To connect Datto RMM, see [Datto RMM](/integrations/rmm/datto/overview). </Info> ## What Neo can do with Datto BCDR <CardGroup> <Card title="BCDR Appliances" icon="hard-drive"> Find the appliance from a Datto alert ticket. Read its last check-in, storage and active alerts, and the last backups of each protected machine with Datto's screenshot verification result. </Card> <Card title="Endpoint Backup" icon="laptop"> Read Endpoint Backup for PCs and Direct-to-Cloud agents and their last backups. Set an agent's bandwidth limit. </Card> <Card title="Activity Log" icon="list"> See who changed an appliance, agent or client in the Partner Portal, and when. </Card> <Card title="SaaS Protection" icon="cloud"> Check whether a user's mailbox, OneDrive or site is backed up and when it last ran. License, pause or unlicense seats. </Card> </CardGroup> Neo does not start a backup, run a screenshot or clear an alert in Datto. Neo reads Datto's screenshot verification result, never the screenshot image or its link, so a link to a server's screen never reaches a ticket note. ## Your clients are mapped automatically Neo matches your Datto organizations to the companies in your PSA and keeps the mapping on the Datto BCDR card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Neo finds the organizations on your appliances, Endpoint Backup clients and SaaS Protection customers. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Then comes the domain: a SaaS Protection domain that matches the website on a PSA company. Last comes an AI match for the long tail. A name match, or one you confirm, is handed straight to your agents, so they find the right client's appliances. A domain match or an AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Datto BCDR" icon="plug" href="/integrations/datto-bcdr/connecting-to-neo"> Create an API key in the Datto Partner Portal and save it in Neo. </Card> # Connecting Datto EDR to Neo Source: https://docs.neoagent.io/integrations/datto-edr/connecting-to-neo Create a Datto EDR API token and save it in Neo with your console address You connect Datto EDR once at the MSP level. One API token covers every organization its user can see, for both Datto EDR and Datto AV. ## 1. Create a user and an API token for Neo <Steps> <Step title="Add a dedicated user for Neo"> In Datto EDR, open **Admin** > **Users & Tokens** and add a user for Neo. The token acts with that user's role: | Role | What the role allows in Datto EDR | | - | - | | **Admin** | Every action, including AV exclusions and policy changes | | **External Analyst** | Restore or delete quarantined files and run alert responses, only in the organizations you assign to the user | | **Analyst** | Respond to alerts and isolate devices; it cannot restore quarantined files | Datto's [role table](https://edr.datto.com/help/Content/01-getting-started/add-users.htm) lists every action per role. </Step> <Step title="Create the token"> Open **API Tokens**, click **Create new token** for that user, and copy the token. Datto EDR shows it once. </Step> <Step title="Copy your console address"> Copy the address you open Datto EDR at from the browser, for example `https://yourcompany.infocyte.com`. </Step> </Steps> <Warning> A Datto EDR token expires one year after you create it. Create a new token before then and save it here. </Warning> ## 2. Add the token in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Datto EDR**](https://dashboard.neoagent.io/integrations?open=datto_edr), under Security. </Step> <Step title="Save the console address and the token"> Paste the console address and the API token and click **Save settings**. Neo checks them against your console before saving, so a wrong address or token is rejected straight away. </Step> </Steps> ## 3. Turn Datto EDR on per agent <Steps> <Step title="Open the agent"> In the Neo Dashboard, open the agent and its **Integrations** tab. </Step> <Step title="Choose an access profile"> Under **Datto EDR**, choose a profile, or set each permission group by hand. </Step> <Step title="Tell the agent what to do"> Add a line to the agent's instructions, for example: "When a ticket is a Datto AV quarantine, find the alert and the quarantined file in Datto EDR, judge whether it is a false positive, and write what you found in an internal note." </Step> </Steps> | Group | Covers | | - | - | | Alerts | Alerts, alert details, the archive, comments and AI assist answers | | Quarantine and Files | Quarantined files, file reputation, file flags, prevalence and lab submissions | | Response Actions | Isolation, response extensions, AV alert actions, ransomware rollback | | Devices | Devices, device groups, applications, licences, scans and scan tasks | | Exclusions, Policies and Rules | Datto AV exclusions, policies, suppression rules, detection rules | | Organizations and Locations | Your clients' organizations and their locations | | Scan Data | Datto EDR scan data and searches | | Account and Integrations | Users, roles, settings, PSA and RMM set-up, webhooks, reports | | Profile | Runs on its own | Asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read | Every write | | **IT Admin** | Alert archive and comments, scans, searches, lab submission, file retrieval, licence assignment, device, organization and location housekeeping, reports | The writes below | | **Full Automation** | Every other write | The writes below | These always ask a technician, under every profile: * Restoring or deleting a quarantined file, and flagging a file or an application * Every response action: isolate or restore a device's network, kill a process, delete or quarantine a file, run a command, reboot, ransomware rollback * Every exclusion, policy, policy assignment, suppression rule and detection rule change * Uninstalling an agent, removing its licence, approving or denying an agent or a network scanner, and any direct edit of a device record * Deleting an organization or a location * Every change to users, roles, settings, PSA and RMM integrations and webhooks # Overview Source: https://docs.neoagent.io/integrations/datto-edr/overview What the Datto EDR integration brings to your Neo Agent setup Datto EDR and Datto AV (formerly Infocyte) protect your clients' devices from one console: Datto AV quarantines malicious files, and Datto EDR raises alerts and responds on the device. Connect your Datto EDR console to Neo once, at the MSP level. One API token covers both products. ## What Neo can do with Datto EDR * Investigate a Datto AV quarantine or a Datto EDR alert ticket: find the alert, read the quarantined file, its reputation and the device, judge whether it is a false positive, and write what it found in an internal note. * Find the alert from any of the ticket shapes: Datto EDR's own Autotask ticket, a Datto RMM alert ticket (the path for Halo and ConnectWise), or an alert email. * List new quarantines on a schedule, so Low and Medium detections that never become a ticket are still reviewed. * Archive (acknowledge) and comment on alerts, scan devices, and manage devices, organizations and locations. * Restore or delete a quarantined file, isolate a device, run a response, and change exclusions and policies. Each of these asks a technician first. The agent tool and its safety controls: [Datto EDR API](/agents/tools/security/datto-edr-api). ## Your organizations are mapped to clients Neo matches each Datto EDR organization to a client in your PSA and keeps the mapping on the Datto EDR card's **Organization Mapping** tab, refreshed on each PSA metadata sync. With the mapping, a scheduled agent or a Chat Agent reads the alerts and quarantined files of the right client by its Datto EDR organization id. A token for an External Analyst sees only the organizations assigned to that user, so only those are mapped. On Autotask, matching starts with Datto EDR's own Autotask integration, if you use it: when every location of an organization that you mapped to an Autotask account in Datto EDR points to the same account, that account is an exact match. Then comes the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **An Autotask match, a name match, or one you confirm, is handed straight to your agents.** An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right client by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Datto EDR" icon="plug" href="/integrations/datto-edr/connecting-to-neo"> Create an API token in Datto EDR and save it in Neo with your console address. </Card> # Confluence Source: https://docs.neoagent.io/integrations/documentation/confluence Connect Atlassian Confluence Cloud for documentation sync and direct API access from Neo agents Neo Agent integrates with Atlassian Confluence Cloud to automatically synchronize your spaces and pages, and to give agents direct API access to your Confluence content. Once connected, Neo indexes your knowledge base for search, and agents can search and read Confluence pages during ticket resolution. <Info> **One-click connection.** Connecting Confluence takes about 30 seconds. There's nothing to install on your side and no developer account to set up — just sign in to Atlassian and grant access. </Info> ## Connect Confluence <Steps> <Step title="Open the Integrations page"> In the Neo Dashboard, open **Integrations** → find the **Confluence** tile in the Documentation section and click it. </Step> <Step title="Click Connect Confluence"> A popup opens to `auth.atlassian.com` with a consent screen showing the permissions Neo is requesting. <Info> You'll see a small "unverified app" notice from Atlassian. That's expected — it appears for any OAuth integration not listed in the Atlassian Marketplace. Your data is still protected by the standard OAuth flow and the permissions you grant. </Info> </Step> <Step title="Sign in and pick your site"> Sign in with the Atlassian account that has access to the Confluence site you want to connect. If your account has access to multiple Atlassian sites, you'll see a dropdown to choose which site to authorize. Click **Accept** to grant the permissions. </Step> <Step title="Done"> The popup closes and the dashboard flips to a green "Confluence connected" card showing your site URL. <Check> Neo automatically starts the first sync. The next scheduled sync also kicks in so your pages stay current without manual action. </Check> </Step> <Step title="Answer the global-spaces question"> Neo opens the **Global spaces** picker straight after the first connect, and you have to answer it — either tick the spaces whose pages apply to every client and click **Save global spaces**, or click **Skip — nothing is global**. Skip it if every space belongs to one client. You can change the answer any time with **Global spaces** on the connected card. Reconnecting later does not ask again. </Step> </Steps> ## Multiple Atlassian sites If your Atlassian account has access to more than one site and you granted access to several during consent, Neo shows a picker right in the dashboard with the site name, URL, and cloud ID for each. Pick the one Neo should sync. You can change your mind later by clicking **Disconnect** and reconnecting against a different site. ## What gets synced | Content | Status | | - | - | | **Pages** in knowledge bases and global spaces | Synced — title, body, author, last modified, labels | | **Personal spaces** | Skipped — these are per-user, not organizational documentation | | **Drafts and trashed pages** | Skipped | | **Attachments** | Metadata only (file name, URL) — file contents not indexed | | **Comments** | Not synced | Page bodies are converted to clean text for search — headings, lists, tables, code blocks, and panels are all preserved. Labels become searchable tags, and Atlassian user IDs are resolved to display names so "created by" shows the person's actual name. Once synced, your Confluence content is searchable alongside ITGlue, Hudu, and any other documentation sources you've connected. ## Re-sync and trigger sync manually Neo re-syncs Confluence on a schedule automatically. To pull in changes immediately: 1. Open the Confluence tile in **Integrations**. 2. Click **Trigger sync**. The status row shows the progress of the current run. You can also click the refresh icon to re-check status. One Confluence sync runs at a time. While a scheduled or earlier sync is still going, **Trigger sync** tells you a sync is already running. Wait for that run to finish, then trigger again if you still need to. ## Mark global spaces By default, a Confluence space's pages are scoped to the company you've mapped it to on the **Organization Mapping** tab. Some spaces, though, apply to every client — shared runbooks, internal knowledge bases, vendor guides. Mark those spaces **global** so their pages surface in every company's searches. <Steps> <Step title="Open the picker"> On the connected Confluence card, click **Global spaces**. </Step> <Step title="Choose spaces"> Tick any space whose pages should be available to every company. Use the filter to find a space by name or key. Every space you leave unticked stays scoped to its mapped company. </Step> <Step title="Save"> Click **Save global spaces**. Neo re-stamps the already-indexed pages immediately, so the change takes effect without waiting for the next sync. </Step> </Steps> <Info> **Global is explicit.** Only spaces you designate here are shared across companies — a space is never treated as global just because Neo couldn't match it to one. </Info> ## Agent access to Confluence When you enable the **Confluence API** tool on an agent, it can search, read, and — depending on the permissions you grant — create, update, and delete Confluence content directly while resolving tickets. ### Permission groups Each group can be set to **Disabled**, **Read Only**, or **Read/Write**. When a group is set to Read/Write, an additional **Allow Delete** toggle controls whether the agent can issue DELETE requests on that group. | Permission Group | What it controls | | - | - | | **Pages** | Pages and blogposts — read, create, update, delete (also covers comments and labels on pages) | | **Spaces** | Space metadata — read, create, update (whole-space DELETE always blocked, see below) | | **Search** | Run CQL search across pages, blogposts, attachments — read-only by API design | | **Attachments** | Attachments on pages and blogposts — read, upload, delete | | **Users** | Resolve user profiles for content authors — read-only by API design | ### Quick-start profiles <CardGroup> <Card title="Read Only" icon="magnifying-glass"> All 5 groups Read Only. The agent can browse anything your account has Confluence permission to see, but cannot make changes — the typical setting for documentation-aware agents. </Card> <Card title="Documentation Manager" icon="file-pen"> Pages and Attachments **Read/Write**, Spaces / Search / Users Read Only. The agent can create and update pages and upload attachments — ideal for agents that maintain runbooks autonomously — but cannot restructure spaces or delete records. </Card> <Card title="Full Access" icon="bolt"> All 5 groups Read/Write with delete enabled. The agent can create, update, and delete pages, blogposts, comments, labels, and attachments. **Whole-space DELETE is always blocked** regardless of this setting — see below. </Card> </CardGroup> ### Safety controls * **Whole-space DELETE is always blocked.** Deleting a Confluence space orphans every page, blogpost, attachment, and comment inside it. Even with Full Access enabled, the agent cannot delete a space — delete pages individually instead, or have a human do the space deletion in Confluence's UI. * **Allow Delete is per-group and opt-in.** Even on Read/Write groups, the agent cannot delete records unless you explicitly enable the per-group "Allow Delete" toggle. * **Reads never trigger approval.** GET requests pass through without technician-in-the-loop checks. Each Read/Write group has a separate "Require Approval" toggle if you want every write to go through a technician. ## Disconnect Open the Confluence tile and click **Disconnect**. This clears Neo's stored tokens and turns off Confluence sync. Your Confluence data and pages aren't affected. If you also want to revoke Neo's grant on the Atlassian side, visit [id.atlassian.com/manage-profile/apps](https://id.atlassian.com/manage-profile/apps) and remove the **Neo Agent** entry. ## Reconnect Click **Reconnect** to refresh the OAuth grant — useful if Neo notifies you that the connection has expired or you want to re-grant permissions. The flow is identical to the initial connect. ## Security * Tokens are stored in Azure Key Vault, encrypted at rest, never logged in plaintext. * Refresh tokens rotate every time Neo refreshes its access — the previous token is invalidated immediately. * Agent write access is opt-in per permission group, with whole-space DELETE structurally blocked. * All API traffic is over HTTPS. * You can revoke Neo's access at any time from `id.atlassian.com/manage-profile/apps`. # Hudu Source: https://docs.neoagent.io/integrations/documentation/hudu Connect Hudu for documentation sync and direct API access from Neo agents Neo Agent integrates with Hudu to automatically synchronize your documentation and give agents direct API access to your Hudu instance. Once connected, Neo indexes your articles, assets, and procedures for search, and agents can read and manage Hudu resources based on the permissions you configure. <Info> Hudu provides robust API access, so Neo can keep your documentation up to date without manual exports — and agents can interact with Hudu directly during ticket resolution. </Info> <Steps> <Step title="Create an API key in Hudu"> 1. Log in to your Hudu instance. 2. Go to **Admin** → **Account Administration** → **API Keys**. 3. Click **+ New API Key**. 4. Give the key a descriptive name (e.g., "Neo Agent"). 5. If you fill in the key's **IP allow list**, add Neo's IP addresses there — see [IP whitelisting](/integrations/ip-whitelisting). Leaving the field empty allows every address. 6. Copy the API key and store it securely. <Info> For agents with write permissions, the API key must have full access. For read-only documentation sync, a read-only key is sufficient. </Info> </Step> <Step title="Add the Hudu integration in Neo"> 1. In the Neo Dashboard, open **Integrations**. 2. Select the **Documentation** tab and add **Hudu**. 3. Enter your Hudu URL and API key. Examples for your Hudu URL: * `https://your-company.huducloud.com` (cloud-hosted) * `https://hudu.your-domain.com` (self-hosted) </Step> <Step title="Initial sync and ongoing updates"> After saving the integration: * Neo connects to Hudu using your API key and URL * Performs an initial sync of all accessible articles, assets, and procedures * Parses content and metadata, then indexes it in Neo's search engine * Re-syncs periodically to pick up additions, edits, and removals <Check> No manual uploads required. Your Hudu docs stay current automatically. </Check> </Step> </Steps> ## What gets synced Neo syncs the following from Hudu for documentation search: | Content Type | Status | | - | - | | **Articles** (Knowledge Base) | Synced | | **Assets** (structured data) | Synced | | **Procedures** (step-by-step process docs) | Synced | | **Companies** | Synced (for organization) | <Warning> Passwords are **never** imported, accessed, or stored by Neo's documentation sync. Agent access to passwords is controlled separately via permission groups and always requires technician approval for write operations. </Warning> ## Agent API access When you enable the **Hudu API** tool on an agent, it can interact with your Hudu instance directly during ticket resolution — looking up documentation, creating articles, managing assets, and more. ### Permission groups Agent access to Hudu is controlled through **8 permission groups**, each configurable as Disabled, Read Only, or Read/Write: | Permission Group | What it controls | | - | - | | **Companies** | Companies, relations, activity logs, matchers, integration cards | | **Articles** | Knowledge base articles, procedures, uploads, public photos | | **Assets** | Asset records — structured data entries created from asset layout schemas | | **Asset Layouts** | Asset layout definitions — the schemas that define asset structure | | **Passwords** | Asset passwords and password folders | | **Folders** | Documentation folders for organizing articles | | **Infrastructure** | Networks, VLANs, VLAN zones, IP addresses (IPAM), rack storages | | **Websites** | Monitored website entries — uptime and SSL tracking | ### Access profiles For quick setup, choose a preset access profile: <CardGroup> <Card title="Read Only" icon="magnifying-glass"> All 8 groups set to read-only. The agent can look up any Hudu data but cannot make changes. </Card> <Card title="Documentation Manager" icon="file-lines"> Read/write for Articles, Assets, Folders, and Websites. Read-only for everything else. Ideal for agents that create and update documentation autonomously. </Card> <Card title="Full Access" icon="bolt"> All groups read/write with delete enabled. Passwords still require technician approval for write operations. Company deletion is always blocked. </Card> </CardGroup> ### Safety controls * **Passwords always require approval** — write operations on passwords trigger technician-in-the-loop approval regardless of permission settings. * **Company deletion is blocked** — agents cannot delete companies, even with full access. * **Delete must be explicitly enabled** — each permission group has a separate "Allow Delete" toggle. ## Troubleshooting If a sync cannot connect to your Hudu instance, or your instance answers with an error, Neo posts a notification to your dashboard inbox. Unless the item below says otherwise, the notification is action-required, and Neo emails your admins if the problem persists across consecutive syncs: * **Hudu unreachable** — Neo could not open a connection to your Hudu URL at all (timeout, connection refused, or DNS failure). Check that your instance is online and reachable from the internet. Self-hosted instances behind a firewall need Neo's IP addresses whitelisted — see [IP whitelisting](/integrations/ip-whitelisting). * **Hudu server error** — your instance answered, but with an HTTP 5xx server error, and kept doing so after Neo retried. The notification names the status and the API path that failed. Check the health and logs of your Hudu server, or contact Hudu support. On Hudu Cloud (`*.huducloud.com`) the server is Hudu's, so this notification is a warning and is not emailed; contact Hudu support if it persists. If only the procedures request fails this way, Neo skips procedures for that sync, posts no notification, and syncs the rest. * **Hudu rejected the API key** — your instance received the request and refused the key itself. Re-check the API key in the integration settings, and confirm it is still active in Hudu. Allowlisting an IP address will not fix this. * **Hudu refused the request before it reached your account** — Neo's address was refused, so the request never reached your data. Add Neo's IP addresses to whichever of these applies, see [IP whitelisting](/integrations/ip-whitelisting): the **IP allow list on the API key itself** (**Admin** → **Account Administration** → **API Keys** → your key); your account-level **IP Access Control** (**Admin** → **Security** → **IP Access Control**), which also covers the REST API as of Hudu 2.45; and, on a self-hosted instance, your firewall, VPN, reverse proxy, or WAF. Your API key is not the problem here. <Note> Hudu answers an address refusal with the same HTTP status as a rejected key, and names the cause in the response body. When Hudu supplies that marker, Neo reads it and shows the allowlist notification; a 401 with no body, or one Neo does not recognize, falls back to the rejected-key notification. So if you see "Hudu rejected the API key" and a fresh key does not help, check the API key's IP allow list anyway. </Note> A sync that fails this way is retried automatically on the next scheduled run, so a brief outage clears without any action in Neo. ## Security * Documentation sync only reads articles, assets, and procedures — no write access required for sync * Passwords are **never** synced or stored by Neo * Agent write access is opt-in per permission group * All data is encrypted in transit and at rest * API keys are stored in Azure Key Vault, never in plaintext # IT Glue Source: https://docs.neoagent.io/integrations/documentation/itglue-api Connect IT Glue to Neo for automatic documentation sync and full API access Neo Agent integrates with IT Glue for automatic documentation sync **and** full read/write API access to IT Glue resources via the [ITGlue API tool](/agents/tools/documentation/itglue-api). <Frame> <img alt="ITGlue API integration in Neo" /> </Frame> ## Setup <Steps> <Step title="Generate IT Glue API credentials"> 1. In IT Glue, go to **Account** → **Settings** → **API Keys**. 2. Click **Generate API Key**. 3. Copy the API key. Useful references: * [IT Glue: API Documentation](https://api.itglue.com/developer/) </Step> <Step title="Connect IT Glue API in Neo Dashboard"> 1. Go to **Integrations** → **Documentation** tab. 2. Click **Add Integration** and select **ITGlue API**. <Frame> <img alt="Select ITGlue API integration" /> </Frame> 3. Enter your IT Glue API key. <Frame> <img alt="ITGlue API onboarding form" /> </Frame> </Step> <Step title="Answer the general-documentation question"> Under **General documentation**, tell Neo how your IT Glue organizations are laid out. The choice is required — you cannot connect without it. | Answer | What Neo does | | - | - | | **Yes — some organizations hold documentation for every client** | Name each one under **Company Names for General Documentation**. Their documents are shared with every company. | | **No — every organization belongs to one client** | Every synced document stays scoped to its own organization. | Names must match the organization name in IT Glue exactly. Press Enter after each one. <Tip> Typical general organizations are named **General**, **Internal**, **MSP** or **Vendors** — anything holding shared runbooks, internal knowledge bases and vendor guides. </Tip> You can change the answer later: **Integrations** → **IT Glue** → edit the connection. </Step> </Steps> <Info> **Shared documentation is an explicit choice.** A document is shared across companies only if it sits in an organization you named here. Neo never infers it — which is why the question is asked outright rather than left as an optional field. </Info> ## What Gets Synced Once connected, Neo syncs the following daily for search during ticket resolution: | Content Type | Status | | - | - | | **Documents** | Synced | | **Flexible Assets** | Synced | | **Configurations** | Synced | | **Organizations** | Synced (for document organization) | ## Attachments The IT Glue API does not return the contents of a file attached to a document, configuration or password. Kaseya confirms this. Neo reads an attachment's name, type and size, and never what is inside it. A document whose only content is an attached file therefore has no text for Neo to index, so the daily sync skips it. Documentation search cannot find it, and an agent cannot read it. To make that content available to Neo, do one of these: * Move the content into the IT Glue document body, as text or a table. * Put the file in a SharePoint site that [Neo syncs](/integrations/documentation/sharepoint). Neo indexes Word, Excel, PDF and text files there. ## Restricted documents IT Glue lets you mark a document or folder as **Restricted access**. By default, Neo **honors that restriction** — its **internal (technician-facing)** agents won't surface those documents, so a technician can't read through Neo what they can't open in IT Glue. (The IT Glue API itself returns restricted documents to Neo regardless — a single API key sees everything, and IT Glue's per-user permissions aren't exposed to the API — so Neo enforces the restriction on its side.) You can change this from the IT Glue integration: | Setting | What internal agents see | | - | - | | **Exclude restricted documents** (default) | Restricted documents and flexible assets never reach an internal agent — not through documentation search and not through the raw IT Glue API tool. | | **Include restricted documents** | Restricted documents and flexible assets are available to your internal agents, marked confidential — the pre-existing behavior, for teams that want it. | <Info> This is an all-or-nothing tenant choice, not per-technician enforcement — Neo can't reconstruct *who* a document is restricted to, only *that* it is. If you want a trusted subset of staff to keep using restricted docs through Neo, switch to **Include** and instead limit who can message the agent via [Chat Agent Access](/product/rbac#chat-agent-access). </Info> <Note> **End-user (client-facing) agents never see restricted documents**, regardless of this setting — they are always excluded from anything served to your clients. </Note> ## Troubleshooting the connection If saving the integration fails, the error message tells you which of the two causes applies — they have opposite fixes, so read it before changing anything. <AccordionGroup> <Accordion title="IT Glue rejected the API key"> IT Glue refused the key itself. Allowlisting an IP address will not help. * Confirm the key is still listed and enabled under **Account** → **Settings** → **API Keys** in IT Glue. * Re-copy the key — a truncated paste or a trailing space is the usual cause. * Check the **API URL** matches the region your IT Glue account is hosted in. A key issued for the EU or Australia data centre is not valid against the Global URL: | Region | API URL | | - | - | | Global | `https://api.itglue.com` | | EU | `https://api.eu.itglue.com` | | Australia | `https://api.au.itglue.com` | </Accordion> <Accordion title="IT Glue refused the request before it reached your account"> IT Glue blocked Neo at the edge, so the request never reached your account. Your API key is not the problem — re-entering it will not help. This is almost always IT Glue's own **IP Access Control**. In IT Glue, go to **Account** → **Settings** → **IP Access Control**. If it is set to *Allow specific IP addresses*, add [Neo Agent's IP addresses](/integrations/ip-whitelisting) to the list. <Warning> Add **all** of Neo's IP addresses, not just one. Connecting the integration and running the daily sync happen from different Neo services with different outbound IPs, so a partial allowlist produces an integration that connects successfully and then fails to sync. </Warning> </Accordion> </AccordionGroup> ## ITGlue API Tool Beyond sync, agents can interact with the **full IT Glue API** in real time — reading, creating, updating, and deleting documents, flexible assets, configurations, contacts, organizations, and passwords. Access is controlled through [7 permission groups](/agents/tools/documentation/itglue-api) with configurable access levels and technician approval requirements. <Info> See the [ITGlue API tool documentation](/agents/tools/documentation/itglue-api) for permission groups, access profiles, and safety controls. </Info> <Note> **The Neo Support Agent is narrower than this.** Granting someone IT Glue under [AI chat data access](/product/rbac#ai-chat-data-access) gives that person's chat read-only access to every group on this page except **Passwords**, for anyone, admins included, with restricted documents excluded by default per the setting above. A `Password`-kind field on a flexible asset layout belongs to that asset, so it still comes back with it. The 7 groups apply in full to agents you build yourself. </Note> ## Security * **Permission-based access control** across 7 resource categories * **Technician-in-the-Loop** for write operations on sensitive resources * **Password writes always require technician approval**, regardless of settings * **Organization deletion always blocked** * **Restricted documents** can be withheld from internal agents, and are always withheld from end-user agents (see [Restricted documents](#restricted-documents)) * All data encrypted in transit and at rest # Lexful Source: https://docs.neoagent.io/integrations/documentation/lexful Connect Lexful for documentation sync and direct API access from Neo agents Neo Agent integrates with Lexful to synchronize your documentation and give agents direct API access to your Lexful account. Once connected, Neo indexes every asset type your account holds — documents, configurations, contacts, locations, domains, and any custom types you've defined — so agents can pull the right record while resolving a ticket. ## Connect Lexful <Steps> <Step title="Create an API key in Lexful"> 1. In Lexful, open **Settings** → **Platform**, then the **APIs** tab. 2. Under **Generate API key**, give the key a name (for example `neo_api_key`) and click **Generate API key**. 3. Copy the **secret** Lexful shows you. It appears once. If you lose it, use **Regenerate secret** on that key. 4. Under **All API keys**, find your new key and copy its **Key ID** and **Account ID**. <Frame> <img alt="Lexful Platform settings, APIs tab — the Generate API key box, and each key listed with its Key ID and Account ID" /> </Frame> Documentation sync reads your organizations, asset types, and assets, and nothing else. Agent access uses the same key, so anything you let an agent do in Lexful has to be within that key's reach. </Step> <Step title="Add the integration in Neo"> In the Neo Dashboard, open [**Integrations**](https://dashboard.neoagent.io/integrations?open=lexful) → the **Directory** tab → **Documentation**, and click the **Lexful** tile. <Frame> <img alt="The Integrations Directory in Neo, filtered to Documentation, with the Lexful tile" /> </Frame> Fill in four values: | Field | Where it comes from | | - | - | | **API Key ID** | Shown next to the key in Lexful | | **API Key Secret** | Shown only once, when the key is created | | **Account ID** | Your Lexful account identifier | | **API URL** | Prefilled with `https://api.us.lexful.app`. Change it only if your Lexful API settings show a different host | <Frame> <img alt="The Lexful integration form in Neo, with fields for API Key ID, API Key Secret, Account ID, and API URL" /> </Frame> Neo verifies all four against Lexful before it saves them, so a wrong value is refused here rather than failing quietly on the first sync. </Step> <Step title="The first sync starts on save"> Saving the credentials switches Lexful sync on. The first run starts within about 15 minutes, and syncs then run daily. You don't have to wait — **Trigger sync** on the Lexful tile starts a run straight away, unless a sync is already running. <Check> Nothing else to switch on. Once the first run finishes, your Lexful content is searchable through the agent's **Find Documentation** tool alongside every other documentation source you've connected. </Check> </Step> </Steps> ## What gets synced Neo reads your asset types from Lexful at the start of every run, rather than working from a fixed list — so a custom asset type you add is picked up on the next sync with no work on either side. | Content | Status | | - | - | | **Documents** | Synced — the richtext body is converted to clean text for search | | **Configurations, Contacts, Locations, Domains** | Synced — every non-secured property on the record | | **Custom asset types** | Synced, the same way as the built-in ones | | **Passwords** | Never synced — see below | | **Secured property values** | Never synced — see below | | **File attachments** | Not synced — an asset's own properties are indexed, files attached to it are not | Each indexed record carries a link back to the asset in Lexful, the organization it belongs to, and the name of the person who last changed it. ## What is never synced <Warning> Credentials stay in Lexful. Neo's documentation index is shared with end-user-facing search, so anything that is half a credential is kept out of it entirely. </Warning> * **The `system.password` asset type is excluded whole** — not only its secret fields. Neo never requests it. * **Any property Lexful types as `secret` or `totp` is excluded on every asset type** — a location's door code, a custom type's secret field. The exclusion works from the property's type in your Lexful schema, so a new secured field is excluded the day you add it. Neo lists the *names* of an asset's secured properties on the indexed record, so an agent knows a credential exists there, and never the values. An agent can still read a credential live, if you deliberately allow it — that runs through the [Lexful API tool](/agents/tools/documentation/lexful-api), where it needs its own permission group and technician approval. ## Company mapping Neo matches your Lexful organizations to companies in your PSA, so documentation is scoped to the right customer in search. Lexful's API carries no PSA identifier, so every match is inferred, in this order: 1. **Exact name** — the organization name matches a PSA company's. 2. **Name without legal suffix** — "Contoso Contractors Ltd" matches "Contoso Contractors". 3. **Website domain** — the organization's website matches the company's, where your PSA records one. 4. **AI match** — a last resort for the long tail the first three miss. Open the **Organization Mapping** tab on the connected Lexful card to see how each organization resolved, which method matched it, and which ones came back **Unmapped**. You can set or correct a mapping there by hand, and your choice survives every later sync. <Frame> <img alt="The Organization Mapping tab, showing each Lexful organization, the PSA company it resolved to, and the match method" /> </Frame> Documents belonging to an unmapped organization are still indexed and still searchable — they simply aren't scoped to a company. ## Re-sync and see what Neo holds Neo re-syncs Lexful daily. To pull changes in immediately, open the Lexful tile and click **Trigger sync** — the status row shows the current run. One Lexful sync runs at a time. While a scheduled or earlier sync is still going, **Trigger sync** tells you a sync is already running. Wait for that run to finish, then trigger again if you still need to. <Frame> <img alt="The connected Lexful card in Neo, showing Trigger sync, sync status, the document count, and the stored credentials" /> </Frame> The **Documents** tab lists what Neo has indexed from Lexful, so you can confirm a record arrived without running a search. ## Agent access to Lexful Sync makes your documentation searchable. To let an agent read and write Lexful records directly during ticket resolution — live values, non-document asset types, file attachments, or an update it writes back — enable the **Lexful API** tool on the agent and choose its permission groups. See [Lexful API](/agents/tools/documentation/lexful-api). ## Troubleshooting When a sync can't get what it needs, Neo records it in your dashboard inbox: * **Lexful refused the request.** Either your API key was rejected, or Neo's IP address isn't allowed. The message names which. A rejected key is fixed in the integration settings; a blocked IP is fixed by adding Neo's addresses under **Settings** → **Platform** → **IP allowlist** in Lexful — see [IP whitelisting](/integrations/ip-whitelisting). Neo also emails your admins if this persists across two consecutive runs. * **Lexful was unreachable.** The connection timed out or was refused. This is normally a short Lexful outage, so Neo records it without emailing anyone, and the next daily sync recovers on its own. If it persists, check that the API URL in the integration matches the host in your Lexful API settings. ## Security * Your API key secret is stored in Azure Key Vault, encrypted at rest, and never returned to the dashboard in plaintext. * Documentation sync only reads from Lexful. Write access is needed for agent actions, never for sync. * Passwords and secured property values are never indexed, and never leave Lexful through sync. * Agent write access is opt-in per permission group, and any write that sets a credential requires technician approval. * All API traffic is over HTTPS. # SharePoint Source: https://docs.neoagent.io/integrations/documentation/sharepoint Sync client documentation from SharePoint document libraries and map folders to companies for company-scoped search Neo Agent reads documentation from your SharePoint document libraries so agents can search and use it during ticket resolution. You choose which libraries Neo may read, leave out any folders inside them that Neo should not index, and then map top-level folders to the companies they belong to — so a search for one client only surfaces that client's documents. <Info> **No API key.** SharePoint runs on a dedicated Microsoft 365 app — a Microsoft 365 admin consents it once, and you pick which libraries Neo may read. It writes nowhere by default. Nothing else about your Microsoft setup has to change. </Info> ## How Neo reads SharePoint Neo reads SharePoint through the **Neo SharePoint Connector** application, which a Microsoft 365 admin consents on your own tenant. It holds exactly three permissions — two that read, and one that grants nothing until you use it. This is what the consent screen shows you: | Permission | What it allows | | - | - | | `Sites.Read.All` | List your SharePoint sites and their document libraries | | `Files.Read.All` | Read the files inside the libraries you select | | `Sites.Selected` | Nothing, by itself — it only makes per-site write grants *possible*. Neo can write to a site only after your admin explicitly grants that site in [Write access](#write-access-optional). No grants, no writes. | By default Neo never writes to, moves, or deletes anything in SharePoint. Consenting the app leaves it read-only: `Sites.Selected` on its own reaches no site. Write access is a separate, per-site opt-in — and deleting is never possible, even on write-granted sites. The app's permissions are what Microsoft *could* allow; **Read access** is what Neo actually uses. The two are not the same, and the difference is worth knowing: `Sites.Read.All` covers your whole tenant, while Neo confines itself to the libraries you list. Neo's own code enforces that, not Microsoft — so unlike the write grants, it is a promise we keep rather than a wall your tenant puts up. <Info> **This is its own app, on purpose.** SharePoint search doesn't ride the broader **Neo Azure Automations** app that powers Microsoft 365 administration. The two consents are independent in both directions, so you can have SharePoint search without granting Neo any Microsoft 365 admin access at all. </Info> <Warning> **Who can grant consent.** Every tenant starts here — Microsoft permissions only exist where an admin has granted them, so a missing grant is the normal first step, not a misconfiguration. Microsoft accepts consent only from a **Global Administrator**, **Privileged Role Administrator**, or **Cloud Application Administrator**; any other account is sent back to Neo without a grant, and Neo shows Microsoft's own reason (the `AADSTS…` code). If your tenant uses the [admin consent request workflow](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/configure-admin-consent-workflow), the click files a request and access starts once an approver grants it. </Warning> ## Connect SharePoint <Steps> <Step title="Open the SharePoint tile"> In the Neo Dashboard, open [**Integrations**](https://dashboard.neoagent.io/integrations) and click the **SharePoint** tile in the Documentation section. </Step> <Step title="Verify access"> Click **Verify access**. Neo checks whether the Neo SharePoint Connector app can read SharePoint on your tenant. * **Not consented yet** (the usual first time) → an amber **Admin consent needed** notice with a **Grant admin consent** button. An admin opens it and approves the two read permissions; Microsoft returns to Neo, which rechecks the grant itself and opens the library picker. **I've granted consent — recheck** re-runs that check by hand if you need it. * **Consent refused** → a red notice with Microsoft's reason. Almost always the signed-in account isn't one of the three roles above; retry as an admin who is. * **Already consented** → you go straight to the library picker. * **Microsoft didn't answer** → a message saying so, with a retry. Microsoft occasionally can't complete the check on a tenant, and that says nothing about your consent — Neo reports it as unknown rather than asking you to grant consent again. Try again in a few minutes. </Step> <Step title="Choose your document libraries"> Neo lists your SharePoint sites. Expand a site to see its document libraries, and tick the ones you want Neo to sync. You can select libraries across multiple sites. A ticked library syncs whole. To leave part of it out, open the library with the chevron next to its name and untick the folders Neo should not read — former customers, archives, raw exports. A folder inside an unticked folder is left out with it. The library's checkbox turns into a dash while any of its folders are left out, and the row counts them. <Tip> Sync the libraries that hold **client-facing documentation** — runbooks, procedures, network diagrams. You'll map their folders to companies in the next step. </Tip> </Step> <Step title="Connect"> Click **Connect *N* libraries**. Neo saves your selection and starts the first sync. Larger libraries take a little longer on the first run; subsequent syncs only pull in what changed. A very large library — hundreds of thousands of files — can take more than one nightly run to finish. Each run picks up where the last one stopped, and the documents it has already read are searchable straight away, so the library fills in rather than appearing all at once. <Check> The tile flips to a **Connected** view: a connection card with the sync status, **Trigger sync** and **Disconnect**, then **Read access** and **Write access** side by side — each listing exactly what it covers — followed by **Company mappings** and **Global folders**. </Check> </Step> <Step title="Answer the global-folders question"> Neo opens the **Global folders** picker straight after the first connect, and you have to answer it — either tick the folders that apply to every client and click **Save global folders**, or click **Skip — nothing is global**. Each library is listed as **Site / Library**, so libraries that share the default name "Documents" are still told apart by their site. Skip it if every library you connected belongs to one client. You can change the answer any time from **Manage** next to **Global folders**. </Step> </Steps> ## Map folders to companies SharePoint has no built-in notion of which company a folder belongs to, so Neo asks you once. After the first sync, Neo scans the top folders in your libraries (2–3 levels deep), matches each to a company by name, and presents the matches for you to confirm — so you approve a list instead of mapping every folder by hand. <Steps> <Step title="Open the review queue"> On the connected SharePoint page, click **Review** next to **Company mappings** (or open it from a company's linked-systems column on the [Companies](https://dashboard.neoagent.io/companies) page). The row shows how many folders are still unmapped, so you can see at a glance whether anything needs review. </Step> <Step title="Review Neo's matches"> Your folders are listed as a tree, grouped by library and nested the way they sit in SharePoint. Use the chevron next to a library or a folder to open or close a branch. A folder Neo matched to a company starts **closed**, because mapping it already covers everything inside it — a subfolder inherits the nearest mapped folder above it. Folders Neo found no match for stay open, since those are the ones still needing a decision. Open any closed branch to map a subfolder to a different company; the deeper mapping wins. Every folder Neo matched to a company is **ticked for you**, and its row shows how confident the match is: | Match | Meaning | | - | - | | **Exact name** | The folder name matches a company name exactly | | **Close name** / **Domain** | A near match | | **AI guess** | A best-effort suggestion for folders that didn't match by name — always review these | Untick anything you don't want, retarget a folder to a different company with the picker, and click the **✕** to dismiss a folder that isn't client documentation (dismissed folders won't be suggested again). Folders Neo found no match for sit in the same tree with an empty picker — pick a company to map one by hand, or dismiss it. Picking a company ticks the row for you. To work in bulk, use **All** and **None** at the top. They apply to what is on screen, so search first to narrow the list, then tick the result in one click. The checkbox next to a library name does the same for that library. <Note> The deterministic name matches appear straight away. Neo keeps working on the folders that didn't match by name, and any **AI guess** it finds fills in on its own a few seconds later — you can start reviewing before it finishes. </Note> </Step> <Step title="Confirm"> Click **Map *N* folders**. Neo saves the mappings and scopes each folder's documents — and everything beneath it — to that company. **Nothing is applied until you confirm**, and only the rows you kept are mapped. </Step> </Steps> <Info> **Unmapped folders stay private.** A folder you don't map (or dismiss) still syncs, but its documents are **not** shared across companies — they surface only where their own company mapping applies. A subfolder always inherits the nearest mapped folder above it, so you only map at the level that matters. To make a folder's documents available to *every* company, designate it global (below) — global is an explicit choice, never inferred from a folder being unmapped. </Info> <Note> If a mapping saves but Neo can't immediately re-scope the already-synced documents (a transient hiccup), the review queue tells you which folders are affected and offers **Retry re-scoping**. The mappings themselves are always saved. </Note> ## Mark global folders Some documentation applies to every client — shared runbooks, internal knowledge bases, vendor guides. Mark those folders **global** so their documents surface in every company's searches, regardless of folder-to-company mapping. <Steps> <Step title="Open the picker"> On the connected SharePoint page, click **Manage** next to **Global folders**. The row shows how many folders are currently designated global, or **None**. </Step> <Step title="Choose folders"> Browse the library tree and tick any folder — or a whole library — whose documents should be global. Libraries are listed as **Site / Library**. A company-mapped subfolder inside a global folder keeps its own company, so you can share a parent broadly while still scoping specific children. </Step> <Step title="Save"> Click **Save global folders**. Neo re-stamps the already-synced documents immediately, so the change takes effect without waiting for the next sync. </Step> </Steps> <Info> **Global is explicit.** Only folders you designate here are shared across companies. This is a deliberate safeguard — a folder is never treated as global just because Neo couldn't match it to a company. </Info> ## What gets synced | | | | - | - | | **File types** | `.pdf`, `.docx`, `.doc`, `.xlsx`, `.xls`, `.csv`, `.txt`, `.md`, `.html`, `.htm` | | **Size limit** | Files up to 50 MB. Larger files are skipped. | | **Very long files** | A file is indexed up to about 4 MB of text (2,000 passages). Anything past that point in the same file is not searchable. This applies to raw data exports and logs saved as documents; ordinary documents and spreadsheets are far below the limit. | | **Other file types** | Skipped (for example images and video) — only the types above are indexed | | **Spreadsheets** | Sheets and CSV files are indexed as tables, so rows and column headings stay together and can be searched | | **Scanned PDFs** | Skipped. A PDF that is only page images carries no text to read, so Neo cannot index it. Save it with a text layer to make it searchable. | | **Folders you leave out** | Not read, not downloaded, not indexed — and their indexed documents are removed when you save. A file moved into a left-out folder leaves the index on the next sync; a file moved out of one is indexed. See [Leave folders out of a library](#leave-folders-out-of-a-library). | | **Change detection** | Only new and changed files are re-downloaded on each sync; unchanged files are left as-is | | **Deleted folders** | Deleting a folder in SharePoint removes its documents from Neo on the next sync, together with everything in the folders below it. | | **Very large libraries** | The first pass over a very large library can span several nightly runs. Each run continues from where the last one stopped, and documents become searchable as they are read. Deleted files are removed once the pass finishes, so the index is never emptied part-way through. | | **Files Microsoft won't release** | Skipped, then retried. If Microsoft 365 blocks a file — a Defender malware flag, a sensitivity label, a legal hold — Neo skips that file and syncs the rest of the library. A file Neo already indexed keeps the version it last read. Neo asks for a skipped file again on every following sync, so it appears once the block is lifted — you do not have to re-sync the library. | Once synced, your SharePoint documents are searchable alongside IT Glue, Hudu, Confluence, and any other documentation sources you've connected — scoped to the company you mapped their folder to. ## See how much you are syncing The **Sync size** row on the connected card shows two figures: | | | | - | - | | **Selected in SharePoint** | The total size of the libraries you picked, with the folders you left out taken off. It counts the current files, so it is smaller than the storage figure in the Microsoft 365 admin center, which also counts version history and the recycle bin. | | **Indexed by Neo** | The files Neo kept, and the number of searchable passages they became. | Expect the two to differ by a lot. Most of a document library is file types Neo does not index — images, video, archives, installers — so a 400 GB library can produce well under 30,000 files. The passage count is the one that tracks how much Neo carries: a spreadsheet or CSV export splits into thousands of passages, so a few hundred data exports can outweigh every real document in the library. The picker shows the same figures per library and per folder. Open a library and each folder lists its size in SharePoint and how many passages Neo currently holds for it. Use the two together to find a folder that is small on disk and large in the index — a folder of audit-log or report exports is the usual answer — and untick it. <Note> A blank figure means Neo could not read it this time, which is different from zero. Reload the page to ask again. </Note> ## Sync on demand Syncs run automatically on a schedule. To pull in changes right away, click **Trigger sync** on the connected card — the status badge next to it shows whether the last sync succeeded, is still running, or failed, and the details table below it breaks down what each sync step did. One sync per platform runs at a time. While a scheduled or earlier sync is still going, **Trigger sync** tells you a sync is already running. Wait for that run to finish, then trigger again if you still need to. ## Read access — change which libraries and folders Neo reads On the **Read access** row, click **Manage** to open the picker with your current selection pre-ticked. Adjust the set and click **Save libraries**. The library list is the read boundary, not just a sync setting. A library you remove stops syncing *and* stops being readable — agents can no longer open its files, folders, lists or pages, and its documents drop out of search results. A library you add is picked up on the next sync. Agents can still *list* your sites and libraries by name anywhere in the tenant, which is how they find one to ask you about; only the content is confined. ### Leave folders out of a library You can keep a library and still leave part of it out of the index. <Steps> <Step title="Open the library"> In the picker, click the chevron next to a ticked library. Its folders load one level at a time; open a folder to see the folders inside it. The filter box at the top narrows the libraries and the folders you have already opened. </Step> <Step title="Untick the folders to leave out"> Untick a folder and its name is struck through. Everything inside it is left out too — those folders show unticked and cannot be ticked on their own. The library's checkbox turns into a dash and the row shows how many folders are left out. The footer lists what the save will change. </Step> <Step title="Save"> Click **Save libraries**. The save completes at once; Neo then removes the documents it already indexed from the folders you left out in the background — a large folder can take some minutes to drain from search results. From the next sync on, Neo does not read those folders. Tick a folder again and save to bring it back: Neo re-reads that library on the next sync, and only the restored folder's files are downloaded. </Step> </Steps> A click on a library's dash ticks the whole library again, bringing every left-out folder back in one step. <Note> Leaving a folder out affects what Neo indexes for search. Agents with the [SharePoint API tool](/agents/tools/documentation/sharepoint-api) can still open files anywhere in a library you read; the tool follows the library list, not the folder list. </Note> ## Write access (optional) Agents with the [SharePoint API tool](/agents/tools/documentation/sharepoint-api) can also create and update files and list items — but only on sites you name. Write access is off until you complete both steps below, and each step is visible in your own Microsoft admin surfaces. The **Write access** row on the SharePoint card tells you where you are without opening it: | Row shows | What it means | Next step | | - | - | - | | **Not enabled** | The connector has read access only. Nobody has consented `Sites.Selected` on your tenant. | Step 1 below | | **Enabled · no sites** | The consent is in place, and it reaches no site. Neo still cannot write anywhere. | Step 2 below | | **N sites** | Neo may write to those N sites, and to nothing else. | Nothing — open **Manage** to add or remove sites | | **Needs re-consent** | Sites are listed, but the `Sites.Selected` consent is gone from your tenant — so none of them accept writes. Someone removed it in Microsoft Entra. | Step 1 below; your site list is kept | <Steps> <Step title="Enable write consent"> On the SharePoint card, open **Write access** and click **Enable write access**. A Microsoft 365 admin re-consents the Neo SharePoint Connector, which now also carries `Sites.Selected`. This consent grants access to **zero** sites — it only unlocks the next step. </Step> <Step title="Choose the sites"> Pick the sites Neo may write to, then sign in when Microsoft asks. This sign-in is a one-time step that creates the per-site grants inside your own SharePoint; it asks for full site control **for that sign-in only** — Neo requests no refresh token and keeps nothing after the grants are written. Leave **Consent on behalf of your organization** unchecked, so the sign-in permission stays personal to the approving admin. </Step> </Steps> <Info> **Microsoft enforces the boundary, not just Neo.** The per-site grants live in your SharePoint (`Sites.Selected`), so a write to any site you did not grant is refused by Microsoft itself — independent of Neo's own permission checks. The agent-side controls (per-group Read/Write levels and technician approval) sit on top of that. </Info> The sign-in permission from step 2 can be removed afterwards in **Microsoft Entra → Enterprise applications → Neo SharePoint Connector → Permissions**; the per-site write grants stay in place. **Removing a site**: in the Write access list, remove the site — Neo stops writing to it immediately. The grant record inside SharePoint stays; to remove that too, an admin runs `Revoke-PnPAzureADAppSitePermission` (PnP PowerShell) or removes it from the site's permissions. ## Disconnect On the connected card, click **Disconnect** and confirm. Neo stops syncing SharePoint and its synced documents stop updating. Your SharePoint content and the admin-consent grant on your tenant are not affected — reconnecting later picks up where you left off. ## Security * The Neo SharePoint Connector app declares exactly `Sites.Read.All`, `Files.Read.All`, and `Sites.Selected` — read access plus the *capacity* for per-site write grants. Consenting it grants read access and nothing more: writes require the explicit per-site grants described under [Write access](#write-access-optional), which only your own admin can create. * Deletion is impossible through Neo on every site, including write-granted ones. * Access runs on **your own tenant**; there are no separate credentials to manage, and you can revoke it at any time from **Enterprise applications** in the Microsoft Entra admin center. * Folder→company mappings are only ever the ones you explicitly confirm — Neo never auto-applies a mapping. * All traffic is over HTTPS, and synced content is isolated per tenant. # Connecting Domotz to Neo Source: https://docs.neoagent.io/integrations/domotz/connecting-to-neo Save a Domotz API key and its endpoint in Neo, and decide what each agent can do You connect Domotz once at the MSP level, then turn it on per agent. ## 1. Create an API key <Steps> <Step title="Open API Keys"> Sign in to the Domotz Portal and open **Settings**, then **Services**, then **API Keys**. </Step> <Step title="Create a key for Neo"> Create a key and name it so you know Neo uses it. The key sees every collector your Domotz account can see. </Step> <Step title="Copy the key and its endpoint"> Copy the key, and the API endpoint shown next to it. The endpoint depends on your region, for example `https://api-us-east-1-cell-1.domotz.com/public-api/v1/` in the US or `https://api-eu-west-1-cell-1.domotz.com/public-api/v1/` in the EU. A key works only at the endpoint shown with it. </Step> </Steps> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> Open [**Integrations**](https://dashboard.neoagent.io/integrations?open=domotz) and find **Domotz** under **Networking**. </Step> <Step title="Save the key"> Paste the endpoint into **API endpoint** and the key into **API key**, then click **Save**. The endpoint works with or without the `/public-api/v1/` path. Neo lists your collectors with the key before it saves, so a refused key shows an error and is not saved. The **Organization Mapping** tab fills after the save, and again on each nightly PSA sync. </Step> </Steps> ## 3. Turn Domotz on per agent Open the agent, go to the Integrations section, and configure the Domotz block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Read collectors, devices, history, alerts and Organizations. Nothing is changed. </Card> <Card title="Helpdesk" icon="headset"> Resolve alerts on its own. Every other change waits on a technician. </Card> <Card title="IT Admin" icon="user-gear"> Change devices, run power actions, resolve alerts and manage Organizations on its own. Monitoring Coverage, Collector Settings and Users & Account changes wait on a technician. </Card> <Card title="Full Automation" icon="bolt"> Manage devices, monitoring, collector settings, Organizations, users, alerts and power actions without approval. Deleting a collector or an Organization still waits on a technician. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Collectors & Devices** | Disabled, Read Only, Read/Write | Collectors and their devices, with status, history, metrics, sensors and device profiles. Write edits a device's details and inventory values, tags it, adds a sensor or an external host, sets device credentials and SNMP settings, applies a device profile, and starts a configuration backup. | | **Collector Settings** | Disabled, Read Only, Read/Write | Scan and interface policies, DHCP discovery, routed networks, service ports, the collector's default SNMP credentials, VPN sessions (list and close), moving a collector to another team, and deleting a collector. A collector deletion always waits on a technician. | | **Monitoring Coverage** | Disabled, Read Only, Read/Write | Alert rules and their bindings to collectors, devices and contact channels, alert profile bindings, excluded and hidden devices, monitoring state, and deleting a device, sensor or trigger. These writes can stop an alert. | | **Alerts** | Disabled, Read Only, Read/Write | Alert events, rules, profiles and contact channels. Write resolves an alert. | | **Device Actions** | Disabled, Read Only, Read/Write | Power on, off or cycle through a PoE switch port or PDU outlet, software reboot, outlet actions, running and binding custom drivers. | | **Organizations** | Disabled, Read Only, Read/Write | The Domotz Organizations, which collectors belong to each, and their contacts. Write creates, changes and deletes them. An Organization deletion always waits on a technician. | | **Users & Account** | Disabled, Read Only, Read/Write | Domotz users, user groups and roles, areas and teams, and the account's tag and inventory field definitions. | Each area also has its own technician approval setting. ## Example: a device is offline Give an agent that runs on your Domotz alert tickets the **Helpdesk** profile and instructions like these: > For a device-offline ticket, find the device in Domotz and check the other devices on the same collector. If the whole site is down, say so on the ticket and stop. If only the device is down and it sits on a PoE switch port or PDU outlet, power cycle it. When the device is back, resolve the Domotz alert and add a note with what you did. The power cycle waits on a technician's approval. See [Domotz API](/agents/tools/networking/domotz-api) for what the agent can read and change. ## Safety controls * **You decide what waits on a technician.** Each area has its own approval setting. Helpdesk asks before every change except resolving an alert; IT Admin asks before a Monitoring Coverage, Collector Settings or Users & Account change; Full Automation asks on nothing else. * **Two deletions always wait on a technician.** Deleting a collector, which removes the site and its whole history, and deleting an Organization both wait for approval, whatever the settings. * **Changes that stop alerts have their own area.** Hiding a device, setting it unmanaged, unbinding an alert rule or deleting a sensor all sit in Monitoring Coverage, so you can keep them behind approval. * **No access links, secrets or images.** Neo refuses these before it calls Domotz: opening a remote connection to a device or a collector VPN session, the text of stored device configurations, and camera snapshots. Neo removes SNMP community strings and keys from every Domotz response before an agent or a script sees it. * **No unnamed bulk deletes.** Neo refuses the bulk delete of a collector's offline devices and the wipe of the account's whole inventory. * **Only Domotz hosts.** Neo refuses an API endpoint whose host is not a Domotz API host. * **Path safety.** A URL path with a `..` segment is rejected before it reaches Domotz. ## Disconnecting Domotz In the Neo Dashboard, open **Integrations**, select the Domotz card, click **Disconnect** and confirm. Neo removes the key from Key Vault. Agents that use Domotz stop working until you connect it again. Your Organization Mapping is kept, including any mapping you set by hand. ## Security * The key lives in Azure Key Vault. It is never stored in plaintext. * All traffic goes over HTTPS to the Domotz API endpoint you saved. * Write access is opt in per agent and per area. # Overview Source: https://docs.neoagent.io/integrations/domotz/overview What the Domotz network monitoring integration brings to your Neo Agent setup Domotz monitors the networks at your clients' sites: a collector at each site finds the devices on the network and watches their status, latency and power. The tickets it causes are routine. A device went offline, the internet is slow, an IP conflict, a frozen access point. Connect Domotz to Neo and your agents check the site from the ticket, power cycle the device through its switch port, and resolve the alert once the device is back. <Info> Domotz uses one API key per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with Domotz <CardGroup> <Card title="Collectors & Devices" icon="network-wired"> Tell whether the site is down or just one device, see when a device dropped off, and read latency, packet loss, internet speed history and IP conflicts. Record a device's name, type, room and notes, tag it, or add a sensor to watch a service. </Card> <Card title="Alerts" icon="bell"> Read the alert behind a ticket, the rule and profile that raised it, and resolve it once the device is back. </Card> <Card title="Device Actions" icon="power-off"> Power cycle a frozen access point, camera or phone through its PoE switch port or PDU outlet, so nobody drives to the site. </Card> <Card title="Monitoring Coverage" icon="eye"> Stop alerting on a device the client retired, or bind the right alert rule to a new switch. </Card> <Card title="Collector Settings" icon="sliders"> Add a routed subnet a new branch office brought, change a scan policy, or close a VPN session left open. </Card> <Card title="Organizations" icon="building"> Find every collector of the ticket's client, and keep a new site and the client's contacts filed under the right Organization. </Card> <Card title="Users & Account" icon="users"> Give a new technician a Domotz login or remove a leaver's, from an onboarding or offboarding ticket. </Card> </CardGroup> ## Your clients are mapped automatically Neo matches each Domotz collector to a company in your PSA and keeps the mapping on the Domotz card's **Organization Mapping** tab. It refreshes the mapping when you save the API key, and again on each nightly PSA sync. A client with several sites has one collector per site, so several collectors map to one company. Matching starts with the name of the Domotz Organization the collector is bound to, then the collector's own name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the rest. **A name match, or one you confirm, is handed straight to your agents**, so they start from the client's collectors without looking them up. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Domotz" icon="plug" href="/integrations/domotz/connecting-to-neo"> Save an API key in Neo and choose what each agent can do. </Card> # Connecting Duo to Neo Source: https://docs.neoagent.io/integrations/duo/connecting-to-neo Create a Duo Admin API application and save its integration key, secret key and API hostname in Neo Neo connects to Duo through an Admin API application. Duo includes the Admin API in the Duo Essentials, Advantage and Premier plans, and only a Duo administrator with the **Owner** role can create the application. ## 1. Create an Admin API application for Neo <Steps> <Step title="Add the application"> Log in to the Duo Admin Panel and open **Applications** > **Application Catalog**. Find **Admin API** and click **+ Add**. With a Duo MSP account, do this in your own (parent) account. One application there reaches every client subaccount, so you do not create one in each subaccount. </Step> <Step title="Copy the keys and the hostname"> On the application's page, copy the **Integration key**, the **Secret key** and the **API hostname** (for example `api-1a2b3c4d.duosecurity.com`). Treat the secret key like a password. </Step> <Step title="Tick the permissions"> Tick the permissions for what you want Neo to do. The first three cover the lockout and onboarding work: | Duo permission | What it lets Neo do | | - | - | | **Grant resource - Read** and **Grant resource - Write** | Users, phones, tokens, bypass codes, groups, devices and policies, and the verification Duo Push | | **Grant read log** | Authentication, administrator and telephony logs, to see why a user was denied or locked out | | **Grant read information** | The account summary and usage | | **Grant identity verification - Read** and **- Write** | Duo identity verification of a user | | **Grant administrators - Read** or **- Write** | Duo administrators, roles and administrative units | | **Grant applications** | The applications Duo protects | | **Grant settings** | Global account settings and branding | Tick **Grant set Admin API permissions** only if you want Neo to grant Admin API permissions to another Duo application. Neo asks a technician before every such grant. Leave it unticked otherwise. </Step> <Step title="As an MSP, tick the subaccount permissions"> Under **Subaccount permissions**, tick **Grant accounts - Read**, so Neo can list your client subaccounts, and the same permissions you ticked above. Without them, Neo sees only your own account and none of your clients. Tick **Grant accounts - Write** only if you want Neo to create subaccounts and set a subaccount's edition and telephony credits, and **Grant user limits - Read** and **- Write** for a subaccount's user limit. </Step> <Step title="Optionally restrict the networks"> **Networks for API Access** limits where the application can be used from. Leave it empty to allow any network, or add [Neo's IP addresses](/integrations/ip-whitelisting). If you restrict it and leave out one of Neo's addresses, Duo refuses some of Neo's requests. </Step> <Step title="Save the application"> Scroll to the bottom of the page and click **Save**. </Step> </Steps> ## 2. Add the keys in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Duo**](https://dashboard.neoagent.io/integrations?open=duo), under Security. </Step> <Step title="Save the keys and the hostname"> Paste the API hostname, the integration key and the secret key, and click **Save settings**. Neo signs a request to Duo with them before saving, so a mistyped key or hostname is rejected straight away. The check reads one user, so it also rejects keys of another application type and an Admin API application without **Grant resource - Read**. Any other missing permission is not caught here: Duo refuses that call later, when an agent makes it. </Step> </Steps> ## 3. Turn Duo on per agent <Steps> <Step title="Open the agent"> In the Neo Dashboard, open the agent and its **Integrations** tab. </Step> <Step title="Choose an access profile"> Under **Duo**, choose a profile, or set each permission group by hand. </Step> <Step title="Tell the agent what to do"> Add a line to the agent's instructions, for example: "When a user is locked out of Duo, verify the caller with a Duo Push, then set the user active again and note what you did on the ticket." </Step> </Steps> | Profile | Runs on its own | Asks a technician | | - | - | - | | **Read Only** | Every read | No write is allowed | | **Helpdesk** | Every read, and the verification Duo Push | Changes to users, phones, bypass codes and groups. Other areas are read only | | **IT Admin** | Changes to users, phones and groups, and the verification Duo Push | Changes to bypass codes, devices, applications and subaccounts, plus the changes that always ask | | **Full Automation** | Every change except the ones below that always ask | The changes that always ask | Under every profile, a technician approves setting a user or group to bypass, adding a user to a group, creating bypass codes, deleting a phone, hardware token, security key or desktop authenticator, detaching a phone or token from a user, every policy, account setting and administrator change, creating or deleting an application, resetting its secret key or granting it Admin API permissions, and changing a subaccount's edition, telephony credits or user limit. The [Duo API](/agents/tools/security/duo-api) page lists the permission groups and what Neo never sends. ## Client subaccounts Neo finds each client's subaccount by its account id and sends the call to that subaccount's own API hostname. Each subaccount is mapped to a client in your PSA on the Duo card's **Organization Mapping** tab; see [Duo overview](/integrations/duo/overview#your-subaccounts-are-mapped-to-clients). With **Grant accounts - Read** ticked, an agent on a ticket reaches only the subaccount mapped to the ticket's client, and never your own account when the client has no mapped subaccount, so map every client you want agents to work on. Without it, Neo may not know your subaccounts, and a ticket call without an account id can then reach your own account. # Overview Source: https://docs.neoagent.io/integrations/duo/overview What the Duo integration brings to your Neo Agent setup Duo (Cisco Duo) puts MFA in front of your clients' sign-ins, and most Duo tickets are a user who is locked out, has a new phone, or is joining or leaving. Neo connects to Duo through one Admin API application. As an MSP with a Duo MSP account, you create that application once in your own account, and it reaches every client subaccount. ## What Neo can do with Duo * Clear an MFA lockout: find the user, read why Duo locked them out, verify the caller with a Duo Push to their phone, and set the user active again. * Onboard a new starter: create the Duo user, put them in the right group, add their phone and have Duo send the enrollment email or the Duo Mobile activation SMS. * Offboard a leaver: disable or remove the Duo user and remove their phones, tokens and bypass codes. * Explain a denied sign-in from the authentication log, and which policy applies to a user and an application. * Manage groups, devices, policies, applications and administrators when you allow it. The agent tool, its access profiles and its safety controls: [Duo API](/agents/tools/security/duo-api). ## How Neo verifies a caller Before Neo or a technician changes a locked-out user, the agent can send a verification Duo Push to a phone on the user's Duo account and read whether the user approved or denied it. Duo keeps the answer for 120 seconds; a push with no answer by then has timed out. The push shows a confirmation code, and the agent gets the same code, so a technician on the phone can ask the caller to read it back. Verifying a caller needs a phone that is activated for Duo Push. A user who has lost their phone cannot approve a push, so verify them another way before you approve a change. ## Your subaccounts are mapped to clients Neo matches each Duo client subaccount to a client in your PSA and keeps the mapping on the Duo card's **Organization Mapping** tab, refreshed on each PSA metadata sync. With the mapping, an agent works in the right client's subaccount for each ticket. When the Admin API application lacks **Grant accounts - Read** under Subaccount permissions, or your Duo account has no subaccounts, Neo cannot read a subaccount list and maps nothing new. Mappings from an earlier sync stay on the tab as they were. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. A name match, or one you confirm, is handed straight to your agents. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right client by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Duo" icon="plug" href="/integrations/duo/connecting-to-neo"> Create an Admin API application in the Duo Admin Panel and save its keys in Neo. </Card> # Connecting Hornetsecurity to Neo Source: https://docs.neoagent.io/integrations/hornetsecurity/connecting-to-neo Save a Hornetsecurity API access token in Neo, and decide what each agent can do You connect Hornetsecurity once at the MSP level, then turn it on per agent. ## 1. Create an API access token <Steps> <Step title="Sign in as a partner admin"> Sign in to the Hornetsecurity Control Panel as an admin at your partner level, so the token reaches every client. A token acts as the user who created it and sees what that user sees. </Step> <Step title="Create the token"> Open **User settings** in the top-right menu, then the **API Token** tab, and click **Create token**. Give it a name, set an expiry if you want one, and copy the token. </Step> </Steps> ## 2. Add the token in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the Hornetsecurity 365 Total Protection card, under Security. </Step> <Step title="Save the token"> Paste the token without the `Token ` prefix and click **Save**. Neo checks it against Hornetsecurity before saving, so a wrong or expired token is rejected straight away. The **Organization Mapping** tab fills separately after the save, and again on each nightly PSA sync. </Step> </Steps> ## 3. Turn Hornetsecurity on per agent Open the agent, go to the Integrations section, and configure the Hornetsecurity block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Search email and look up clients. Nothing is released or changed. </Card> <Card title="Helpdesk" icon="headset"> Release, reclassify and delete held email, and edit allow and deny lists, with technician approval. </Card> <Card title="IT Admin" icon="user-gear"> Release, reclassify and delete held email on its own. Allow and deny list edits wait on a technician, because an allow entry can quietly weaken protection. </Card> <Card title="Full Automation" icon="bolt"> Release, reclassify and delete held email, and edit allow and deny lists, without approval. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Emails** | Disabled, Read Only | Search the email log and read one email's detail and header. | | **Quarantine Actions** | Disabled, Read Only, Read and Write | Release, release and allow the sender, reclassify, delete. | | **Allow & Deny Lists** | Disabled, Read Only, Read and Write | Entries for a client or one user. | | **Customers** | Disabled, Read Only | Client lookup and the partner hierarchy. | | **Mailboxes** | Disabled, Read Only | Mailboxes, aliases and groups. | | **Domains** | Disabled, Read Only | Protected domains. | ## Safety controls * **You decide what waits on a technician.** Each area has its own approval setting. Helpdesk asks on every quarantine action and list edit; IT Admin asks on list edits; Full Automation asks on nothing. * **Threats are named.** When the agent releases an email Hornetsecurity classed as a threat, it says so on the ticket. Hornetsecurity itself may refuse the release for your account. * **Only what the job needs.** Neo sends only email search and actions, allow and deny lists, and client, mailbox and domain lookups. Token management, backup, e-learning and every other Control Panel area are unreachable, and so is delivery to Hornetsecurity's support desk. * **Path safety.** Suspicious URL paths (anything containing `..`, for example) are rejected before they reach Hornetsecurity. ## If Hornetsecurity refuses Neo's requests | What comes back | Cause | Fix | | - | - | - | | `401` | The token expired or was deleted | Create a new token and save it in Neo | | `403` | The token's user may not act on that client, or may not release that classification | Create the token as a partner-level admin, or release the email in the Control Panel | | `429` | Rate limited | Wait. The agent does not retry within the same run | | A failed **Hornetsecurity 365 Total Protection Company Mapping** row with a `401` or `403` | The same token problem, met by the nightly mapping | Fix the token as above. The next PSA sync rebuilds the mapping | ## Disconnecting Hornetsecurity In the Neo Dashboard, open **Integrations**, select the Hornetsecurity card, click **Disconnect** and confirm. Neo removes the token from Key Vault. Agents that use Hornetsecurity stop working until you connect it again. Your Organization Mapping is kept, including any mapping you set by hand. ## Security * The token lives in Azure Key Vault. It is never stored in plaintext. * All traffic goes over HTTPS to `cp.hornetsecurity.com`. * Write access is opt in per agent and per area. # Overview Source: https://docs.neoagent.io/integrations/hornetsecurity/overview What the Hornetsecurity 365 Total Protection integration brings to your Neo Agent setup Hornetsecurity 365 Total Protection filters email for your clients. The same platform is sold as Proofpoint 365 Total Protection. The most common ticket it causes is "an email I need was held, please let it through". Connect Hornetsecurity to Neo and your agents can find the held email, release it to the user, and allow the sender, from the ticket. Nobody opens the Control Panel. <Info> Hornetsecurity uses one API access token per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with Hornetsecurity <CardGroup> <Card title="Emails" icon="magnifying-glass"> Search a client's email log: who sent it, when, how it was classified (spam, threat, content), and whether it was delivered, with the reason. </Card> <Card title="Quarantine Actions" icon="envelope-open"> Release a held email to its recipient, release it and allow the sender in one step, reclassify it, or delete it. </Card> <Card title="Allow & Deny Lists" icon="list-check"> Add a sender, domain or IP address to a client's or a user's allow list or deny list, and remove an entry. </Card> <Card title="Customers" icon="building"> Find the client behind a ticket by its domain, and list the clients under your partner account. </Card> </CardGroup> Mailboxes and Domains are also available, read only: a client's protected mailboxes, aliases and domains. ## Your clients are mapped automatically Neo matches your Hornetsecurity customers to the companies in your PSA and keeps the mapping on the Hornetsecurity card's **Organization Mapping** tab, refreshed on each PSA metadata sync. It reads every customer under your partner account, including those under sub-partners. Matching starts with the Microsoft 365 tenant: a customer protecting the same tenant Neo has on a company is an exact match. Then comes the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Then the domain, for customers named by their domain, against the website on each PSA company. Last comes an AI match for the long tail. **A tenant match, a name match, or one you confirm, is handed straight to your agents**, so they know the client's Hornetsecurity customer without looking it up. A domain match or an AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it, and an agent that looks the company up can still find it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Hornetsecurity" icon="plug" href="/integrations/hornetsecurity/connecting-to-neo"> Save an API access token in Neo and choose what each agent can do. </Card> # Connecting Huntress to Neo Source: https://docs.neoagent.io/integrations/huntress/connecting-to-neo Generate a Huntress API key pair, save it in Neo, and decide what each agent can do You connect Huntress once at the MSP level, then turn it on per agent. Setup takes a few minutes. <Info> Huntress uses one API key pair (a public key and a secret key) per Huntress account. There is no per-customer URL — organizations are scoped inside the API, so one key pair covers every customer in the account. </Info> ## 1. Generate an API key pair in Huntress <Steps> <Step title="Open API Credentials"> Sign in at `<your-subdomain>.huntress.io` as a user with **Admin** privileges, open the hamburger menu in the top-right corner, and choose **API Credentials**. If you don't see the option, you're signed in as a non-Admin user — an Admin on your account can create the key, or grant you the role. </Step> <Step title="Decide which key you need"> Huntress offers an account key and user-based keys. **The default account API key is read-only.** If you want Neo to isolate hosts, approve remediations, resolve incidents, or manage organizations and users, generate a **user-based key** whose Huntress user holds those portal permissions. <Tip> Create the user-based key against a dedicated Huntress user (for example "Neo Agent") rather than a person's login, so the audit trail in Huntress names the automation and the key survives staff changes. </Tip> </Step> <Step title="Generate and copy both values"> Click **Setup**, then **Generate**. Huntress shows the **API Secret Key only once** — copy both the public key and the secret before leaving the page. If you lose the secret, regenerate the pair; you cannot retrieve it later. </Step> </Steps> ## 2. Add the keys in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the **Huntress** card under **Security**. </Step> <Step title="Save both values"> Paste the API Key and the API Secret, then click **Save**. <Check> Neo tests the pair by reading the Huntress account the credentials belong to. If either value is wrong, the save fails so you can fix it before moving on. </Check> </Step> </Steps> Neo stores the secret encrypted and only ever shows it masked afterwards. The public key stays visible so you can confirm which key pair is connected. ## 3. Turn Huntress on per agent Each agent decides whether it uses Huntress and which areas it can touch. Open the agent, go to the **Integrations** section, and configure the Huntress block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area read only. The agent can investigate any alert, host, or report but never changes anything. Best for triage, reporting, and QBR agents. </Card> <Card title="Helpdesk" icon="headset"> Incidents at read/write — still behind technician approval on every write — and read-only everywhere else. Enough to work an alert to resolution without touching hosts, access rules, or users. </Card> <Card title="IT Admin" icon="user-shield"> Every writable area at read/write, with technician approval required on all writes. The cautious rollout tier. </Card> <Card title="Full Automation" icon="bolt"> Access rules and organization changes run autonomously. Host isolation, remediation approval, incident resolution, and portal access changes still require technician approval — that cannot be turned off. The [Huntress API tool](/agents/tools/security/huntress-api#safety-controls) reference lists every action that always needs approval. </Card> </CardGroup> ### Or set each area yourself | Permission group | Access levels | | - | - | | **Incidents** | Disabled / Read Only / Read-Write | | **Agents** | Disabled / Read Only / Read-Write | | **Unwanted Access Rules** | Disabled / Read Only / Read-Write | | **Organizations** | Disabled / Read Only / Read-Write | | **Users** | Disabled / Read Only / Read-Write | | **Detections** | Disabled / Read Only | | **Reporting & Billing** | Disabled / Read Only | Detections and Reporting & Billing are read-only because the Huntress API has no write endpoint for them. <Note> Changing a customer's Huntress subscription is deliberately not exposed to agents, even though the Huntress API supports it. Reporting & Billing is read-only for reconciliation and QBRs, not for buying. </Note> ## Disconnecting Huntress <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the Huntress card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault. </Step> </Steps> Your Organization Mapping is kept, including any mapping you set by hand, so reconnecting later picks up where you left off. Agents that use Huntress stop working until you connect it again. ## Troubleshooting | What you see | What it means | | - | - | | Save fails immediately | One of the two values is wrong, or API access is not enabled for your Huntress account. Regenerate the pair and re-enter both. | | Reads work but a write fails with "not found" | The connected key lacks that portal permission. Huntress returns the same "not found" response for "doesn't exist" and "you can't touch it" — the default account key is read-only, so generate a user-based key. | | Calls start failing under load | Huntress rate limits each account to 60 requests per minute. Neo backs off, but an agent doing a very wide sweep can hit it — narrow the query, or scope it to one organization. | | It worked for months, then an agent says the credentials must be regenerated | The key pair was regenerated or deleted in Huntress after you saved it in Neo, so Huntress now rejects it. Generate a new pair and re-enter both values here. Until you do, every Huntress read and write is refused: agents cannot query or change anything in Huntress, and Organization Mapping stops refreshing its Huntress links. The PSA sync itself keeps running, and the rest of Neo is unaffected. | # Overview Source: https://docs.neoagent.io/integrations/huntress/overview What the Huntress integration brings to your Neo Agent setup Huntress is the managed EDR/MDR platform many MSPs run across their whole fleet. Connecting it to Neo means your agents can read the alert behind a Huntress-generated ticket, gather the evidence, and — with your approval — act: approve the remediation, isolate the host, resolve the incident, or file the travel exception that stops the escalation recurring. <Info> Huntress uses one API key pair per Huntress account. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with Huntress <CardGroup> <Card title="Incidents" icon="triangle-exclamation"> Read incident reports and escalations with their full findings and remediation steps, approve or reject remediations, and resolve the incident once the work is done. </Card> <Card title="Agents" icon="desktop"> Look up any deployed host by name, organization, platform, or version. Edit host tags and tamper protection, isolate a compromised host from the network or release it, and uninstall the Huntress agent from a host, for offboarding or before a reinstall. </Card> <Card title="Detections" icon="magnifying-glass"> Investigate the evidence: signals, managed identities and their MFA and risk state, externally exposed ports, platform actions, and SIEM log queries. Read-only. </Card> <Card title="Unwanted access rules" icon="plane"> Create time-boxed travel and geolocation exceptions with an automatic expiry date, plus VPN and IP rules — so a user abroad stops generating unwanted-country escalations without anyone permanently whitelisting a country. </Card> <Card title="Organizations" icon="building"> Enumerate the customers under your Huntress account, and create, rename, or remove organizations during onboarding and offboarding. </Card> <Card title="Reporting" icon="chart-line"> Read monthly, quarterly, and yearly summary reports for QBRs and security-posture reviews, plus account and reseller invoices. Read-only. </Card> </CardGroup> ## Why connect Huntress 1. **The alert context arrives with the ticket.** A Huntress-generated ticket normally sends a technician into the Huntress portal to find out what actually happened. With the integration, the agent pulls the incident report, its indicators, and the affected host into the ticket before anyone opens it. 2. **Containment and remediation stay one approval away.** Isolating a host and approving remediations are single actions the agent can prepare and a technician can approve, instead of a portal round trip under time pressure. 3. **Recurring geolocation noise becomes self-cleaning.** Travel exceptions get created with an expiry date, so the exception disappears on its own when the trip ends. 4. **Posture and billing data feeds reporting agents.** Summary reports and invoices are readable, so QBR and reconciliation agents work from Huntress's own numbers. ## How agents reach Huntress When you enable any Huntress permission group on an agent, Neo automatically adds the Huntress tool to that agent's toolbox. Nothing to install, no toolbox tweaking. Every call uses the key pair you saved in the dashboard and stays inside the areas and access levels you allowed. Some Huntress actions are always gated behind technician approval, whatever the agent's automation level: **isolating a host or uninstalling its Huntress agent, approving or rejecting remediations, resolving an incident or escalation, and any change to who has Huntress portal access.** ## Where to go next <CardGroup> <Card title="Connecting Huntress to Neo" icon="plug" href="/integrations/huntress/connecting-to-neo"> Generate the API key pair, save it in Neo, and decide what each agent can do. </Card> <Card title="Huntress API tool" icon="wrench" href="/agents/tools/security/huntress-api"> The tool reference: permission groups, access profiles, and safety controls. </Card> </CardGroup> # Overview Source: https://docs.neoagent.io/integrations/intro Connect your tools to allow Neo to work across your PSA, RMM, M365, documentation, and more Neo integrates with the typical MSP stack to automate and streamline operations. Most tools in [**Integrations → Directory**](https://dashboard.neoagent.io/integrations?tab=directory) show what Neo can do with them when you hover over the card or open the tool. If you can create agents and message Neo Support, each use case also has a **Set up with Neo** button that opens Neo Support with the request ready to send. <Warning>Connecting your PSA first is mandatory to allow Neo to start reading and automating from incoming tickets in your PSA</Warning> <CardGroup> <Card title="PSA" icon="ticket" href="/integrations/psa/intro"> Automates ticket management, client data synchronization, and workflow orchestration. </Card> <Card title="Documentation" icon="book-open" href="/integrations/documentation/intro"> Retrieves client documentation and provides knowledge base integration. </Card> <Card title="RMM" icon="server" href="/integrations/rmm/intro"> Monitors endpoints, executes remote commands, and manages device health. </Card> <Card title="Marketplaces" icon="key" href="/integrations/marketplaces/intro"> Tracks software licenses, manages subscriptions, and automates provisioning. </Card> <Card title="M365 & Azure" icon="microsoft" href="/integrations/m365/intro"> Automates identity management, mailbox operations, and user provisioning. </Card> <Card title="Microsoft Teams" icon="comment" href="/integrations/teams/intro"> Surfaces notifications, approvals, and bot interactions directly in Teams. </Card> <Card title="Slack" icon="slack" href="/integrations/slack/intro"> Posts workflow notifications inside Slack, and puts your branded chat agent in your clients' Slack workspaces. Approval requests go to Microsoft Teams or inline in chat. </Card> <Card title="TimeZest" icon="calendar" href="/integrations/timezest/overview"> Automates appointment scheduling and calendar management for end-user bookings. </Card> <Card title="ScalePad" icon="layer-group" href="/integrations/scalepad/overview"> Reads client and asset data, manages Lifecycle Manager content, ControlMap compliance, Quoter quotes, and Backup Radar backup health. </Card> <Card title="Huntress" icon="shield-halved" href="/integrations/huntress/overview"> Reads Huntress incidents, hosts, and detections, and resolves them with technician sign-off — including host isolation and travel exceptions. </Card> <Card title="ThreatLocker" icon="shield-halved" href="/integrations/threatlocker/overview"> Reads computers, applications, and policies, and resolves pending approval requests with technician sign-off. </Card> <Card title="AutoElevate" icon="user-shield" href="/integrations/autoelevate/overview"> Reads privilege-elevation requests and the file, publisher and user behind each one, and approves or denies with technician sign-off. </Card> <Card title="Proofpoint Essentials" icon="envelope-circle-check" href="/integrations/proofpoint-essentials/overview"> Adds senders to client safe and block lists and manages users and domains. Releasing quarantined email stays in the Proofpoint console. </Card> <Card title="Hornetsecurity 365 Total Protection" icon="envelope-open" href="/integrations/hornetsecurity/overview"> Searches client email, releases, reclassifies and deletes held email, and allows or denies senders. </Card> <Card title="Mimecast" icon="envelope-open-text" href="/integrations/mimecast/overview"> Finds reported and held email, judges whether it is phishing, releases good mail and blocks bad senders. </Card> <Card title="SentinelOne" icon="shield-virus" href="/integrations/sentinelone/overview"> Reads threats, alerts and endpoints, closes threats with the right verdict, and mitigates threats or isolates endpoints. </Card> <Card title="Wizer" icon="graduation-cap" href="/integrations/wizer/overview"> Adds and disables a client's training users, starts courses, and reports who has not finished. </Card> <Card title="Ubiquiti UniFi" icon="wifi" href="/integrations/unifi/overview"> Reads consoles, sites, devices and clients across your UniFi fleet; restarts devices and changes networks or firewall rules with technician sign-off. </Card> <Card title="Domotz" icon="network-wired" href="/integrations/domotz/overview"> Reads collectors, devices, history and alerts at each client site; edits devices and monitoring, power cycles a device through its switch port or PDU, and resolves the alert once it is back. </Card> <Card title="Auvik" icon="network-wired" href="/integrations/auvik/overview"> Network device status, uplinks, alerts and billing usage at each client site; dismiss alerts. </Card> <Card title="Zabbix" icon="chart-line" href="/integrations/zabbix/overview"> Reads hosts, open problems and latest values from your Zabbix server; acknowledges and closes problems, sets maintenance and runs your Zabbix scripts. </Card> <Card title="Cisco Meraki" icon="wifi" href="/integrations/meraki/overview"> Reads device status, uplinks, events, switch ports and Wi-Fi clients across your Meraki organizations, runs live diagnostics, and reboots devices or changes settings with the approvals you choose. </Card> <Card title="WatchGuard" icon="shield-halved" href="/integrations/watchguard/overview"> Checks Fireboxes and access points after an offline alert, manages Firebox exceptions and policies, and reads and acts on endpoint security and ThreatSync, across every WatchGuard Cloud account you manage. </Card> <Card title="Sophos" icon="shield-halved" href="/integrations/sophos/overview"> Checks a device in Sophos when your RMM says it is offline, reads and acts on Sophos alerts, isolates and scans endpoints, and reads firewalls, email quarantine and mobile devices, across every Sophos Central tenant you manage. </Card> <Card title="CentralReach" icon="user-plus" href="/integrations/centralreach/overview"> Creates and deactivates staff accounts in your clients' CentralReach practices, with their labels, custom fields and tasks, as part of onboarding and offboarding. </Card> <Card title="CyberQP" icon="user-shield" href="/integrations/cyberqp/overview"> Verifies end users before a reset, manages just-in-time admin accounts, and reads customers, agent GUIDs and the install token from CyberQP. </Card> <Card title="TP-Link Omada" icon="wifi" href="/integrations/omada/overview"> Reads devices, clients and alerts across your Omada customers and sites, reboots devices, blocks clients, issues vouchers and changes WiFi, network and firewall settings with the approvals you choose. </Card> <Card title="Uniview Backup" icon="hard-drive" href="/integrations/uniview/overview"> Reads backup status, backup jobs and BackupIQ alerts from Unitrends and Kaseya backup, so agents can close backup alerts that have recovered. </Card> <Card title="Datto BCDR" icon="hard-drive" href="/integrations/datto-bcdr/overview"> Connects your Datto Partner Portal API key for SIRIS, ALTO and NAS backup appliances and SaaS Protection. </Card> <Card title="CIPP" icon="cloud" href="/integrations/cipp/overview"> Works Microsoft 365 tickets in your customers' tenants through your CIPP instance: accounts, MFA, mailboxes, quarantine, devices and sign-in alerts. </Card> <Card title="BeyondTrust EPM" icon="user-lock" href="/integrations/beyondtrust-epm/overview"> Looks up JIT application access requests and the computer behind each one, to put elevation tickets on the right client. </Card> <Card title="SaaS Alerts" icon="shield-halved" href="/integrations/saas-alerts/overview"> Connects your SaaS Alerts partner API key for Microsoft 365 and Google Workspace security alerts. </Card> <Card title="ConnectWise CPQ" icon="file-invoice-dollar" href="/integrations/connectwise-cpq/overview"> Connects your ConnectWise CPQ API keys. </Card> <Card title="Kaseya Quote Manager" icon="file-invoice-dollar" href="/integrations/kaseya-quote-manager/overview"> Connects your Kaseya Quote Manager API key. </Card> <Card title="myITprocess" icon="clipboard-check" href="/integrations/myitprocess/overview"> Connects your myITprocess API key, so agents read reviews, roadmaps and QBR meetings. </Card> <Card title="QuoteWerks" icon="file-invoice" href="/integrations/quotewerks/overview"> Connects your QuoteWerks Web API key. </Card> <Card title="Datto EDR" icon="shield-virus" href="/integrations/datto-edr/overview"> Connects your Datto EDR and Datto AV console with an API token. </Card> <Card title="RoboShadow" icon="bug" href="/integrations/roboshadow/overview"> Connects your RoboShadow refresh token, so agents read CVEs, missing patches and endpoint security, and patch through your RMM. </Card> <Card title="Duo" icon="mobile-screen" href="/integrations/duo/overview"> Verifies a caller with a Duo Push, clears MFA lockouts, and enrolls and offboards users, in your own account or a client subaccount. </Card> <Card title="OpenText Secure Cloud" icon="cart-shopping" href="/integrations/opentext/overview"> Sets up and removes users' Microsoft 365 licences in Secure Cloud (formerly AppRiver), reads what each client pays for, and scans or isolates Webroot endpoints. </Card> </CardGroup> Browse the nav for the full list of supported PSAs, RMMs, marketplaces, and documentation systems — each has its own setup guide. <Tip> The tool you need is not listed? [Request an integration](/integrations/request-an-integration). When the vendor has a usable API, Neo builds the integration within 5 working days. </Tip> # IP Whitelisting Source: https://docs.neoagent.io/integrations/ip-whitelisting Configure firewall rules to allow Neo Agent to connect to your systems If your organization uses a firewall to restrict access to your PSA, RMM, documentation system, or other integrated platforms, you need to whitelist Neo Agent's IP address to ensure reliable connectivity. <Info> This applies to any integration where your system is protected by a firewall or IP-based access control. </Info> ## Neo Agent Static IPs Add the following IP addresses to your firewall's allowlist: ``` 74.235.25.90 52.5.41.248 44.196.4.206 ``` <Warning> Add **all** of the addresses above, not just one. Different Neo services handle different work — verifying an integration when you connect it, and running the scheduled syncs afterwards — and they use different outbound IPs. Allowlisting only some of them produces an integration that connects successfully and then fails to sync, or the reverse. </Warning> <Warning> If you don't whitelist these IPs, Neo Agent may be unable to connect to your systems, resulting in failed syncs, API errors, or workflow interruptions. </Warning> ## Is an IP block actually your problem? An IP block and a bad API key produce different errors, and the fixes don't overlap. Neo's error messages name which one you're hitting: | What the error says | Cause | Fix | | - | - | - | | The platform **rejected the API key** | The key is wrong, revoked, or issued for a different region | Re-issue or re-copy the key; check the API URL region. Allowlisting an IP won't help. | | The platform **refused the request before it reached your account** | Neo's IP isn't allowlisted | Add the IPs above. Re-entering the API key won't help. | <Note> Some platforms host the allowlist themselves rather than leaving it to your firewall, so Neo is blocked even though nothing on your own network is. IT Glue is the common one: **Account** → **Settings** → **IP Access Control** restricts both web login *and* API access to the addresses listed there. Lexful has the same kind of control under **Settings** → **Platform** → **IP allowlist** — if you use it, add the addresses above there too. Hudu has two of its own IP controls that can block the REST API, and either can be the cause. The **API key's own IP allow list** (**Admin** → **Account Administration** → **API Keys** → your key → **IP allow list**) applies on cloud and self-hosted instances alike. Separately, account-level **IP Access Control** (**Admin** → **Security** → **IP Access Control**) also applies to REST API requests as of Hudu 2.45 — so if it is on, Neo's addresses have to be listed there too. On a cloud instance (`*.huducloud.com`) you have no firewall of your own in front of Hudu, so these two Hudu controls are the places to check. ThreatLocker can also restrict Portal API access **by geolocation** rather than by address. The refusal reads `Unauthorized - Request was made from a disallowed geolocation`, and no key change fixes it: the restriction has to permit the **United States** — all three addresses above egress from US regions — or be turned off for your API user. </Note> ## Where to Apply You may need to whitelist this IP in several places depending on your setup: <CardGroup> <Card title="PSA Systems" icon="ticket"> Autotask, ConnectWise, HaloPSA, and other PSA platforms that restrict API access by IP. </Card> <Card title="RMM Platforms" icon="server"> Datto RMM, NinjaRMM, ConnectWise Automate, and other RMM tools with IP restrictions. </Card> <Card title="Documentation Systems" icon="book"> IT Glue, Hudu, Lexful, and other documentation platforms with firewall rules or their own IP allowlist. </Card> <Card title="Other Integrations" icon="plug"> Microsoft 365, Teams, Slack, and any other service with IP-based access controls. </Card> </CardGroup> # Connecting Kaseya Quote Manager to Neo Source: https://docs.neoagent.io/integrations/kaseya-quote-manager/connecting-to-neo Create a Kaseya Quote Manager API key and save it in Neo You connect Kaseya Quote Manager once at the MSP level. One API key covers your whole Kaseya Quote Manager account. ## 1. Create the API key <Steps> <Step title="Open the Developer API page"> Sign in to Kaseya Quote Manager, open your account menu in the top right and choose **Developer API**. </Step> <Step title="Copy a key"> Create an API key and copy it. </Step> </Steps> <Warning> Do not delete the key in Kaseya Quote Manager after you connect it. Neo loses access until you save a new key here. </Warning> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the Kaseya Quote Manager card, under Sales & Quoting. </Step> <Step title="Save the key"> Paste the API key and click **Save**. Neo checks it against Kaseya Quote Manager before saving, so a wrong key is rejected straight away. </Step> </Steps> <Note> Kaseya Quote Manager allows 60 API requests a minute and sets a daily limit. </Note> ## 3. Turn Kaseya Quote Manager on per agent Open the agent, go to the Integrations section, and configure the Kaseya Quote Manager block. The **Read Only** profile turns on every area. To leave an area out, set it to Disabled: | Area | Access levels you can pick | Notes | | - | - | - | | **Quotes and Orders** | Disabled, Read Only | Quotes, sales orders, purchase orders and your employees. This is the area an order-status agent needs. Quotes carry your private notes. | | **Customers and Contacts** | Disabled, Read Only | Customers, contacts and addresses: personal data. | | **Catalog and Suppliers** | Disabled, Read Only | Products, prices, supplier stock and cost. Turn it off on an agent that writes to your customers. | See [Kaseya Quote Manager API](/agents/tools/sales/kaseya-quote-manager-api) for what the agent can read. # Overview Source: https://docs.neoagent.io/integrations/kaseya-quote-manager/overview What the Kaseya Quote Manager integration brings to your Neo Agent setup Kaseya Quote Manager (formerly Datto Commerce) holds your quotes, sales orders and purchase orders. Connect your Kaseya Quote Manager API key to Neo once, at the MSP level. The Kaseya Quote Manager API is read-only, so Neo cannot create, send or change a quote, sales order or purchase order in Kaseya Quote Manager. ## What Neo can do with Kaseya Quote Manager * Answer "where is the order for quote QO10001?": the quote's status and expiry, its sales order's status, fulfilment and payments, and each purchase order's supplier, status, items received and serial numbers * Read a quote's lines, and the Autotask opportunity, company and quote it is linked to. Kaseya Quote Manager's published API documents Autotask link fields and no ConnectWise link * Look up a customer and its contacts * Price a product from your catalog and check which supplier has it in stock See [Kaseya Quote Manager API](/agents/tools/sales/kaseya-quote-manager-api) for the permission groups. ## Your customers are mapped to clients Neo matches your Kaseya Quote Manager customers to the companies in your PSA and keeps the mapping on the Kaseya Quote Manager card's **Organization Mapping** tab, refreshed on each PSA metadata sync. On Autotask, matching starts with the Autotask company on the customer's quotes: when every Autotask-linked quote of a customer points to the same company, that company is an exact match. An account with 10,000 quotes or more skips this step. Then comes the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **An Autotask match, a name match, or one you confirm, is handed straight to your agents.** An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Kaseya Quote Manager" icon="plug" href="/integrations/kaseya-quote-manager/connecting-to-neo"> Create an API key in Kaseya Quote Manager and save it in Neo. </Card> # Cloud Source: https://docs.neoagent.io/integrations/m365/cloud Connect Microsoft 365 cloud tenants for automation ## How it works Neo connects to your client Microsoft 365 tenants through the **Neo Automations** app registration. You install this app once per tenant with the necessary permissions, and Neo can then perform automated actions on behalf of your MSP. The integration uses: * **Microsoft Graph API** for user management, licensing, and group operations * **Exchange Online PowerShell** for mailbox and email operations *** <Warning> The steps below must be completed for **every** Microsoft tenant you want to connect to Neo. A customer that owns more than one tenant needs one company per tenant — see [Customers with more than one Microsoft tenant](/integrations/m365/intro#customers-with-more-than-one-microsoft-tenant). </Warning> ## 1. Find the tenant ID Use the tenant ID when authenticating the Neo Automations app. <Frame> <img alt="Find tenant ID in Microsoft Entra ID" /> </Frame> ## 2. Add the company in Neo Dashboard 1. Go to `https://dashboard.neoagent.io/end-companies` and select New Company <Frame> <img alt="Create a new company" /> </Frame> 2. Fill details * Pax8 is optional (only if you manage Microsoft licenses via Pax8) * Custom instructions are optional for onboarding/offboarding policies 3. Click Create <Frame> <img alt="Company details and access buttons" /> </Frame> 4. Click the key icon to get the access link for the company's tenant. * Select **Open here**, or **Copy** the link and open it in a private window, another browser, or send it to the customer's administrator. The link needs no Neo sign-in and works for 2 days. * A **Global Administrator** or **Privileged Role Administrator** of the customer's tenant approves the Microsoft consent screen. The same browser then finishes a Microsoft sign-in, usually without a prompt, so Neo can confirm who approved. A partner account signed in through GDAP cannot approve here; [connect through GDAP](/integrations/m365/gdap) instead. * When the link was opened outside your Neo session, the page says **Access granted** and can be closed. The company shows as connected on the Companies page. * If the page says Microsoft did not confirm the administrator role yet, wait a minute and open the same link again. If Microsoft did not grant access, or the account is not an administrator, open the same link again and approve with a Global Administrator or Privileged Role Administrator account. Only an expired link needs a new one. <Frame> <img alt="Grant application permissions" /> </Frame> <Info> Neo acts in a tenant only after it is connected for your account, through this link or [GDAP](/integrations/m365/gdap). Every company with the same tenant ID shares that connection. If you change a company's tenant ID, connect the new tenant before agents work in it. </Info> <Info> Application access is the only grant Neo needs. It covers everything the automation does in the tenant — creating users, assigning licenses, resetting passwords, and disabling accounts. </Info> <Info> Neo automatically assigns the **Exchange Administrator** role to the Neo Automations app after consent, so mailbox actions (shared mailboxes, forwarding, delegation) work out of the box. No manual role assignment is needed. </Info> ## Re-granting access after permission updates Neo occasionally adds new Microsoft Graph permissions to the Neo Automations app as capabilities expand. A tenant's consent only covers the permissions that existed when access was granted — to pick up additions, re-run the Microsoft consent screen for that company — **... > Reinitialize application access** on a connected company, or **Grant access** on one that is not connected yet. Existing automation keeps working in the meantime; only the newest capabilities stay unavailable until you re-consent. For example, tenants consented before June 2026 are missing `User-PasswordProfile.ReadWrite.All`, which is what lets the agent reset a password and set the *require password change at next sign-in* flag. If Neo reports that a password reset was refused for a company, re-consent it the same way — that picks the permission up. You do not have to guess which permission is short. When Microsoft refuses a call because the consent does not cover it, and the agent cannot finish the job without that permission, it names the permission in its summary — for example `AuditLog.Read.All`, which sign-in and audit log reads need. Re-consent that company and make sure the named permission is selected. A company you connected through [GDAP](/integrations/m365/gdap) has neither consent button: add the permission to your **GDAP permissions** selection, then ask us to re-provision the company. <Check> You've completed permissions. Neo can now perform actions across Microsoft Graph and Exchange Online. </Check> # GDAP Source: https://docs.neoagent.io/integrations/m365/gdap Connect Neo to your customer tenants through your existing GDAP relationships, with no admin action in each tenant This needs CSP enrollment and active GDAP relationships. Once a tenant is connected, Neo works in it through its own app, with app-only access, the same as with [Direct Consent](/integrations/m365/cloud). ## What it takes A few clicks in [**Integrations → GDAP**](https://dashboard.neoagent.io/integrations?open=gdap): sign in, have a Global Administrator approve Neo, and click **Connect all eligible**. The run continues in the background, and you do not need to stay on the page. A company is eligible once it is mapped to a tenant that Neo can reach through CSP, and your account's group has **Privileged Role Administrator** (or an alternative the role table lists) on that relationship. A client you add later gets a **Connect via GDAP** button on its row once it is eligible. Your relationships need a role for each of the two jobs in [Roles your relationships need](#recommended-roles), assigned to the group of the account you sign in with. ## Connecting customer tenants via GDAP The **Integrations → GDAP** page shows these steps as a checklist. <Steps> <Step title="Connect GDAP"> Click **Connect** and sign in with your Secure App Model service account. Check **Consent on behalf of your organization**, which needs a Global Administrator. If the account you use is not one, see [Connect GDAP returns to Neo and nothing changes](#troubleshooting). </Step> <Step title="Grant the Partner Center permission"> Connecting GDAP consents Microsoft Graph only, so a Global Administrator approves one more permission. Use **Copy consent link**, have a Global Administrator approve, then click **I've granted it — recheck**. This lets Neo see which of your clients it can reach through GDAP. If step 1 already used the consent link, this step is done. </Step> <Step title="Check the default permissions"> Neo starts with a default set of [permission categories](/integrations/m365/intro) for each tenant. Change them here if you want, or per company later. </Step> <Step title="Connect your clients"> Click **Find tenants from GDAP**. Neo matches your PSA companies to the customer tenants in your relationships, and you apply the matches. Then click **Connect all eligible**. Progress shows in the provisioning-run panel, and each connected company shows "via GDAP" under **M365 Access**. For a company Neo could not match, click **Map GDAP tenant** on its row on the **Companies** page and pick the tenant. Once the tenant is mapped and Neo can reach the client through CSP, its **Connect via GDAP** button appears. </Step> </Steps> If several PSA companies map to the same Microsoft tenant, connecting one connects them all, because Neo's access belongs to the tenant. A client that owns two Microsoft tenants needs one company per tenant: see [Customers with more than one Microsoft tenant](/integrations/m365/intro#customers-with-more-than-one-microsoft-tenant). *** ## Roles your relationships need Neo acts in each customer tenant through its own app, with the Microsoft Graph permissions in your [M365 permission profile](/integrations/m365/intro). It uses relationship roles only to set that app up. Each relationship needs a role for each of these two jobs: | Job | Role that does it | | - | - | | **Consent the Neo app** | **Application Administrator**. **Cloud Application Administrator** or **Global Administrator** also works. Without one of these, consent fails with a Partner Center `403 Forbidden`. | | **Grant Neo's app the permissions you selected** | **Privileged Role Administrator**. **Global Administrator** or **Partner Tier2 Support** (in Lighthouse default relationships) also works. | Neo assigns **Exchange Administrator** to its own app, because app-only Exchange access needs it, unless you turn off **Auto-assign Exchange Administrator role on consent** for the company. Your account's group does not need that role. Global Administrator covers both jobs, but a relationship with it cannot auto-extend (see the suggested role set below). **The account you sign in with must be in a security group that has a role for both jobs on each relationship.** A role on the relationship is not enough if your group's access assignment does not include it. This is the most common reason a client will not connect. The checklist flags a company whose group lacks **Privileged Role Administrator** (or an alternative) or has no access assignment there. It does not check **Application Administrator** (or an alternative): without one, the client fails only when Neo connects it, with the `403 Forbidden` above. Fix the access assignment in [Microsoft Lighthouse](https://lighthouse.microsoft.com) or [Partner Center](https://partner.microsoft.com/dashboard). For Lighthouse-managed relationships (`LHSetup`, `MLT_`), do not edit them in Entra, because Lighthouse reverts manual changes. <Accordion title="Creating a new relationship? Suggested full role set"> A GDAP relationship cannot be edited after you create it, so include every role you may need. Beyond Application Administrator and Privileged Role Administrator, these cover the work MSPs most often give Neo: | Role | What it covers | | - | - | | **Exchange Administrator** | Mailboxes, forwarding and delegation | | **User Administrator** | Users and groups; password resets for non-admins | | **Privileged Authentication Administrator** | Password, MFA and session resets for **admins** too. Neo gets this role only for a company where you turn on **Auto-assign Privileged Authentication Administrator role** (off by default) | | **Authentication Policy Administrator** | Authentication methods policy and MFA settings | | **Security Administrator** | Security reports, identity protection and threat management | | **Cloud App Security Administrator** | Defender for Cloud Apps | | **Cloud Device Administrator** | Entra devices and BitLocker keys | | **Intune Administrator** | Intune policies and devices | | **SharePoint Administrator** | SharePoint Online and Microsoft 365 groups | | **Teams Administrator** | Microsoft Teams | Leave **Global Administrator** out. A relationship with it cannot auto-extend, so it expires and takes your access with it. Extra roles do not widen Neo's access by themselves: Neo's app can do only what your permission profile grants. </Accordion> *** ## Moving a direct-consent company to GDAP A company connected by [direct consent](/integrations/m365/cloud) can move to GDAP at any time. Neo keeps its access throughout, and no client admin consents again. On the **Companies** page, open **⋯ → Move to GDAP** on the company's row, or use **Move to GDAP (N)** in the banner to move all eligible companies. Progress shows in the provisioning-run panel, and **M365 Access** then shows "via GDAP". After the move, the company's permissions come from your **GDAP permissions** selection. <Warning> Do not remove Neo's app in the customer tenant first. That revokes Neo's access and changes nothing in the Dashboard. </Warning> *** ## Disconnecting a company On [**End Companies**](https://dashboard.neoagent.io/end-companies), select the company and click **Disconnect**. Neo removes the **Neo Azure Automations** app from the customer tenant. Every other company on the same tenant loses access too. Disconnecting needs an active GDAP relationship. If it has lapsed, reconnect GDAP first, or have an admin remove the **Neo Azure Automations** app in the tenant. ## Disconnecting GDAP entirely In **Integrations → GDAP**, click **Disconnect GDAP**. Neo stops using your relationships, for example before you switch the connected account. <Warning> This does not remove Neo from tenants you already connected. To do that, [disconnect each company](#disconnecting-a-company) **before** you disconnect GDAP. If you already disconnected GDAP, reconnect it and then disconnect each company, or have an admin remove the **Neo Azure Automations** app in each tenant. </Warning> *** ## When a GDAP relationship lapses A relationship lasts at most 730 days. When it lapses, connected tenants keep working, but you cannot connect new clients or add permissions. Create a new relationship in Partner Center with the same roles, then reconnect GDAP in the Neo Dashboard. To remove Neo from a tenant, [disconnect the company](#disconnecting-a-company) while a relationship is still active. *** ## GDAP vs Direct Consent | | GDAP | [Direct Consent](/integrations/m365/cloud) | | - | - | - | | **Who consents** | You, through GDAP. No client involvement | A tenant admin in each customer tenant | | **CSP enrollment required** | Yes | No | | **Adding permissions later** | Automatic | Client admin must re-approve | | **Best for** | MSPs with many tenants | Single tenants, or non-CSP partners | The choice is not permanent: see [Moving a direct-consent company to GDAP](#moving-a-direct-consent-company-to-gdap). *** ## Troubleshooting <AccordionGroup> <Accordion title="Connect GDAP returns to Neo and nothing changes"> Microsoft returns you to Neo with no consent screen, and the checklist shows **A Global Administrator must approve Neo**. No Global Administrator has approved Neo yet, or a recent approval has not taken effect. Signing in again gives the same result. 1. In the checklist, click **Copy consent link**. 2. Send it to a Global Administrator of your partner tenant. They open it and approve. 3. Click **I've granted it — recheck**. If they just approved, wait a minute first. 4. When the checklist shows **Reconnect to finish**, click **Reconnect GDAP**. A Global Administrator can also approve in the Microsoft Entra admin center: **Enterprise applications** → **Neo Agent - GDAP** → **Permissions** → **Grant admin consent**. </Accordion> <Accordion title="Consent fails for a customer tenant"> * Check that the relationship is **Active** in Partner Center. * A Partner Center `403 Forbidden` usually means no consent role: check for **Application Administrator**, **Cloud Application Administrator** or **Global Administrator**. Privileged Role Administrator alone cannot consent. * Check that the relationship also has **Privileged Role Administrator**, **Global Administrator** or **Partner Tier2 Support**. * Check that your connected account's group is **assigned** those roles. See [Roles your relationships need](#recommended-roles). * `Unable to initialize the authorization context` can mean the relationship expired with no active replacement, or that your connected account's group has no access assignment on it. Check both. </Accordion> <Accordion title="Neo can't perform actions after GDAP consent"> * Check that Neo's app holds the directory role the action needs in the tenant, for example Exchange Administrator for mailbox work. See [Roles your relationships need](#recommended-roles). * Check the company's permissions in the Neo Dashboard. Missing permissions show as unavailable operations. </Accordion> <Accordion title="Tenant matches won't load"> * **"Microsoft is rate-limiting Neo's requests"**: Microsoft throttles reads of your partner relationships when you have many customer tenants. Your connection is fine and no mapping is lost. Wait a few seconds and read the list again. * **"Temporarily unavailable"**: a temporary failure. No mapping is lost. Wait a moment and read the list again. * To read the list again, click **Try again** in the **Find tenants from GDAP** window. The per-company **Map a GDAP tenant** dialog has no such button: close it and open it again. * **"Couldn't load tenant matches"**: reconnect GDAP, then reopen the window. </Accordion> </AccordionGroup> # Microsoft 365 Source: https://docs.neoagent.io/integrations/m365/intro Connect Microsoft 365 for user management and automation Neo integrates with Microsoft 365, Active Directory, and Exchange to automate the full spectrum of identity, mailbox, and security operations — across cloud, on-prem, and hybrid environments. Connect once, and your AI agents can handle everything from password resets to full user onboarding and offboarding. ## What Neo Can Do <AccordionGroup> <Accordion title="User Lifecycle" icon="user-plus"> Create, update, disable, enable, and delete users in Entra ID or on-prem Active Directory. Assign managers, update job titles and departments, and manage user properties — all from a single agent. </Accordion> <Accordion title="Passwords & Security" icon="lock"> Reset passwords (including *require password change at next sign-in* — see [re-granting access](/integrations/m365/cloud#re-granting-access-after-permission-updates) for tenants connected before June 2026), unlock accounts, revoke sign-in sessions, reset MFA, and manage authentication methods. Block and unblock user sign-in. In hybrid environments, Neo makes changes on-prem and triggers Azure AD Connect sync automatically — or, for hybrid tenants without AD Connect sync, applies the same change to both directories directly. </Accordion> <Accordion title="Licensing" icon="id-card"> Assign and remove Microsoft 365 licenses. Look up friendly license names from SKU IDs. Works with direct Microsoft licensing, Pax8, and Partner Center. </Accordion> <Accordion title="Groups" icon="users"> Add and remove users from security groups, Microsoft 365 groups, distribution lists, and mail-enabled security groups. Search and list groups across Entra ID and on-prem AD. In hybrid environments, Neo automatically routes group operations to the correct directory. </Accordion> <Accordion title="Directory Roles" icon="shield-halved"> Assign and remove Entra ID directory roles (Global Admin, Exchange Admin, User Admin, etc.). View a user's current role assignments. </Accordion> <Accordion title="Mailboxes" icon="envelope"> Convert mailboxes to shared, create new shared mailboxes, and delete shared mailboxes. Set up and remove email forwarding. Configure mailbox delegation (full access, send-as, send-on-behalf). Works with Exchange Online and on-prem Exchange Server. </Accordion> <Accordion title="Mailbox Permissions" icon="key"> Grant and revoke full access, send-as, and send-on-behalf permissions. Add and remove recipient permissions. View current mailbox permission assignments. </Accordion> <Accordion title="Conditional Access" icon="filter"> List, view, create, update, and delete Conditional Access policies. Destructive operations always require technician approval regardless of workflow settings. </Accordion> <Accordion title="Devices" icon="mobile"> View user devices in Intune. Remote wipe and retire mobile devices. Device deletion is always blocked for safety. </Accordion> <Accordion title="On-Prem Active Directory" icon="server"> Full AD management via RMM: user and computer management, organizational units, group operations, infrastructure queries, and Entra Connect sync triggers. </Accordion> <Accordion title="Exchange Server (On-Prem)" icon="server"> All Exchange operations work on-prem too: mailbox management, permissions, recipients and contacts, distribution groups, mail flow and transport rules, address lists and policies, compliance and auditing. </Accordion> </AccordionGroup> <Tip> Need an operation that's not listed? Let us know — we add new capabilities regularly. </Tip> *** ## Granular Permission Controls Every agent workflow has its own permission configuration. You control exactly what the agent can and cannot do — per integration, per operation category. <CardGroup> <Card title="Microsoft Graph" icon="cloud"> 14 permission groups covering users, groups, licensing, security, roles, devices, conditional access, domains, mail, audit logs, security operations, SharePoint & OneDrive, Teams & chats, and app registrations </Card> <Card title="Active Directory" icon="server"> 6 permission groups covering users, groups, computers, OUs, infrastructure, and Entra Connect sync </Card> <Card title="Exchange" icon="envelope"> 7 permission groups covering mailboxes, permissions, recipients, distribution groups, mail flow, address lists, and compliance </Card> </CardGroup> Each permission group has three access levels: | Level | What the agent can do | | - | - | | **Disabled** | No access to this category | | **Read Only** | Query and list operations only | | **Read / Write** | Full access including create, update, and delete | You can also require **technician approval** for any permission group — the agent will pause and wait for a technician to approve before executing write operations. <Info> **Built-in safety guardrails:** Some destructive operations (like deleting a user or wiping a device) always require technician approval, even if the permission group doesn't have it enabled. Every write in the **Applications** group (app registrations, client secrets, consent grants) requires approval the same way. Other operations (like deleting a domain) are blocked entirely. </Info> **Quick-start profiles** let you configure all permission groups at once: | Profile | Best for | | - | - | | **Read Only** | Monitoring and reporting agents | | **Helpdesk** | Tier 1 agents — password resets, group changes, basic user updates | | **IT Admin** | Tier 2/3 agents — user lifecycle, licensing, mailbox management | | **Full Automation** | Fully autonomous agents — all operations, no approval required | ### Service Health **Service Health** is read only, and it is the one permission group with no Write level: Microsoft exposes no write for service health. Turning it on lets an agent read Microsoft 365 service health, open incidents, and Message Center announcements for that client company — so it can tell a user "Microsoft has an open incident affecting Exchange" instead of troubleshooting a fault that is not yours. **A client company that connected to Neo before 3 September 2026 needs one extra step.** Service Health needs two Microsoft permissions that Neo did not ask for until then, and adding a permission to our app never grants it to a tenant retroactively. So the first Service Health call for an older company fails, and the agent tells you why. What fixes it depends on how that company was connected: * **Direct admin consent** — open **Companies** and use the ⋯ actions menu → **Reinitialize application access** on that company. It re-runs the same Microsoft consent screen, which now asks for both permissions. A company that is not connected yet shows **Grant access** instead, and that covers it the same way. * **GDAP** — a GDAP company's permissions come from your **GDAP permissions** selection rather than a consent screen, so there is no per-company button for it. Check that selection includes both permissions (the default set does), then ask us to re-provision the company. Companies you connect from now on include both permissions. So do companies Neo provisions through your GDAP relationship — unless you have saved a narrowed **GDAP permissions** selection, in which case add them there first. ### "Coming Soon" permission groups A permission group badged **Coming Soon** and greyed out is one we have built the controls for but have not released. The Microsoft access behind it has not been granted to Neo, so every call it would cover fails — for every customer, in every tenant. No group is in this state today; Service Health was the last one, released on 3 September 2026. If you meet one in a future release, you cannot switch it on, and working around it does not help: * The quick-start profiles leave it **Disabled**, and both the dashboard and the API refuse to set it any higher. * **Re-consenting or re-authorizing your Microsoft 365 connection does not help.** A tenant admin can only consent to the permissions Neo's app asks for, and an unreleased group is one we do not ask for yet. * If an agent of yours has one enabled from an older configuration, its calls have been failing. Set the group back to **Disabled** on that row. Neo also refuses those calls and tells the agent why, so it stops spending its run on them. Ask us if you want a Coming Soon group prioritized. We will tell you where it stands rather than give you a date we cannot keep. *** ## Works Everywhere Neo supports cloud, on-prem, and hybrid Microsoft environments — configured independently per client company. | Environment | Identity | Mailbox | | - | - | - | | **Cloud** | Entra ID via Microsoft Graph API | Exchange Online via Graph + PowerShell | | **On-prem** | Active Directory via RMM + PowerShell | Exchange Server via RMM + PowerShell | | **Hybrid** | On-prem AD with Azure AD Connect sync | Exchange Hybrid (on-prem cmdlets + cloud routing) | | **Hybrid (no AD Connect sync)** | On-prem AD + Entra ID — Neo applies every identity change to both directories directly | Exchange Online or Exchange Server (configured separately) | Identity provider and mailbox provider are configured separately — you can mix and match. For example, on-prem AD with Exchange Online, or Entra ID with on-prem Exchange Server. *** ## Connect Cloud Tenants Two ways to connect Neo to customer Microsoft 365 tenants: | | [GDAP](/integrations/m365/gdap) | [Direct Consent](/integrations/m365/cloud) | | - | - | - | | **Who consents** | MSP admin, using GDAP access — no customer involvement | A tenant admin in each customer tenant | | **How Neo authenticates** | Standard client\_credentials (same for both) | Standard client\_credentials | | **CSP enrollment required** | Yes | No | | **Best for** | MSPs managing many tenants — onboard without waiting for each customer's admin | Individual tenants, or non-CSP scenarios | A company connected by direct consent can [move to GDAP](/integrations/m365/gdap#moving-a-direct-consent-company-to-gdap) later, without losing access. <CardGroup> <Card title="GDAP" icon="shield-halved" href="/integrations/m365/gdap"> CSP partners can consent to Neo on behalf of customers using existing GDAP access. </Card> <Card title="Direct Consent" icon="cloud" href="/integrations/m365/cloud"> A tenant admin in each customer tenant consents to the Neo app directly. </Card> </CardGroup> *** ## Customers With More Than One Microsoft Tenant A company record holds **one** Microsoft tenant ID, and Neo works in the tenant set on the company attached to the ticket. A customer that runs two tenants — after an acquisition, or a group that never merged its directories — needs **one company per tenant**. <Steps> <Step title="Give each tenant its own company in your PSA"> Neo's companies map one-to-one onto PSA companies, so the second tenant needs a company of its own in your PSA — a child company or a site works. </Step> <Step title="Set the tenant ID on each company"> On [**Companies**](https://dashboard.neoagent.io/end-companies), open each one and set **Microsoft Tenant ID of the company** to that tenant's GUID. </Step> <Step title="Connect each company"> Grant access per company, with [GDAP](/integrations/m365/gdap) or [Direct Consent](/integrations/m365/cloud). Connecting one of them does not reach the other tenant. </Step> </Steps> The ticket decides which tenant Neo acts in. If tickets for both tenants land on a single company, Neo only ever acts in the tenant set on that company — so split the tickets the way you split the companies. <Note> The reverse needs no extra setup: several companies may share one tenant ID, which is the normal shape for a group with one PSA company per site. Connect any one of them and they all show connected, because the access belongs to the tenant. </Note> *** ## Connect On-Prem Environments <Card title="On-prem" icon="server" href="/integrations/m365/on-prem"> Connect on-premises Active Directory and Exchange environments via RMM. </Card> <Note> **Hybrid environments:** Configure as on-prem — Neo executes operations on your domain controller and Azure AD Connect syncs changes to the cloud. If both directories exist but nothing syncs between them, set the company's identity provider to **"Hybrid (no AD Connect sync)"** instead — Neo then applies each identity change to both on-prem AD and Entra ID directly. See [which hybrid type to pick](/integrations/m365/on-prem#1-configure-company-settings). </Note> # On-prem Active Directory & Exchange Source: https://docs.neoagent.io/integrations/m365/on-prem Enable Neo to manage on-premises Active Directory and Exchange Server via RMM ## How it works Neo manages on-premises Active Directory and Exchange Server by executing PowerShell scripts through your RMM platform. This enables the same operations available in cloud environments — password resets, user provisioning, group management, mailbox delegation, and more. Neo uses two execution patterns depending on your environment: * **Direct execution** — The RMM agent is installed on the target server (e.g., the Domain Controller or Exchange server). Neo runs scripts directly on it. * **Remote execution** — The target server doesn't have an RMM agent. Neo runs scripts on a "runner" VM that *does* have RMM, and uses PowerShell Remoting to reach the target server. Identity Provider (AD) and Mailbox Provider (Exchange) are configured independently per company — you can mix and match. For example, on-prem AD with Exchange Online, or Entra ID with on-prem Exchange Server. <Tip> Setting up a user onboarding agent for on-prem AD with Azure AD Connect? Use the [Hybrid AD User Onboarding recipe](/recipes/hybrid-ad-user-onboarding). </Tip> **What routes where:** | Operation | Where it runs | | - | - | | AD changes (create user, reset password, groups, etc.) | On the AD Runner via RSAT — either the DC or a runner VM | | AD Connect sync | On the AD Connect server (remotely from the runner if the AD Connect server isn't in RMM) | | Exchange Online / Exchange Hybrid standard ops (forwarding, delegation, shared mailbox, etc.) | Cloud — via Microsoft Graph | | Exchange on-prem cmdlets (e.g., `Enable-RemoteMailbox`) | On the Exchange server (remotely from the runner if the Exchange server isn't in RMM) | *** ## Setup ### 1. Configure Company Settings For each client with on-prem infrastructure, configure their identity provider and mailbox provider settings in the [**Companies** tab](https://dashboard.neoagent.io/end-companies). #### Identity Provider Settings | Field | Description | | - | - | | **Identity Provider Type** | Select "On-prem AD", "Hybrid", "Hybrid (no AD Connect sync)", or "Entra ID (Cloud)" | | **AD Runner Hostname** | *(On-prem AD and both Hybrid types)* Hostname of the machine where AD scripts run — either the DC itself or a [runner VM](#3-set-up-a-runner-machine) with RSAT AD tools. Must identify a device in RMM — see [how Neo matches a runner hostname](#how-neo-matches-a-runner-hostname). | | **AD Service Account Username** | *(On-prem AD and both Hybrid types, optional)* `DOMAIN\username` of the service account used for AD operations. | | **AD Connect Server Hostname** | *(Hybrid only)* Hostname of the server running Azure AD Connect. Neo triggers a directory sync on this server after making AD changes, so updates propagate to Entra ID. If this server differs from the AD Runner, Neo uses [remote execution](#4-enable-remote-execution) to reach it. | <Note> **Which hybrid type?** Choose **"Hybrid"** when Azure AD Connect syncs your on-prem AD to Entra ID — Neo makes identity changes in AD and triggers a sync so they propagate to the cloud. Choose **"Hybrid (no AD Connect sync)"** when both directories exist but nothing syncs between them (e.g., AD Connect was decommissioned) — Neo then performs every identity operation in **both** on-prem AD and Entra ID directly: user creation, password resets, sign-in blocking, deletion, and profile updates are applied to each side with the same values. Picking "Hybrid" without a working AD Connect leaves new users stranded in AD, never reaching the cloud. </Note> #### Mailbox Provider Settings | Field | Description | | - | - | | **Mailbox Provider Type** | Select "Exchange Server" (on-prem), "[Exchange Hybrid](#exchange-hybrid)", or "Exchange Online" (cloud) | | **Exchange Server Hostname** | *(Exchange Server and Exchange Hybrid only)* Hostname of the Exchange server. When no Exchange Runner is set, Neo runs scripts here — see [how Neo matches a runner hostname](#how-neo-matches-a-runner-hostname). | | **Exchange Runner Hostname** | *(Exchange Server and Exchange Hybrid, optional)* Set this if the Exchange server doesn't have an RMM agent. Neo runs scripts on this [runner VM](#3-set-up-a-runner-machine) and uses [remote execution](#4-enable-remote-execution) to reach the Exchange server. Must identify a device in RMM — see [how Neo matches a runner hostname](#how-neo-matches-a-runner-hostname). | | **Exchange Service Account Username** | *(Exchange Server and Exchange Hybrid, optional)* `DOMAIN\username` of the service account. Required when using an Exchange Runner — enables CredSSP authentication to solve the [Kerberos double-hop problem](#5-configure-credssp-for-exchange-runners). | #### Service Account Password | Field | Description | | - | - | | **Service Account Password** | Password for the on-prem service account. Stored securely in Azure Key Vault — never stored in the database. Required when a service account username is configured. Leave blank when editing to keep the existing password unchanged. | #### How Neo matches a runner hostname Enter the runner as your RMM displays it, or as the machine's fully-qualified domain name. This applies to every hostname Neo runs scripts on — the **AD Runner**, the **Exchange Runner**, and the **Exchange Server** when no Exchange Runner is set. Neo matches the name against all of the following: * **The device name shown in your RMM.** This always works. * **The machine's real host name**, when your RMM displays an editable label instead. ConnectWise ASIO, for example, shows the friendly name a technician typed — `DC - Head Office - ADSync` — while the machine itself is named `HO-DC01`. Either one resolves. * **The machine's fully-qualified domain name**, for RMM platforms that report one. NinjaOne reports both `HO-DC01` and `HO-DC01.contoso.local`. A fully-qualified name also finds a device that your RMM lists under the short name alone, so `DC01.contoso.local` resolves a device named `DC01`. <Note> Neo learns a device's real host name and its full FQDN during the RMM device sync. If you enter one of these and your RMM does not already display it, allow one device sync to finish before the runner resolves. An FQDN whose short name your RMM already shows is the exception — `DC01.contoso.local` resolves a device displayed as `DC01` right away, with no sync. </Note> <Note> **Sharing one runner across companies.** When several companies share a single domain controller or runner (e.g. a multi-academy trust or a healthcare group), set that same hostname as each company's AD/Exchange Runner Hostname. The device only needs to exist in RMM under **one** of those companies — Neo will use it for the others too. Neo resolves the shared runner in this order: 1. A device with that hostname mapped to the company on the ticket. 2. A device with that hostname owned by a company in the same **PSA parent group** — the shared company's parent, plus every company under that parent. This lets a generic hostname such as `dc2` be reused across a group even when the same name also exists at unrelated customers, as long as only one machine of that name sits inside the group. 3. A device with that hostname anywhere in your RMM, if it resolves to a single company. Neo refuses only when the name still points at more than one machine after those steps — for example two different servers both named `dc2` inside the same parent group, or the same name at unrelated companies with no parent link. Then it asks you to give one of them a unique hostname (or, for unrelated companies, to assign the correct device under **Integrations → RMM → Device Mapping**). You do **not** need to reassign a device that is shared by design across a parent group. </Note> ### 2. Upload the Neo Script to Your RMM Neo needs a wrapper script installed in your RMM to execute PowerShell commands. <Tabs> <Tab title="ConnectWise Asio"> **No upload required.** ConnectWise Asio ships a built-in `PowerShell script` automation template that Neo uses to execute PowerShell on managed endpoints. Neo dispatches the wrapper code inline as the `body` parameter of that template on every run, so you don't need to create or maintain any Neo-specific script in your Asio library. <Note> Asio's user-created PowerShell scripts (Add → PowerShell script in the Tasks page) don't expose a "Parameters" tab, so Neo can't use one as the wrapper. Don't create a `[Neo Script] Run Powershell` task in Asio — it won't be used. </Note> 1. Confirm an Asio agent is installed on the target server (DC, Exchange server, runner VM, etc.) and reporting `osType=windows`. 2. Trigger an RMM sync in Neo at [Integrations → RMM](https://dashboard.neoagent.io/integrations) so Neo discovers the endpoint and the built-in `PowerShell script` template. </Tab> <Tab title="Datto RMM"> 1. Download the Neo PowerShell component: <Card title="Neo Script Run Powershell.cpt" icon="download" href="https://stneoagentpublic.blob.core.windows.net/docs-assets/neo-script-run-powershell.cpt"> Datto RMM component for executing Neo PowerShell scripts </Card> 2. Import the component into Datto RMM by following [Datto's import instructions](https://rmm.datto.com/help/en/Content/3NEWUI/Automation/Components/COMPONENTLIBRARY.htm#Importing_a_component). 3. Trigger an RMM sync in Neo by going to [Integrations → RMM](https://dashboard.neoagent.io/integrations) and clicking the sync button. This allows Neo to discover the newly imported script. #### Re-importing an updated component Importing a newer version does **not** update the existing component — Datto creates a *second* one and appends a number to its name (`[Neo Script] Run Powershell [615296]`). Neo finds the wrapper by **exact name**, so the copy with the suffix is never used. 1. **Delete the old component first, then import** — so the new one keeps the exact name. (If you already imported, delete the old one and rename the new one back to `[Neo Script] Run Powershell`.) 2. **Re-enable Requires Component Credentials and save** — the `.cpt` doesn't carry it, so every import arrives with it **OFF**. See [Configure RMM Component Credentials](#3c-configure-rmm-component-credentials). 3. **Trigger an RMM sync** in Neo so it picks up the new component. <Warning> Skipping step 2 is silent: Datto falls back to **LocalSystem**, whose network identity is the runner's machine account. AD/Exchange **reads keep working while every write fails** with `Insufficient access rights to perform the operation`, which reads as a directory permissions problem rather than a Datto one. </Warning> </Tab> <Tab title="ConnectWise Automate"> Build the wrapper in the Automate web **Script Editor** (Automation → Scripts). 1. Open **Scripts → All Scripts** and click **+ Add**. <Frame> <img alt="All Scripts view with the Add button in ConnectWise Automate" /> </Frame> 2. On the **Summary** tab, set **Name** to `[Neo Script] Run Powershell`, **Target** to `Computer`, and leave **Function Script** toggled **off**. <Warning> The name must match exactly, including the square brackets. Neo finds the wrapper by this name. Leave **Function Script** off, or the script can't run against a computer. </Warning> <Frame> <img alt="Summary tab with the name, Computer target, and Function Script off" /> </Frame> 3. On the **Editor** tab, click **Parameters → Add** and add a parameter named `script_content_path`. <Frame> <img alt="Adding the script_content_path parameter" /> </Frame> 4. Add an **Execute Script** step. Set **Script Type** to `PowerShell`, **Script Credentials** to `Local Agent`, **Variable** to `@psoutput@`, and paste this into the **Script Editor**: ```powershell theme={null} $env:script_content_path = "@script_content_path@" $neo_base_url = "https://engine.neoagent.io" $script_content_path = $env:script_content_path $script_content_url = "$neo_base_url/$script_content_path" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Retried so a single transient network/TLS blip doesn't fail the whole job. $commands = $null $neo_download_error = "" for ($neo_attempt = 1; $neo_attempt -le 3; $neo_attempt++) { try { $wc = New-Object System.Net.WebClient $wc.Encoding = [System.Text.Encoding]::UTF8 $commands = $wc.DownloadString($script_content_url) break } catch { $neo_download_error = $_.Exception.Message if ($neo_attempt -lt 3) { Start-Sleep -Seconds (5 * $neo_attempt) } } } # If the download never succeeded, fold the failure into the same $neo_output / # $neo_failed path as an inner-script error so the clear NEO_SCRIPT_DOWNLOAD_FAILED # cause reaches Neo via the SAME retried result-POST below, rather than a one-shot # POST that a lingering blip could also drop. $neo_output = "" $neo_failed = $false if ($null -eq $commands) { $neo_output = "NEO_SCRIPT_DOWNLOAD_FAILED after 3 attempts: $neo_download_error" $neo_failed = $true } else { try { $neo_output = (iex $commands *>&1 | Out-String) } catch { $neo_output = "ERROR: $($_.Exception.Message)" $neo_failed = $true } } Write-Output $neo_output # Retried: the work is already done at this point, and losing the result to one # blip leaves Neo waiting out its full deadline on a run that actually succeeded. $result_path = $script_content_path -replace '\?', '/result?' $result_url = "$neo_base_url/$result_path" for ($neo_post = 1; $neo_post -le 3; $neo_post++) { try { $rc = New-Object System.Net.WebClient $rc.Encoding = [System.Text.Encoding]::UTF8 $rc.Headers.Add("Content-Type", "text/plain; charset=utf-8") $null = $rc.UploadString($result_url, "POST", $neo_output) break } catch { if ($neo_post -eq 3) { Write-Output "NEO_RESULT_CALLBACK_FAILED: $($_.Exception.Message)" } else { Start-Sleep -Seconds (5 * $neo_post) } } } if ($neo_failed) { exit 1 } ``` <Frame> <img alt="Execute Script step set to PowerShell, Local Agent, output variable psoutput" /> </Frame> 5. Add a **Script Log Message** step after it, with **Message** set to `@psoutput@`. This records the script's output to the run history. <Frame> <img alt="Script Log Message step set to psoutput" /> </Frame> 6. On the **Settings** tab, turn **Enable Enhanced Script Logging** on (required for the Log Message step to record output). 7. Save. The Editor should now show two steps — Execute Script, then Log Message: <Frame> <img alt="Editor showing the Execute Script and Log Message steps" /> </Frame> 8. Trigger an RMM sync in Neo at [Integrations → RMM](https://dashboard.neoagent.io/integrations) so Neo discovers the new script. </Tab> <Tab title="NinjaOne"> <Note> NinjaOne passes script parameters to the script as a single raw string instead of binding them to named variables (the way Datto and ConnectWise Automate do). The wrapper below reads the path Neo sends and runs it, so you do not need to configure any **Script Variables** or **Parameters** in NinjaOne. Neo supplies everything at runtime. </Note> 1. In NinjaOne, open the **Automation Library** and create a new script. 2. Name it exactly **`[Neo Script] Run Powershell`**. <Warning> The name must match exactly, including the square brackets. Neo finds the wrapper by this name. </Warning> 3. Set **Language** to **PowerShell**, **Operating System** to **Windows**, and leave **Run as** set to **System**. Leave **Script Variables** and **Parameters** empty. 4. Paste this into the script body: ```powershell theme={null} $ErrorActionPreference = "Stop" $neo_base_url = "https://engine.neoagent.io" # NinjaOne passes the script path to this wrapper as a raw "name=value" string, # not bound to a named variable the way Datto and ConnectWise do. Pull the # rmm/script path (with its ?code= token) out of whichever source carries it. $path = $null foreach ($candidate in @($env:script_content_path, ($args -join ' '))) { if ($candidate -and ($candidate -match '(rmm/script/\S+)')) { $path = $Matches[1]; break } } if (-not $path) { throw "Neo wrapper: no rmm/script path found. env='$($env:script_content_path)' args='$($args -join ' ')'" } # Retried so a single transient network/TLS blip doesn't fail the whole job. [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $commands = $null $neo_download_error = "" for ($neo_attempt = 1; $neo_attempt -le 3; $neo_attempt++) { try { $wc = New-Object System.Net.WebClient $wc.Encoding = [System.Text.Encoding]::UTF8 $commands = $wc.DownloadString("$neo_base_url/$path") break } catch { $neo_download_error = $_.Exception.Message if ($neo_attempt -lt 3) { Start-Sleep -Seconds (5 * $neo_attempt) } } } # Capture the output and report it back to Neo, so a result reaches Neo even when # the RMM only surfaces a truncated wrapper log. Best-effort and retried: the work # is already done, and losing the result to one blip leaves Neo waiting out its # full deadline on a run that actually succeeded. A failed download reports the # clear NEO_SCRIPT_DOWNLOAD_FAILED cause the same way, instead of throwing silently. $neo_output = "" $neo_failed = $false if ($null -eq $commands) { $neo_output = "NEO_SCRIPT_DOWNLOAD_FAILED after 3 attempts: $neo_download_error" $neo_failed = $true } else { try { $neo_output = (iex $commands *>&1 | Out-String) } catch { $neo_output = "ERROR: $($_.Exception.Message)" $neo_failed = $true } } Write-Output $neo_output $result_path = $path -replace '\?', '/result?' for ($neo_post = 1; $neo_post -le 3; $neo_post++) { try { $rc = New-Object System.Net.WebClient $rc.Encoding = [System.Text.Encoding]::UTF8 $rc.Headers.Add("Content-Type", "text/plain; charset=utf-8") $null = $rc.UploadString("$neo_base_url/$result_path", "POST", $neo_output) break } catch { if ($neo_post -lt 3) { Start-Sleep -Seconds (5 * $neo_post) } } } if ($neo_failed) { exit 1 } ``` 5. Click **Save**. 6. In Neo, go to [Integrations → RMM](https://dashboard.neoagent.io/integrations) and click the sync button so Neo can discover the new script. When an agent runs an on-prem AD or Exchange action, Neo calls this wrapper, which downloads the generated PowerShell from Neo and runs it on the target machine. </Tab> <Tab title="Kaseya VSA X"> 1. In your VSA X portal, go to **Automation → Scripts** and create a new script. 2. Name it exactly **`[Neo Script] Run Powershell`**. <Warning> The name must match exactly, including the square brackets. Neo finds the wrapper by this name when it syncs your script catalog. </Warning> 3. Set the script **Type/Platform** to **PowerShell** / **Windows**. 4. Add a single **input variable** named exactly `script_content_path` (type: text/string). Neo passes the script path into this variable at runtime. <Note> VSA X keys script variables by an internal Id, but Neo resolves your `script_content_path` variable to its Id automatically at execution time — you only need to create the input variable with that name. (If the script defines exactly one input variable, Neo binds to it even if you named it differently, but matching `script_content_path` is the reliable choice.) </Note> 5. Paste this into the script body: ```powershell theme={null} $ErrorActionPreference = "Stop" $neo_base_url = "https://engine.neoagent.io" # VSA X surfaces the script's input variable to PowerShell; the exact binding can # vary by agent/runtime, so pull the rmm/script path (with its ?code= token) out of # whichever source carries it — the bound variable, an environment variable, or args. $path = $null foreach ($candidate in @($script_content_path, $env:script_content_path, ($args -join ' '))) { if ($candidate -and ($candidate -match '(rmm/script/\S+)')) { $path = $Matches[1]; break } } if (-not $path) { throw "Neo wrapper: no rmm/script path found in the script_content_path variable." } # Download the generated script from Neo, retrying so a single transient # network/TLS blip doesn't fail the whole job. [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $commands = $null $neo_download_error = "" for ($neo_attempt = 1; $neo_attempt -le 3; $neo_attempt++) { try { $wc = New-Object System.Net.WebClient $wc.Encoding = [System.Text.Encoding]::UTF8 $commands = $wc.DownloadString("$neo_base_url/$path") break } catch { $neo_download_error = $_.Exception.Message if ($neo_attempt -lt 3) { Start-Sleep -Seconds (5 * $neo_attempt) } } } # Execute it # Capture the output and report it back to Neo, so a result reaches Neo even when # the RMM only surfaces a truncated wrapper log. Best-effort and retried: the work # is already done, and losing the result to one blip leaves Neo waiting out its # full deadline on a run that actually succeeded. A failed download reports the # clear NEO_SCRIPT_DOWNLOAD_FAILED cause the same way, instead of throwing silently. $neo_output = "" $neo_failed = $false if ($null -eq $commands) { $neo_output = "NEO_SCRIPT_DOWNLOAD_FAILED after 3 attempts: $neo_download_error" $neo_failed = $true } else { try { $neo_output = (iex $commands *>&1 | Out-String) } catch { $neo_output = "ERROR: $($_.Exception.Message)" $neo_failed = $true } } Write-Output $neo_output $result_path = $path -replace '\?', '/result?' for ($neo_post = 1; $neo_post -le 3; $neo_post++) { try { $rc = New-Object System.Net.WebClient $rc.Encoding = [System.Text.Encoding]::UTF8 $rc.Headers.Add("Content-Type", "text/plain; charset=utf-8") $null = $rc.UploadString("$neo_base_url/$result_path", "POST", $neo_output) break } catch { if ($neo_post -lt 3) { Start-Sleep -Seconds (5 * $neo_post) } } } if ($neo_failed) { exit 1 } ``` 6. Save the script. 7. Trigger an RMM sync in Neo at [Integrations → RMM](https://dashboard.neoagent.io/integrations) so Neo discovers the new wrapper script. <Note> Running scripts also requires the **Automation** permission group to be set to **Read & Write** in your VSA X agent's settings — read-only Automation can browse the catalog but not execute. The Third-Party Token must likewise grant write access to Automation. </Note> When an agent runs an on-prem AD or Exchange action, Neo calls this wrapper on the target device, which downloads the generated PowerShell from Neo and runs it. </Tab> </Tabs> ### 3. Set Up a Runner Machine <Note> **Required if:** any server Neo manages (DC, Exchange server, AD Connect server) does **not** have an RMM agent installed. Common scenarios: * You don't want to install RMM on the Domain Controller * The Exchange server doesn't have an RMM agent * The AD Connect server doesn't have an RMM agent </Note> A runner machine is any domain-joined server with an RMM agent that Neo uses to execute scripts on behalf of servers that don't have RMM. The runner can be any domain-joined Windows server — a dedicated management VM, an existing utility server, etc. A single machine can serve as both the AD Runner and Exchange Runner. #### 3a. Install RSAT AD Tools <Note> **Required if:** the DC doesn't have an RMM agent (i.e., the runner performs AD operations on its behalf). </Note> The runner needs the AD PowerShell module to execute Active Directory commands: <Tabs> <Tab title="Windows Server"> Open PowerShell as Administrator and run: ```powershell theme={null} Install-WindowsFeature -Name RSAT-AD-PowerShell ``` Or via Server Manager: **Add Roles and Features → Features → Remote Server Administration Tools → AD DS Tools → AD DS Snap-Ins and Command-Line Tools** </Tab> <Tab title="Windows 10/11"> Open PowerShell as Administrator and run: ```powershell theme={null} Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 ``` Or via **Settings → Apps → Optional Features → Add a feature** and install **RSAT: Active Directory Domain Services and Lightweight Directory Tools**. </Tab> </Tabs> Verify installation by running `Import-Module ActiveDirectory` in PowerShell — it should complete without errors. #### 3b. Create a Dedicated Service Account Create a service account in Active Directory (e.g., `DOMAIN\neo_automation`) and grant it the permissions needed for the operations you want Neo to perform. <Tip> **You control what Neo can do.** Grant only the permissions your team is comfortable with. **Best practice:** Delegate permissions on specific OUs rather than domain-wide. </Tip> <Accordion title="Active Directory permissions"> | Permission | Neo capabilities | | - | - | | Create/delete user objects | User onboarding and offboarding | | Reset password | Password resets, unlock accounts, force password change at logon | | Read/write all user properties | Update name, job title, department, manager, phone, office, company, employee ID, etc. | | Enable/disable accounts | Enable/disable user accounts during onboarding/offboarding | | Read/write group membership | Add/remove users from security and distribution groups | | Read computer objects | View computer accounts and their properties | | Enable/disable computer objects | Enable/disable computer accounts | </Accordion> <Accordion title="Exchange Server permissions (if using on-prem Exchange)"> Assign the **Recipient Management** role to the service account, or delegate equivalent permissions: | Permission | Neo capabilities | | - | - | | Mailbox management | Convert user mailboxes to shared, delete mailboxes | | Mail forwarding | Set up and remove email forwarding | | Mailbox permissions | Grant/revoke Full Access to mailboxes | | Recipient permissions | Grant/revoke Send As and Send on Behalf permissions | | Address list visibility | Hide/unhide mailboxes from the Global Address List | | Distribution group management | Create, delete, and manage distribution group membership | | Mail contact management | Create and manage external mail contacts | | Auto-reply configuration | Configure out-of-office messages | | Mobile device management | View and wipe mobile devices (for offboarding) | | Message tracking | Trace email delivery for troubleshooting | | Transport rules | Create and manage mail flow rules | | Public folder management | Create and manage public folders | | Quarantine management | Release or delete quarantined messages | | Inbox rules | View and manage user inbox rules | | Calendar/resource management | Configure room and equipment booking policies | | Retention policies | Configure message retention settings | | Address list management | Manage GAL, OAB, and address book policies | If the Exchange server is not in RMM (i.e., Neo uses [remote execution](#4-enable-remote-execution) from a runner), the service account also needs WinRM remoting access to the Exchange server. </Accordion> <Accordion title="Azure AD Connect permissions (if using Hybrid identity)"> To trigger AD Connect syncs, the service account must be a member of the **ADSyncOperators** group on the AD Connect server. If the AD Connect server is not the same machine as the AD Runner (i.e., the AD Connect server is not in RMM), the service account also needs WinRM remoting access to the AD Connect server. Neo will use `Invoke-Command` from the runner to trigger the sync remotely. </Accordion> <Accordion title="Extended AD capabilities (optional)"> Neo can also perform these Active Directory operations if you grant the necessary permissions: | Permission | Neo capabilities | | - | - | | Create/delete computer objects | Computer account lifecycle management | | Create/delete/modify OUs | Organizational unit management | | Manage service accounts | Managed Service Account (MSA/gMSA) operations | | Fine-grained password policies | View and modify password policies | | Move/rename AD objects | Reorganize objects between OUs | </Accordion> #### 3c. Configure RMM Component Credentials By default, Datto RMM scripts run under LocalSystem, which has no AD or Exchange permissions on non-DC machines. To run scripts under your service account, configure **Component Credentials** for each site that uses a runner machine. <Note> Component Credentials are configured per site (end-client). For sites without credentials configured, scripts run under LocalSystem — which only works if the RMM agent is installed directly on the DC or Exchange server. </Note> <Warning> **Both halves are required.** Enabling **Requires Component Credentials** on the component does nothing on its own — if the site has no Component Credential, Datto still runs the script as LocalSystem. Likewise, a site credential is ignored by a component that doesn't request credentials. Re-importing the component resets the component half, so check both after every import. **Symptom when either half is missing:** AD/Exchange *reads* succeed (LocalSystem authenticates as the machine account, which can read the directory) while every *write* fails with `Insufficient access rights to perform the operation`. The error names the attribute being written, not the credential, so it reads as an AD permissions problem on the target object rather than a Datto configuration one. To confirm, run `whoami` on the runner through the component: it returns `NT AUTHORITY\SYSTEM` when credentials are not being applied, and `DOMAIN\<service account>` when they are. </Warning> **Step 1: Enable Component Credentials on the Neo script** First, configure the Neo script to use Component Credentials when available: 1. Go to **Automation → Components** and open the **\[Neo Script] Run Powershell** component 2. Toggle **Requires Component Credentials** to ON 3. Click **Save** to apply the change <Warning> Don't forget to save the component after toggling the credential setting. The toggle won't take effect until the component is saved. </Warning> <Frame> <img alt="Datto RMM component with Requires Component Credentials enabled" /> </Frame> **Step 2: Create credentials for each site** For each client that uses a runner machine: 1. In Datto RMM, go to **Setup → Credentials → Create Credential** 2. Enter a **Name** (e.g., "Neo Agent Service Account") 3. Set **Scope** to **Site** and select the client's site 4. Set **Type** to **Component** 5. Enter the service account credentials: * **Username:** `DOMAIN\neo_ad_automation` * **Password:** *(the service account password)* 6. Click **Create Credential** <Frame> <img alt="Creating a Component Credential for a site in Datto RMM" /> </Frame> Repeat for each site where Neo uses a runner machine. ### 4. Enable Remote Execution <Note> **Required if:** a target server doesn't have an RMM agent and Neo reaches it remotely from the runner. This applies when: * The AD Connect server doesn't have an RMM agent (AD Connect Server Hostname differs from AD Runner Hostname) * The Exchange server doesn't have an RMM agent (an Exchange Runner Hostname is configured) </Note> **On each target server (the one without RMM), complete these steps:** 1. **Enable PowerShell Remoting:** ```powershell theme={null} Enable-PSRemoting -Force ``` This configures WinRM and opens the necessary firewall rules. See [Microsoft's documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting) for details and troubleshooting. 2. **Grant the service account remoting access.** The service account configured in [Component Credentials](#3c-configure-rmm-component-credentials) must be able to establish remote PowerShell sessions to the target server. If the service account is not a Domain Admin, add it to the **Remote Management Users** group on the target server, or grant it WinRM access via Group Policy. 3. **Verify network connectivity** from the runner to the target server on port **5985** (HTTP) or **5986** (HTTPS). ### 5. Configure CredSSP for Exchange Runners <Note> **Required if:** the Exchange server doesn't have an RMM agent and Neo reaches it remotely from the runner. This means: * You configured an **Exchange Runner Hostname** in [Mailbox Provider Settings](#mailbox-provider-settings) * The runner and Exchange server are different machines </Note> When the runner remotes into the Exchange server, Exchange cmdlets need to reach Active Directory to perform operations like provisioning mailboxes or modifying user attributes. By default, Windows blocks the service account's credentials from being forwarded beyond that first remote connection — a known limitation called the [Kerberos "double-hop" problem](https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/ps-remoting-second-hop?view=powershell-7.5). Neo solves this with [CredSSP authentication](https://learn.microsoft.com/en-us/windows/win32/secauthn/credential-security-support-provider). When CredSSP is enabled, Neo forwards the service account's credentials to the Exchange server, allowing Exchange to authenticate directly to AD. No Kerberos delegation configuration is needed. <Warning> CredSSP sends the service account's credentials to the remote machine. This is safe when the Exchange server is a trusted, domain-joined server on an internal network — which it always is in this scenario. The service account should have only the minimum permissions required. </Warning> **Step 1: Enter the service account credentials in Neo.** In the [Companies tab](https://dashboard.neoagent.io/end-companies), edit the company and fill in: * **Exchange Service Account Username** — e.g., `CONTOSO\SVC_NEO_AUTOMATION` * **Service Account Password** Neo stores the password securely in Azure Key Vault and injects it into the script only at execution time. **Step 2: Enable CredSSP on the runner (client role).** On the runner machine, open PowerShell as Administrator: ```powershell theme={null} Enable-WSManCredSSP -Role Client -DelegateComputer "EXCHANGE-SHORT","EXCHANGE-FQDN","*.yourdomain.com" -Force ``` Replace `EXCHANGE-SHORT` with the Exchange server's short hostname, `EXCHANGE-FQDN` with its FQDN, and `*.yourdomain.com` with your domain's wildcard. Including all three forms prevents hostname resolution mismatches. **Step 3: Enable CredSSP on the Exchange server (server role).** On the Exchange server, open PowerShell as Administrator: ```powershell theme={null} Enable-WSManCredSSP -Role Server -Force ``` **Step 4: Verify CredSSP is working.** On the runner, open a PowerShell prompt as the service account: ```powershell theme={null} runas /user:DOMAIN\your_service_account powershell ``` Then test the full chain: ```powershell theme={null} $password = ConvertTo-SecureString 'YOUR_PASSWORD' -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential('DOMAIN\your_service_account', $password) Invoke-Command -ComputerName "EXCHANGE-SERVER" -Authentication CredSSP -Credential $cred -ScriptBlock { Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn Get-ExchangeServer | Select-Object Name } ``` This tests the full chain: Runner → Exchange (via CredSSP) → Active Directory. `Get-ExchangeServer` requires Exchange to query AD, so if it returns the server name, CredSSP is working end-to-end. * If it **succeeds** — CredSSP is configured correctly. * If it fails with **"A computer policy does not allow the delegation of the user credentials"** — re-run Step 2 with the correct hostname forms, including the wildcard. * If it fails with a **permissions error** — CredSSP is working, but the service account may lack [Exchange permissions](#3b-create-a-dedicated-service-account). ### 6. Verify Connectivity After completing setup, run these checks from the runner machine (or the DC if using direct execution) to confirm everything is working. #### Neo API connectivity The machine running scripts must be able to reach the Neo API. Run: ```powershell theme={null} [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri "https://engine.neoagent.io" -UseBasicParsing ``` **Expected result:** `401 Unauthorized` — this confirms the server can reach Neo over HTTPS. If you see an SSL error or timeout, see [Troubleshooting](#troubleshooting). #### AD tools (if using on-prem AD) Verify the runner has the AD PowerShell module and can query the domain: ```powershell theme={null} Import-Module ActiveDirectory Get-ADUser -Filter * -ResultSetSize 1 ``` Both commands should complete without errors. #### Remote execution (if applicable) If the AD Connect server or Exchange server is reached via [remote execution](#4-enable-remote-execution), verify connectivity from the runner under the service account: ```powershell theme={null} # Test AD Connect server Invoke-Command -ComputerName "AD-CONNECT-SERVER" -ScriptBlock { hostname } # Test Exchange server Invoke-Command -ComputerName "EXCHANGE-SERVER" -ScriptBlock { hostname } ``` Each command should return the target server's hostname. If it fails, check: * PowerShell Remoting is enabled on the target (`Enable-PSRemoting -Force`) * The service account is in the **Remote Management Users** group on the target * Port **5985** or **5986** is open between the runner and the target *** ## Exchange Hybrid Use **Exchange Hybrid** when a client has both on-prem Exchange and Exchange Online — typically during a migration or in long-term coexistence. **How Neo routes operations:** * **Standard mailbox operations** (forwarding, delegation, shared mailbox conversion, permissions, etc.) route to **Exchange Online** via Microsoft Graph — the same as pure Exchange Online clients. * **On-prem Exchange cmdlets** (e.g., `Enable-RemoteMailbox` for hybrid mailbox provisioning) are executed on the on-prem Exchange server when Neo's agent determines they're needed. **Setup:** 1. Set **Mailbox Provider Type** to "Exchange Hybrid" in [Company Settings](#1-configure-company-settings) 2. Set the **Exchange Server Hostname** to the on-prem Exchange server 3. *(Optional)* Set the **Exchange Runner Hostname** if the Exchange server doesn't have an RMM agent — then complete [Step 3](#3-set-up-a-runner-machine), [Step 4](#4-enable-remote-execution), and [Step 5](#5-configure-credssp-for-exchange-runners) <Tip> If you already have a runner VM for AD operations, you can reuse it as the Exchange Runner — just set the **Exchange Runner Hostname** to the same machine and ensure the service account has the necessary [Exchange permissions](#3b-create-a-dedicated-service-account). </Tip> *** ## Troubleshooting ### "The supplied credential is invalid" on Exchange Runner **Symptom:** Exchange operations (e.g., `Enable-RemoteMailbox`) fail with: ``` Active Directory operation failed on . The supplied credential for 'DOMAIN\service_account' is invalid. ``` **Cause:** This is the [Kerberos "double-hop" problem](https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/ps-remoting-second-hop?view=powershell-7.5). When Neo remotes from the runner to the Exchange server, Windows blocks the service account's credential from being forwarded to Active Directory. The credential itself is valid — Windows is blocking the delegation. **How to tell:** If the same service account works for AD operations (password resets, user creation, group changes) but fails only for Exchange commands via a runner, this is the double-hop issue. **Fix:** Configure CredSSP authentication. See [Step 5](#5-configure-credssp-for-exchange-runners) for instructions. Ensure the service account username and password are entered in the [Company Settings](#1-configure-company-settings). **Still failing after configuring CredSSP?** Check these common issues: * **CredSSP client not configured:** Run `Get-WSManCredSSP` on the runner — it should show CredSSP is enabled as a client with the Exchange server in the delegate list. * **CredSSP server not configured:** Run `Get-WSManCredSSP` on the Exchange server — it should show CredSSP is enabled as a server. * **GPO blocking delegation:** If you see "A computer policy does not allow the delegation of the user credentials", re-run `Enable-WSManCredSSP -Role Client` on the runner with the FQDN, short hostname, AND domain wildcard forms. * **Wrong password in Neo:** Verify the service account password in the Companies tab is correct. ### SSL/TLS Certificate Trust Error **Symptom:** RMM scripts fail with an error like: ``` The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ``` **Cause:** The server running Neo scripts cannot validate the certificate chain for `engine.neoagent.io`. There are two common causes: 1. **A DNS or web filter is intercepting the request.** Filtering products (Cisco Umbrella/OpenDNS, and similar DNS-layer or TLS-inspecting appliances) answer the lookup with their own block page instead of the real address. Because that block page cannot present a valid certificate for `engine.neoagent.io`, the connection surfaces as a trust failure rather than as a "blocked" message. Intermittent failures on a machine that usually works point here. 2. **Outdated root certificates**, typically on older Windows servers. **Diagnose:** Run this on the affected server: ```powershell theme={null} [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri "https://engine.neoagent.io" -UseBasicParsing ``` * **Expected result:** 401 Unauthorized (confirms SSL/TLS is working) * **If you see an SSL error:** continue below to tell the two causes apart Check whether a filter is answering the DNS lookup: ```powershell theme={null} Resolve-DnsName engine.neoagent.io ``` A filtered result returns an address belonging to the filtering vendor rather than Neo's — Cisco Umbrella block addresses are in `146.112.61.0/24`. You can confirm which product is responsible with: ```powershell theme={null} Resolve-DnsName debug.opendns.com -Type TXT ``` If that returns records with a non-zero `originid`, the machine's DNS is being handled by an Umbrella/OpenDNS account, and its policy is what to check. **Fix:** 1. **Allow `neoagent.io` in your DNS/web filter** — if the checks above showed a filter answering the lookup, add `neoagent.io` **including its subdomains** to the filter's allow list. In Cisco Umbrella this is Policies → Destination Lists; Reporting → Activity Search for `engine.neoagent.io` shows which policy and category triggered the block. Allow the whole domain rather than a single host, so the dashboard, docs and API stay reachable too. 2. **Update Windows root certificates** — Install the latest Windows updates, or manually update certificates: ```powershell theme={null} certutil -generateSSTFromWU roots.sst certutil -addstore -f Root roots.sst ``` 3. **Check TLS 1.2 is enabled** — Verify in registry: ``` HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2 ``` 4. **Check server clock** — Certificate validation fails if the system time is significantly off 5. **Check for TLS-inspecting proxies** — Some security appliances re-sign HTTPS traffic; the appliance's root CA must be trusted by the machine, or the chain breaks <Note> Neo's wrapper retries a failed download three times before giving up, so a brief blip recovers on its own. A failure that reaches Neo reports as `NEO_SCRIPT_DOWNLOAD_FAILED`, which means all three attempts failed and the cause is persistent. </Note> ### No Internet Access / Firewall Blocking **Symptom:** RMM scripts fail with connection errors, timeouts, or "Unable to connect to the remote server." **Cause:** The server running Neo scripts cannot reach the Neo API endpoint due to no internet access or firewall restrictions. **Fix:** Ensure the server can reach `https://engine.neoagent.io`. Add a firewall rule to allow outbound HTTPS (port 443) to this endpoint. **Diagnose:** Run this on the affected server: ```powershell theme={null} [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri "https://engine.neoagent.io" -UseBasicParsing ``` * **Expected result:** 401 Unauthorized (confirms connectivity is working) * **If you see a connection/timeout error:** The server cannot reach the endpoint — check firewall rules and proxy settings *** ## Other RMM Platforms Neo supports on-prem execution through any RMM platform that can run PowerShell scripts, including: * N-Able N-Sight RMM * N-Able N-Central * ConnectWise RMM (Asio) <Tip> Using an RMM other than Datto, NinjaOne, ConnectWise Automate, or Kaseya VSA X? Reach out to us in Teams and we'll help you get set up. </Tip> # Marketplaces Source: https://docs.neoagent.io/integrations/marketplaces/intro Manage SaaS licensing and automate provisioning checks ## Supported platforms * [Pax8](/integrations/marketplaces/pax8) * D\&H Cloud Marketplace * Ingram Micro Cloud Marketplace * Sherweb * [TD SYNNEX StreamOne ION](/integrations/marketplaces/td-synnex) * [TD SYNNEX StreamOne Stellr](/integrations/marketplaces/td-synnex-stellr) * [OpenText Secure Cloud](/integrations/opentext/overview) (formerly AppRiver) * Microsoft Partner Center ## What you can automate * Purchase or cancel license seats, targeting a **specific subscription** when multiple exist for the same license * Assign or unassign licenses as part of user lifecycle * Adjust license seats during onboarding/offboarding * Sync product and subscription data to drive checks ## Subscription targeting Many MSPs maintain multiple subscriptions for the same Microsoft license (e.g., an 80/20 yearly/monthly split). Neo Agent targets the exact subscription by first calling [List License Subscriptions](/agents/tools/m365/list-license-subscriptions) to discover all subscriptions for a license — including their IDs, billing terms, commitment terms, and seat counts — and then passing the chosen subscription ID to the purchase or cancel tool. Use custom instructions to guide which subscription the agent should target (e.g., "always add seats to the Monthly subscription"). ## Setup overview Marketplace integration requires two steps: 1. **Connect your platform** (once per MSP) — Save your API credentials under **Integrations → Other**. This lets Neo communicate with the marketplace API. 2. **Map each company** (per end-client) — On the **Companies** page, add a **Marketplace Company ID** for each company that needs license management. This tells Neo which marketplace customer corresponds to which PSA company. **Ingram Micro**, **TD SYNNEX ION**, **TD SYNNEX Stellr** and **OpenText Secure Cloud** customers are matched to PSA companies automatically after each PSA sync (see [Ingram Micro](#ingram-micro-cloud-marketplace), [TD SYNNEX ION](/integrations/marketplaces/td-synnex#customer-mapping), [TD SYNNEX Stellr](/integrations/marketplaces/td-synnex-stellr#customer-mapping) and [OpenText Secure Cloud](/integrations/opentext/overview#your-clients-are-mapped-automatically)); a typed ID is only needed to override or fill a gap. <Info> The **Marketplace Company ID** is the customer identifier from your marketplace provider (e.g., the Ingram Micro `customerId`, Pax8 company UUID, D\&H account ID, or Sherweb customer ID) — **not** the Autotask or ConnectWise company ID. Find it in your marketplace portal under the customer's account details. For **Sherweb**, pick the customer from the dropdown instead (see [Sherweb](#sherweb)). </Info> For Pax8, D\&H, Sherweb and Microsoft Partner Center, a company without a marketplace ID cannot have its licenses managed — Neo won't know which marketplace customer to query. Ingram Micro, TD SYNNEX ION, TD SYNNEX Stellr and OpenText Secure Cloud companies need one only when the automatic match is missing or wrong. ## Step 1 — Connect your platform ### Pax8 1. Open Pax8 Integrations → Credentials and create API credentials. <Frame> <img alt="Create and manage Pax8 API credentials" /> </Frame> 2. View the credential to copy Client ID and Client Secret. <Frame> <img alt="View Pax8 credential details" /> </Frame> 3. In Neo, go to Integrations → Other and save the credentials. To let agents order a product a client does not hold yet, see [Pax8](/integrations/marketplaces/pax8). ### D\&H 1. Create a D\&H user with required access. 2. Find your AccountID from the MSP company URL, for example: `https://cp.dandhcloudsolutions.com/#/Account/View/54632/Overview`. 3. In Neo, save username, password, and AccountID under Integrations → Other. ### Ingram Micro Cloud Marketplace Neo connects to the [Ingram Micro Cloud Marketplace API](https://apidocs.cloud.im/) to manage subscriptions and license seats. You will need five pieces of information: | Credential | Description | | - | - | | **Username** | Your Marketplace API username (typically in the format `youremail.API`) | | **Password** | The password configured for the API user | | **Subscription Key** | The `X-Subscription-Key` value that authenticates every API request | | **API URL** | The API URL shown on your Marketplace API page — copy it **exactly** (e.g. `https://api.cloud.im/marketplace/na`). CloudBlue hosts differ by region/cluster, so this must come from your portal, not be guessed | | **Marketplace** | Your country marketplace code (e.g. `au`, `nz`, `us`, `uk`) — one API URL can serve multiple marketplaces (the Oceania URL serves both `au` and `nz`) | <Warning> **Do not enter your regular XVantage login credentials into Neo — they will not work.** The Marketplace API is a separate product with its own dedicated username, password, and subscription key. You obtain these only after activating the free "Marketplace API" add-on (see Step 1). Attempting to authenticate with XVantage portal credentials will return `401 Unauthorized` from Ingram and no license operations will succeed. </Warning> <Note> Ingram Micro has consolidated its partner experience under **XVantage**, which is where you now manage cloud subscriptions and activate the Marketplace API add-on. For background on the underlying API, see Ingram's [Cloud Marketplace API — Getting Started](https://apidocs.cloud.im/1.5/howto/ready/) guide. </Note> #### Step 1 — Activate the Marketplace API product (free) 1. Sign in to **XVantage** (or your regional Cloud Marketplace portal, e.g. `https://portal.cloud.im/`). 2. Search the storefront for **"Marketplace API"** — it lives under the *Integration and Tools* category. 3. Add it to your cart and place the order. **This is free (\$0.00)** — no charge is added to your account, but placing the order is what activates the API. 4. Once activated, a new **Marketplace API** menu item appears in your portal. <Tip> If you can't find the product, Ingram has a walkthrough on the [Cloud Marketplace API — Getting Started](https://apidocs.cloud.im/1.5/howto/ready/) page, and the [Ingram Developer Portal](https://developer.ingrammicro.com/) hosts the full API reference. </Tip> #### Step 2 — Collect your API credentials 1. Open the **Marketplace API** menu in XVantage (or the Cloud Marketplace portal). 2. Copy the **Username**, **API URL**, and **Subscription Key** shown on that page. 3. If you don't have a password yet or need a reset, contact Ingram Micro Cloud support: * US: `imcloudservicedesk.us@cloud.im` * General integration support: `usxvantageintegrations@ingrammicro.com` #### Step 3 — Determine your marketplace code The **API URL** from Step 2 already points Neo at the right regional host (for example, North America is served by `…/marketplace/na`, Europe and the UK by `…/marketplace/eu`, and Oceania by `…/marketplace/oc`) — so you don't enter a region separately. You still need your **marketplace** code: the specific country marketplace Ingram tags each request with. One API URL can serve multiple marketplaces, so the host and the marketplace code are not the same value: | Host region | Example marketplace codes | | - | - | | North America (`…/marketplace/na`) | `us` | | Europe / UK (`…/marketplace/eu`) | `uk`, `de`, `fr`, `it`, `es`, … (country-specific) | | Oceania (`…/marketplace/oc`) | `au`, `nz` | <Note> If you skip the marketplace value, the token request fails with `401 Unauthorized` from Ingram — this is what Ingram means when they ask whether you're tagging requests with the correct country code. </Note> #### Step 4 — Save credentials in Neo 1. In Neo, go to **Integrations → Other**. 2. Select **Ingram Micro** from the integration dropdown. 3. Enter your **username**, **password**, **subscription key**, **API URL**, and **marketplace**. 4. Click **Save**. Neo runs a live token call to confirm the credentials before saving, so a wrong API URL or marketplace code is caught here rather than failing silently later. #### Finding your customer IDs After connecting your credentials, Neo maps your Ingram Micro customers to PSA companies for you. On every PSA sync it lists your marketplace customers and matches each one to a PSA company by name (exact, then legal-suffix-tolerant, then an AI suggestion for the long tail). Review the result under **Integrations → Other → Ingram Micro → Organization Mapping**: map any customer left unmapped, or correct a match — a manual mapping is kept across syncs. Only an exact, one-to-one name match is used on its own. Everything else — a legal-suffix match, an AI suggestion, two companies sharing a name, or two customers matching one company — is shown for confirmation only, and Neo never places or cancels an order against it. To override the automatic match for a company, enter its **Customer ID** as the Marketplace Company ID on the Companies page (see [Step 2](#step-2-—-map-companies-to-marketplace-customers)); a typed ID always wins: 1. Sign in to XVantage (or your regional Cloud Marketplace portal). 2. Navigate to **Customers** and open the customer account. 3. The **Customer ID** is displayed in the customer details — this is the value to enter as the Marketplace Company ID in Neo. <Info> Neo's integration uses Ingram's **Cloud Marketplace API** (the API URL you provide, e.g. `https://api.cloud.im/marketplace/na`), which covers SaaS subscription lifecycle — purchase, change quantity, cancel. Ingram's separate [XVantage Integration (XI) API](https://developer.ingrammicro.com/) covers product catalog, orders, quotes, invoices, and renewals for hardware/traditional SKUs, and is not currently used by Neo for M365 license management. </Info> ### Sherweb Neo connects to the [Sherweb Service Provider API](https://developers.sherweb.com/) to manage subscriptions and license seats. You will need three pieces of information: | Credential | Description | | - | - | | **Client ID** | Your Sherweb API client ID | | **Client Secret** | Your Sherweb API client secret | | **Subscription Key** | The `Ocp-Apim-Subscription-Key` value that authenticates every API request | #### Collecting your API credentials 1. Sign in to the [Sherweb Cumulus portal](https://cumulus.sherweb.com/). 2. Navigate to **Security → APIs**. 3. Create or view your API credentials to obtain the **Client ID**, **Client Secret**, and **Subscription Key**. #### Saving credentials in Neo 1. In Neo, go to **Integrations → Other**. 2. Select **Sherweb** from the integration dropdown. 3. Enter your **Client ID**, **Client Secret**, and **Subscription Key**. 4. Click **Save**. #### Mapping companies to Sherweb customers 1. Go to the **Companies** page and open (or add) a company. 2. Under **Marketplace Company IDs**, add a row and select **Sherweb**. 3. Pick the customer from the searchable dropdown and click **Save**. ### TD SYNNEX TD SYNNEX runs two platforms with separate APIs; connect the one your portal is. * **StreamOne ION**: connect with your Account ID and a refresh token. See [TD SYNNEX ION](/integrations/marketplaces/td-synnex). * **StreamOne Stellr**: connect with a Client ID and Client Secret from the Stellr Developer Portal. See [TD SYNNEX Stellr](/integrations/marketplaces/td-synnex-stellr). ### OpenText Secure Cloud OpenText Secure Cloud connects with a Client ID, a Client secret and a refresh token, and maps its customers to PSA companies on its own **Organization Mapping** tab. Agents use it through the [Vendor API](/agents/tools/vendor-api) tool to create users and assign or remove their Microsoft 365 licences, and change seat quantities with [Change License Seats](/agents/tools/m365/change-license-seats). For a company typed by hand, the Marketplace Company ID is the Secure Cloud customer ID (a GUID). See [Connecting OpenText Secure Cloud to Neo](/integrations/opentext/connecting-to-neo). ### Microsoft Partner Center 1. Sign in to [Partner Center](https://partner.microsoft.com/dashboard/home) with a Global Admin account. 2. Select **Settings** (gear icon) → **Account settings** → **App management**. * Direct link: [https://partner.microsoft.com/dashboard/v2/account-settings/appmanagement](https://partner.microsoft.com/dashboard/v2/account-settings/appmanagement) * If you don't see this option, try with a different Global Admin user. 3. Add a new web app. 4. Copy the **App ID** and **Key** (client secret). 5. In Neo, go to **Integrations → Other**, select **Microsoft Partner Center**, and save the credentials. ## Step 2 — Map companies to marketplace customers Once your platform credentials are saved, link each end-client company to its marketplace customer: 1. Go to the **Companies** page in Neo. 2. Click a company to open it. 3. Under **Marketplace Company IDs**, click **Add Marketplace**. 4. Select your marketplace provider (e.g., Ingram Micro) from the dropdown. 5. Enter the **customer ID from your marketplace portal** — this is the ID your marketplace provider uses to identify this customer, not the PSA company ID. For **Sherweb**, pick the customer from the dropdown instead (see [Sherweb](#sherweb)). 6. Click **Save**. <Tip> Neo auto-detects which marketplace to use for each company based on the marketplace IDs you configure. If a company has multiple marketplace IDs, Neo checks in this order: Pax8 → D\&H → Ingram Micro → Sherweb → TD SYNNEX ION → TD SYNNEX Stellr → OpenText Secure Cloud → Microsoft Partner Center. A company with no typed ID but a confirmed or exact-matched Ingram Micro, TD SYNNEX ION, TD SYNNEX Stellr or OpenText Secure Cloud customer in Organization Mapping uses that marketplace, in that order. When a mapped OpenText Secure Cloud customer holds no Microsoft 365 service there and you saved Partner Center credentials, Neo uses Microsoft Partner Center instead; without Partner Center credentials, the agent tells the technician that customer has no Microsoft 365 service. </Tip> # Pax8 Source: https://docs.neoagent.io/integrations/marketplaces/pax8 Connect Pax8 so agents can read subscriptions and prices, add or remove licence seats, and order a product a client does not hold yet Neo connects to the [Pax8 Partner API](https://devx.pax8.com/). With it connected, an agent can: * Read companies, contacts, subscriptions, orders, invoices and usage * Look up products, the price you pay per billing term, commitment terms and the details an order needs * Order a product a client does not hold yet, after a technician approves it * Add or remove seats on an existing subscription with [Change License Seats](/agents/tools/m365/change-license-seats) ## Connect Pax8 <Steps> <Step title="Create an API credential"> In Pax8, open **Integrations → Credentials** and create an API credential. View it to copy the **Client ID** and **Client Secret**. </Step> <Step title="Save it in Neo"> Open [**Integrations**](https://dashboard.neoagent.io/integrations?open=pax8), select **Pax8**, enter the Client ID and Client Secret, and click **Save**. </Step> <Step title="Map each company"> On the [Companies](https://dashboard.neoagent.io/end-companies) page, open a company and add its Pax8 company ID under **Marketplace Company IDs**. Find the ID in the Pax8 portal on the company's page. Agents use this ID for orders and cancellations, and each approval request names the Pax8 company. </Step> </Steps> ## What agents can do Agents call Pax8 through the [Vendor API](/agents/tools/vendor-api) tool, which is added when you give the agent Pax8 permissions in its settings. Each permission group has its own access level: | Permission group | What it covers | | - | - | | **Companies** | Pax8 companies, creating or updating one | | **Contacts** | A company's contacts and their roles | | **Products & Pricing** | Products, your cost per billing term, commitment terms and provisioning details (read-only) | | **Subscriptions** | Subscriptions, seat counts and history, cancellation | | **Orders** | Order history and new orders | | **Invoices & Usage** | Invoices, invoice lines and usage (read-only) | The access profiles are **Read Only**, **Helpdesk** (every change asks a technician first) and **IT Admin** (no approval, except the two changes below). You can set approval per permission group. <Warning> A new order and a subscription cancellation always ask a technician for approval, in every profile. Pax8 bills you for an order, and Microsoft does not let you reduce or cancel an annual commitment after its first days. </Warning> ## Buying a product a client does not hold 1. The agent finds the product, your price for the billing term, the commitment term and the provisioning details Pax8 needs. 2. It asks a technician to approve the order. The request names the product, the quantity, the billing and commitment terms, the price and what the commitment allows, such as "seats cannot be reduced until the term ends". 3. After approval, it places the order with exactly those values. 4. For a Microsoft product, once the new subscription is active and the licence shows in the client's Microsoft 365 tenant, the agent assigns it if it has the M365 Licensing permission; otherwise it uses your licensing tool, such as CIPP, or hands the step to a technician. When a company has order approval turned on in Pax8, the order waits there until someone approves it in Pax8. ## Seat changes To add or remove seats on a subscription the client already holds, the agent uses [Change License Seats](/agents/tools/m365/change-license-seats). It changes one subscription at a time and reads the new count back. The Vendor API tool refuses every subscription update, so a seat change made at the same time cannot overwrite it. Change a billing term in the Pax8 portal. # TD SYNNEX ION Source: https://docs.neoagent.io/integrations/marketplaces/td-synnex Connect TD SYNNEX StreamOne ION so agents can read customers, subscriptions and prices, place orders, and add or remove licence seats Neo connects to the [StreamOne ION API](https://docs.streamone.cloud/) (version 3), the cloud marketplace TD SYNNEX resellers buy Microsoft 365 and other subscriptions through. With it connected, an agent can: * Find the ION customer behind a PSA company, and the Microsoft tenant it is bound to * Read subscriptions with their seat counts, renewal dates and auto-renew settings * Look up products, SKUs, plans and customer prices * Create a customer, place an order for a product the customer does not hold yet, and follow the order to completion * Add or remove seats on an existing subscription with [Change License Seats](/agents/tools/m365/change-license-seats) <Note> If your portal is StreamOne Stellr, the SYNNEX platform many North and Latin American partners use, connect [TD SYNNEX Stellr](/integrations/marketplaces/td-synnex-stellr) instead. The two use different APIs and different credentials. </Note> ## Connect TD SYNNEX You need two values from the ION portal: your **Account ID** and a **Refresh Token**. <Steps> <Step title="Copy your Account ID"> In the StreamOne ION portal, open **Settings → Account Information** and copy the Account ID. It is a number. </Step> <Step title="Create a refresh token"> Open **Settings → Users** and edit the user Neo will act as. We recommend a dedicated API user with the **Account Admin** role, so orders Neo places are easy to tell apart in ION. Choose **OAuth credentials → Request New Credentials** and copy the **Refresh Token**. </Step> <Step title="Save it in Neo"> Open [**Integrations**](https://dashboard.neoagent.io/integrations?open=td_synnex), select **TD SYNNEX ION**, enter the Account ID and the Refresh Token, and click **Save**. Neo exchanges the token with ION before it saves, so a wrong or used token is refused on the spot. </Step> </Steps> <Warning> **Use the refresh token in Neo only.** An ION refresh token works once. Each time Neo connects, ION returns a new token and Neo stores it in place of the old one. If another tool or script uses the same token, one of the two stops working and you must create a new token in the portal. </Warning> A refresh token expires after 32 days without use. Neo maps your ION customers to PSA companies after each PSA sync, and that run renews the token, so an account whose PSA keeps syncing stays connected. If ION refuses the token (for example, after someone requested new credentials for the same user), Neo shows an action item in your inbox: create a new refresh token and save it in Neo again. ## Customer mapping Neo maps each ION customer to a PSA company after you save the credentials, and again after each PSA sync: 1. **Microsoft tenant** — the tenant on the customer's ION Microsoft profile matches the **Tenant ID** on one of your companies. This is an exact match. 2. **Name** — the customer's organization name matches a PSA company name. 3. **AI suggestion** — for the names the first two steps miss. Review the result under **Integrations → TD SYNNEX ION → Organization Mapping**. Map a customer left unmapped, or correct a match; a manual mapping is kept across syncs. Seat changes spend money, so only a tenant match, an exact one-to-one name match, or a mapping you confirmed selects the customer for a seat change. A suggested match lists for confirmation and never places an order on its own. To override the mapping for one company, enter its ION customer ID as a **Marketplace Company ID** on the [Companies](https://dashboard.neoagent.io/end-companies) page; a typed ID always wins. ## What agents can do Agents call ION through the [Vendor API](/agents/tools/vendor-api) tool, which is added when you give the agent TD SYNNEX permissions in its settings. Each permission group has its own access level: | Permission group | What it covers | | - | - | | **Customers** | ION customers, their Microsoft tenants, creating a customer, linking or provisioning its Microsoft tenant | | **Catalog & Pricing** | Products, SKUs, plans and customer prices (read-only) | | **Subscriptions** | Subscriptions, seat counts and renewal dates (read-only) | | **Orders** | Placing an order for a new product, following it, cancelling one ION has not processed | | **Carts** | Building a multi-item purchase and checking it out | | **Reports** | Reports saved in ION, such as billing and renewals (read-only) | The access profiles are **Read Only**, **Helpdesk** (every change asks a technician first) and **IT Admin** (no approval). You can set approval per permission group. A seat change always goes through [Change License Seats](/agents/tools/m365/change-license-seats), never through an order from the Vendor API tool. ### Seat changes To add or remove seats on a subscription a customer already holds, the agent uses [Change License Seats](/agents/tools/m365/change-license-seats), not an order through the Vendor API tool. It serializes changes to one subscription, so two changes at the same time cannot both start from the same count, waits for ION to finish the order, and reads the subscription back to confirm the new count. The wait has a time limit, about 30 seconds in a chat and 90 seconds in an automation. When ION takes longer, the agent reports the change as unconfirmed, and you can check the count in the ION portal. Neo does not schedule a TD SYNNEX seat change for the renewal date yet, so a seat change applies immediately. To change seats at renewal, schedule the workflow to run on the renewal day. # TD SYNNEX Stellr Source: https://docs.neoagent.io/integrations/marketplaces/td-synnex-stellr Connect TD SYNNEX StreamOne Stellr so agents can read customers, subscriptions and prices, create subscriptions, and add or remove licence seats Neo connects to the StreamOne Stellr API, the cloud marketplace TD SYNNEX resellers in North and Latin America buy Microsoft 365 and other subscriptions through. With it connected, an agent can: * Find the Stellr customer behind a PSA company, and the Microsoft tenant on its vendor account * Read subscriptions with their seat counts, renewal dates and auto-renew settings * Look up products and prices, and read invoices * Create a customer or a new subscription, and follow the provisioning operation to completion * Add or remove seats on an existing subscription with [Change License Seats](/agents/tools/m365/change-license-seats) <Note> If your portal is StreamOne ION, the global TD SYNNEX platform, connect [TD SYNNEX ION](/integrations/marketplaces/td-synnex) instead. The two use different APIs and different credentials. </Note> ## Connect TD SYNNEX Stellr You need a **Client ID** and a **Client Secret** from the Stellr Developer Portal. <Steps> <Step title="Enroll for API access"> Sign in to ECExpress and open **StreamOne Stellr → Integration → Developer APIs**. Enroll, then open the **Developer Portal**. </Step> <Step title="Create a client credential"> In the Developer Portal, open **My Account → Client Credentials** and create a **Prod** credential. Copy the **Client Secret** now, because the portal shows it only once. Give the credential the **End Customers** and **Subscriptions** API permissions. A new credential can take up to 10 minutes to start working. </Step> <Step title="Save it in Neo"> Open [**Integrations**](https://dashboard.neoagent.io/integrations?open=td_synnex_stellr), select **TD SYNNEX Stellr**, and enter the Client ID and the Client Secret. Set **Region** to the region your reseller account belongs to (United States, Canada, Brazil or Mexico). Leave **Environment** on **Production** unless TD SYNNEX gave you sandbox credentials; a sandbox credential works only against the sandbox. Click **Save**. Neo checks the credential against your region before it saves, so a wrong secret, region or environment is refused on the spot. </Step> </Steps> ## Customer mapping Neo maps each Stellr customer to a PSA company after you save the credentials, and again after each PSA sync: 1. **Microsoft tenant**: the Microsoft ID on the customer's Stellr Microsoft vendor account matches the **Tenant ID** on one of your companies. This is an exact match. 2. **Name**: the customer's company name matches a PSA company name. 3. **AI suggestion**: for the names the first two steps miss. Review the result under **Integrations → TD SYNNEX Stellr → Organization Mapping**. Map a customer left unmapped, or correct a match; a manual mapping is kept across syncs. Seat changes spend money, so only a tenant match, an exact one-to-one name match, or a mapping you confirmed selects the customer for a seat change. A suggested match lists for confirmation and never changes seats on its own. To override the mapping for one company, enter its Stellr customer number as a **Marketplace Company ID** on the [Companies](https://dashboard.neoagent.io/end-companies) page; a typed ID always wins. ## What agents can do Agents call Stellr through the [Vendor API](/agents/tools/vendor-api) tool, which is added when you give the agent TD SYNNEX Stellr permissions in its settings. Each permission group has its own access level, covering customers and their Microsoft tenants, the catalogue and prices, subscriptions and provisioning operations, and invoices. The access profiles are **Read Only**, **Helpdesk** (every change asks a technician first) and **IT Admin** (no approval). You can set approval per permission group. Seat changes go through Change License Seats, never through the Vendor API tool, and follow that tool's own approval setting. ### Seat changes To add or remove seats on a subscription a customer already holds, the agent uses [Change License Seats](/agents/tools/m365/change-license-seats). It serializes changes to one subscription, so two changes at the same time cannot both start from the same count. It asks Stellr for the new total seat count, waits for Stellr's provisioning operation to finish, and reads the subscription back to confirm the new count. The wait has a time limit, about 30 seconds in a chat and 90 seconds in an automation. When Stellr takes longer, the agent reports the change as unconfirmed, and you can check the count in the Stellr portal. A Stellr subscription keeps at least one seat. To remove the last seat, cancel the subscription. Neo does not schedule a Stellr seat change for the renewal date yet, so a seat change applies immediately. To change seats at renewal, schedule the workflow to run on the renewal day. # Connecting Cisco Meraki to Neo Source: https://docs.neoagent.io/integrations/meraki/connecting-to-neo Save a Meraki Dashboard API key and your Meraki region in Neo You connect Meraki once at the MSP level, with one Dashboard API key. ## 1. Generate the API key <Steps> <Step title="Pick the admin"> The key acts as the dashboard admin who generates it, in every organization that admin can see. Use an admin with access to your clients' organizations. A key from a read-only admin lets Neo read only. An admin who signs in only through SAML cannot generate a key. </Step> <Step title="Generate the key"> In **Organization** → **API & Webhooks**, open **API keys and access** and click **Generate API key**. Copy the key: Meraki shows it once. An admin can hold two keys. </Step> </Steps> <Warning> Do not revoke the key in Meraki after you connect it. Neo loses access until you save a new key here. </Warning> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Cisco Meraki**](https://dashboard.neoagent.io/integrations?open=meraki), under Networking. </Step> <Step title="Save the key"> Enter the API key. Leave **Region** on Global unless you sign in to Meraki at a Canada, China, India or US FedRAMP address. Click **Save settings**. Neo checks the key against Meraki before saving, so a wrong key or region is rejected straight away. </Step> </Steps> ## 3. Turn Meraki on per agent Open the agent, go to the Integrations section, and configure the Cisco Meraki block. Agents reach only the organizations the key's admin can see. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Read every area. Nothing is changed. </Card> <Card title="Helpdesk" icon="headset"> Read every area. Device, client and switch port actions (reboot, port cycle, cable test, block a client) wait on a technician. </Card> <Card title="IT Admin" icon="user-gear"> Read and change every area. Security Appliance & VPN, Wireless, Firmware, Licensing and Administration changes wait on a technician. </Card> <Card title="Full Automation" icon="bolt"> Read and change every area without approval, apart from the changes below that always ask. </Card> </CardGroup> ### Or set each area by hand Each area takes Disabled, Read Only or Read/Write, and has its own technician approval setting. | Area | Covers | | - | - | | **Organizations & Networks** | Organizations, networks, network settings, floor plans and the configuration change log. | | **Devices & Inventory** | Devices, availability, inventory, live diagnostics (ping, ARP and MAC tables, port status); reboot, blink LEDs, wake-on-LAN, claim. | | **Monitoring & Clients** | Events, alerts, uplinks, loss and latency, clients, topology and LLDP/CDP; block or allow a client. | | **Wireless** | SSIDs, RF profiles, Air Marshal, SSID firewall rules and Wi-Fi stats. | | **Switching** | Switch ports, stacks, ACLs, routing and QoS; port cycle and cable test. | | **Security Appliance & VPN** | MX firewall, VLANs, NAT, content filtering, threat protection, traffic shaping and VPN. | | **Firmware** | Firmware upgrades, staged upgrades and rollbacks. | | **Licensing** | Licences, co-term and subscriptions, seat moves. | | **Administration** | Dashboard admins, SAML, login security, alert and webhook settings, SNMP and syslog, policy objects, group policies and templates. | | **Systems Manager** | Managed devices, profiles, apps and device commands. | | **Cameras, Sensors & Other** | Cameras, sensors, cellular and campus gateways, wireless controllers, Insight and Spaces. | ### Changes that always ask a technician Whatever the profile, a technician approves: deleting, combining, splitting or unbinding a network; removing a device from a network or releasing it from the inventory; wiping or unenrolling a Systems Manager device; every change to dashboard admins, SAML, SAML roles, login security and Systems Manager admin roles; and every change to Meraki Authentication users (802.1X, splash and client VPN accounts). ### What Neo never sends Neo refuses: deleting an organization, turning off an organization's API access, action batches, creating or revoking API keys, vMX authentication tokens, packet captures and camera snapshots. # Overview Source: https://docs.neoagent.io/integrations/meraki/overview What the Cisco Meraki integration brings to your Neo Agent setup Cisco Meraki manages your clients' access points, switches, security appliances and cameras from one cloud dashboard. Connect Meraki to Neo once, at the MSP level, with one Meraki Dashboard API key. The key acts as the dashboard admin who generated it, in every Meraki organization that admin can see. ## What Neo can do with Cisco Meraki * **Find the customer and the device.** Match the ticket's company to a Meraki organization or network, and find a device by serial, MAC or name. * **Answer "is it really down".** Read device availability and when it changed, MX uplink status, WAN loss and latency, and VPN tunnel state. * **Investigate.** Read network events, assurance alerts, the configuration change log, switch port status and LLDP/CDP neighbours, Wi-Fi connection and failure stats, and a user's client. * **Run live diagnostics.** Ping from a device, read its ARP or MAC table, check switch port status and PoE power. * **Check licences and firmware.** Read licence expiry, co-term state and scheduled firmware upgrades. * **Act, with the approvals you choose.** Reboot a device, cycle a switch port, run a cable test, block a client, or change an SSID, VLAN or firewall rule. * **Document the network.** Write the customer's organizations, networks and devices, with models, serials, firmware, uplinks, VLANs and SSIDs, into the ticket, IT Glue or Hudu. Neo removes Wi-Fi passwords and VPN and SNMP secrets from every Meraki answer. ## Your Meraki organizations and networks are mapped to clients Neo matches your Meraki organizations and networks to companies in your PSA and keeps the mapping on the Cisco Meraki card's **Organization Mapping** tab. It refreshes the mapping when you save the API key, and again on each nightly PSA sync. Neo matches each organization first. For an organization that matches no client, such as a service-tier organization, Neo matches each of its networks instead. Networks named like "Acme - HQ" and "Acme - Branch" both map to Acme. An organization with only one network shows as that network. Once one of an organization's networks is mapped, the organization itself no longer shows, because it holds several clients. Each name is matched exactly, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the rest. **A name match, or one you confirm, is handed straight to your agents**, so they start from the client's organization and network ids without looking them up. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Neo sees only the organizations the API key's admin can access. An organization whose networks Meraki does not let Neo list (for example, with API access turned off) does not show. Anything else Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Cisco Meraki" icon="plug" href="/integrations/meraki/connecting-to-neo"> Generate an API key in the Meraki dashboard and save it in Neo. </Card> # Connecting Mimecast to Neo Source: https://docs.neoagent.io/integrations/mimecast/connecting-to-neo Create a Mimecast API 2.0 credential and save it in Neo You connect Mimecast once at the MSP level, with a Client ID and a Client Secret from Mimecast API 2.0. ## 1. Create the credential in Mimecast <Tabs> <Tab title="Every client (partner credential)"> <Steps> <Step title="Open the Tenant API Gateway"> Sign in to your own Mimecast account as a Super Administrator or Full Administrator and open **Multi Account Control** > **Tenant API Gateway**. </Step> <Step title="Create the credential"> Click **Create API credential**, name it **Neo Agent**, and create it. </Step> <Step title="Copy the Client ID and Client Secret"> Copy both values. Copy the Client Secret before you leave the page. </Step> </Steps> </Tab> <Tab title="One client"> <Steps> <Step title="Open the Integrations Hub"> Sign in to the client's Mimecast account as an administrator and open **Integrations** > **Integrations Hub**. On the **Mimecast API 2.0** tile, click **Configure New**. </Step> <Step title="Pick the products and role"> Name the application **Neo Agent**. Under **Products**, select every product Neo should reach. Pick an **Application Role** that allows those products: see [What the credential needs](#what-the-credential-needs). </Step> <Step title="Copy the Client ID and Client Secret"> Finish the wizard and copy both values. Copy the Client Secret before you leave the page. </Step> </Steps> </Tab> </Tabs> ## What the credential needs A partner credential acts with your partner administrator rights in each client's account. A credential for one client acts with its application role, which needs these permissions: | For | Role permissions | | - | - | | Finding and judging email (read only) | Gateway: Tracking Read; Monitoring: URL Protection, Attachment Protection and Impersonation Protection Read; Account: Dashboard Read; Services: Threat Remediation Read; Security Events and Data Retrieval: Threat and Security Statistics Read | | Releasing or rejecting held email | Account: Monitoring: Held Edit | | Blocking or permitting senders | Gateway: Managed Senders Edit | | Blocking or permitting URLs | Services: URL Protection Edit | | Changing policies | Gateway: Policies Edit | | Removing an email from every mailbox | Services: Threat Remediation Edit | When the role lacks a permission, Mimecast refuses the call and the agent reports what Mimecast refused. Each endpoint's page in Mimecast's API documentation names the permission it needs. <Warning> Do not delete or regenerate the credential in Mimecast after you connect it. Neo loses access until you save the new values here. </Warning> ## 2. Add the credential in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Mimecast**](https://dashboard.neoagent.io/integrations?open=mimecast), under Security. </Step> <Step title="Save the credential"> Paste the Client ID and the Client Secret and click **Save settings**. Neo checks them against Mimecast before saving, so a wrong value is rejected straight away. </Step> </Steps> ## 3. Turn Mimecast on per agent <Steps> <Step title="Open the agent's integrations"> Open the agent in the Neo Dashboard and go to its **Integrations** tab. </Step> <Step title="Pick an access profile"> Under **Mimecast**, pick an access profile, or set each permission group by hand. | Profile | What it does | | - | - | | **Read Only** | Finds and judges email, reads the held queue and policies; changes nothing | | **Helpdesk** | Also rejects held email and blocks senders and URLs, each with technician approval | | **IT Admin** | Rejects, blocks and manages users, groups and DMARC Analyzer on its own; policy and account changes ask a technician | | **Full Automation** | Every supported write without approval, except releases, permits, policy changes, remediations and sending email | The groups are Messages & Tracking, Threat Intelligence, Held Messages, Sender & URL Lists, Policies, Remediation, Users & Groups, Account & Domains, DMARC Analyzer, and Awareness & Human Risk. See [Mimecast API](/agents/tools/security/mimecast-api). </Step> <Step title="Tell the agent what to do"> Add an instruction, for example: "When a ticket reports a suspected phishing email, find it in Mimecast, judge whether it is malicious from Mimecast's results, and write the evidence and your verdict in an internal note." </Step> </Steps> # Overview Source: https://docs.neoagent.io/integrations/mimecast/overview What the Mimecast integration brings to your Neo Agent setup Mimecast filters your clients' email: it holds suspicious messages, rewrites links and scans attachments. Connect Mimecast to Neo once, at the MSP level, with an API 2.0 credential. A partner credential from your own Mimecast account reaches every client you manage in Mimecast. A credential created inside one client's Mimecast account reaches that client only. ## What Neo can do with Mimecast * Find a reported phishing email and judge it from Mimecast's link, attachment and impersonation results, then write the evidence and its verdict on the ticket * Find an email Mimecast held and the reason, then release or reject it * Block a sender or a malicious link, and permit a wanted one * Remove a malicious email from every mailbox it reached * Read and change policies, users and groups, domains and DMARC Analyzer settings Releases, permits, policy changes, remediations and sending email always ask a technician. See [Mimecast API](/agents/tools/security/mimecast-api) for the permission groups and access profiles. ## Your Mimecast accounts are mapped to clients Neo matches each Mimecast customer account to a client in your PSA and keeps the mapping on the Mimecast card's **Organization Mapping** tab, refreshed on each PSA metadata sync. With the mapping, an agent works in the right client's Mimecast account by its account code. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Then come the account's own mail domains in Mimecast, against the website on a PSA company. Neo skips a free-mail domain, an `onmicrosoft.com` domain and a domain that two accounts share. Last comes an AI match for the long tail. A name match, or one you confirm, is handed straight to your agents. A domain match or an AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right client by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Mimecast" icon="plug" href="/integrations/mimecast/connecting-to-neo"> Create an API 2.0 credential in Mimecast and save it in Neo. </Card> # Connecting myITprocess to Neo Source: https://docs.neoagent.io/integrations/myitprocess/connecting-to-neo Create a myITprocess API key and save it in Neo You connect myITprocess once at the MSP level. One API key covers your whole myITprocess account. ## 1. Create the API key <Steps> <Step title="Open the API keys page"> Sign in to myITprocess as an administrator, click your name in the upper-right corner, choose **Account Settings** and open the **API Keys** tab. </Step> <Step title="Copy a key"> Click **Add API key**, enter a name such as Neo, click **Generate** and copy the key. myITprocess shows the key only on this page. </Step> </Steps> <Warning> Do not delete the key in myITprocess after you connect it. Neo loses access until you save a new key here. </Warning> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the myITprocess card, under Customer Success. </Step> <Step title="Save the key"> Paste the API key and click **Save**. Neo checks it against myITprocess before saving, so a wrong key is rejected straight away. </Step> </Steps> <Note> myITprocess allows 50 API requests a minute for your account. Neo keeps its own calls under that, and leaves room for your other myITprocess integrations. </Note> ## 3. Turn myITprocess on per agent Open the agent, go to the Integrations section, and configure the myITprocess block. The **Read Only** profile turns on every area. To leave an area out, set it to Disabled: | Area | Access levels you can pick | Notes | | - | - | - | | **Clients and Reviews** | Disabled, Read Only | Clients and alignment scores, reviews, the review questions and their answers, categories up for review, and your myITprocess users. | | **Roadmap and Meetings** | Disabled, Read Only | Recommendations with budgets, initiatives and meetings. Turn it off on an agent that writes to your clients and must not see budget figures. | See [myITprocess API](/agents/tools/sales/myitprocess-api) for what the agent can read. # myITprocess Source: https://docs.neoagent.io/integrations/myitprocess/overview Let Neo agents read your myITprocess reviews, findings, roadmap and QBR meetings myITprocess is Kaseya's vCIO platform: client reviews, alignment scores, the roadmap of recommendations and the QBR meetings you hold with each client. Connect it, and Neo agents can read it while they prepare a QBR or answer a question about a client. Neo reads myITprocess only, so it cannot answer a review question, change a recommendation or book a meeting in myITprocess. When you ask Neo to answer review questions, it proposes each answer with its evidence, and you enter it in myITprocess. ## What Neo can do with myITprocess * Prepare a QBR brief: the client's alignment score, its open reviews, the findings, its roadmap by status with budgets, and the next meeting's agenda * List the clients with categories up for review, and who owns each review * Propose an answer, with its evidence, to each review question you send to your PSA as a ticket * On Autotask, match recommendations to their opportunities and Kaseya Quote Manager quotes, create a missing opportunity, and name the review questions behind it on the opportunity. Neo says how it matched each one and which it could not check * On another PSA, compare a client's recommendations with the opportunities in your PSA, by title and amount ## Answer review questions from PSA tickets Neo reads a review's open questions from the tickets myITprocess opens in your PSA. myITprocess opens a ticket for a question in the queue you chose in its PSA settings, and the ticket's title is the question. <Steps> <Step title="Send a question to your PSA"> In myITprocess, open the review under **Alignment**, click the ticket icon on a question and save the ticket. </Step> <Step title="Let an agent answer it"> An agent that runs on new tickets in that queue reads the systems connected to it for the client, such as your RMM, Microsoft 365, IT Glue and PSA, and writes the proposed answer (Yes, No, N/A or Cannot tell) with its technical analysis and evidence as an internal note. An agent without permission to add internal ticket notes gives the answer in its reply instead. </Step> <Step title="Enter the answer"> The technician chooses the answer in myITprocess and pastes the technical analysis. </Step> </Steps> Ask [Neo Support](/chat-agents/neo-support-agent) to set up the agent, and name the queue myITprocess sends its tickets to. ## Recommendations, Autotask opportunities and quotes myITprocess links a recommendation to its Autotask opportunity inside its own app. Neo finds that opportunity in Autotask: an opportunity myITprocess creates takes the recommendation's name as its title, and an opportunity another agent created can name the recommendation's devices. Neo says how it matched each one. With [Kaseya Quote Manager](/integrations/kaseya-quote-manager/overview) connected, Neo then reads the opportunities' KQM quotes. Each answer has a fixed number of calls, so on a long roadmap Neo names the devices and quotes it did not check. When you ask and name the opportunity's owner, and the agent can write Autotask opportunities, Neo creates the missing opportunity with the recommendation's exact name. Link it in myITprocess: open the recommendation on the Strategic Roadmap and choose the opportunity under **Search or Create an Opportunity** in its Autotask section. See [myITprocess API](/agents/tools/sales/myitprocess-api) for the permission groups. ## Your clients are mapped to companies Neo matches your myITprocess clients to the companies in your PSA and keeps the mapping on the myITprocess card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Matching uses the client name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **A name match, or one you confirm, is handed straight to your agents.** An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect myITprocess" icon="plug" href="/integrations/myitprocess/connecting-to-neo"> Create an API key and save it in Neo. </Card> # Connecting TP-Link Omada to Neo Source: https://docs.neoagent.io/integrations/omada/connecting-to-neo Save an Omada Open API application in Neo, for a Cloud-Based Controller or for a Software or hardware controller you run You connect Omada once at the MSP level. How depends on where your controller runs: | Your controller | Connection to pick in Neo | What you create | | - | - | - | | An Omada Cloud-Based Controller (Omada Central) | **Omada Cloud-Based Controller** | An Open API application in client mode, on the controller | | A Software Controller (Windows or Linux), or an OC200, OC220, OC300 or OC400 hardware controller, at version 6.2.0 or later | **Software or hardware controller, through Omada cloud access** | An account Open API application, in the Omada cloud portal | Neo never connects to a controller's own address. It reaches a controller you run through TP-Link's cloud, so that controller needs Cloud Access turned on. A controller older than 6.2.0 cannot be connected until you update it. ## 1. Create the Open API application ### On a Cloud-Based Controller <Steps> <Step title="Pick the view"> Sign in to your Omada Cloud-Based Controller as an administrator. To reach all your Omada customers, stay in the **MSP view**. To reach one organization's sites, open that organization's **Global view**. </Step> <Step title="Create the application"> Open **Settings** > **Platform Integration** > **Open API** and add an application in **Client** mode. Give it a role that can manage the customers and sites Neo should reach. </Step> <Step title="Copy the values"> Click **View** on the application and copy the **Interface Access Address**, the **Omada ID** (in the MSP view it is your MSP ID), the **Client ID** and the **Client Secret**. </Step> </Steps> ### On a controller you run <Steps> <Step title="Turn on Cloud Access"> On the Software Controller or hardware controller, check that it runs version 6.2.0 or later, and turn on **Cloud Access** so the controller is bound to your TP-Link ID. </Step> <Step title="Create the account application"> Sign in to the Omada cloud portal with that TP-Link ID and create an account Open API application. Select the controller Neo should reach, and pick the longest validity period. </Step> <Step title="Copy the values"> Copy the application's **Client ID** and **Client Secret**. The **Omada ID** is the controller's: on the controller, open **Settings** > **Platform Integration** > **Open API** and click **View** on any application. If you use the controller's MSP view, it is your MSP ID. </Step> </Steps> <Warning> Changing the application's role, site or customer privileges, or copying or importing sites, makes Omada cancel the tokens it issued. Neo then gets a new token by itself. Deleting the application, creating a new secret, or the end of an account application's validity period stops Neo until you save the new values here. </Warning> ## 2. Add the application in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **TP-Link Omada**](https://dashboard.neoagent.io/integrations?open=omada), under Networking. </Step> <Step title="Save the application"> Pick the **Connection** and the account type (**MSP view** or **Single organization**), and paste the Omada ID, Client ID and Client Secret. For the **Open API address**, a Cloud-Based Controller takes its Interface Access Address. Cloud access takes the account address for your region: | Region | Open API address for cloud access | | - | - | | US | `https://use1-omada-northbound.tplinkcloud.com` | | Europe | `https://euw1-omada-northbound.tplinkcloud.com` | | Asia Pacific | `https://aps1-omada-northbound.tplinkcloud.com` | Click **Save settings**. Neo checks the values against Omada before saving, so a wrong value is rejected straight away. For cloud access, Neo also checks that the application reaches the controller, that the controller is online and at 6.2.0 or later, and that it lists your customers or sites. </Step> </Steps> After you save, Neo maps your Omada customers (MSP view) or sites (single organization) to the companies in your PSA. Check and correct the matches on the **Organization Mapping** tab. ## 3. Turn Omada on per agent <Steps> <Step title="Open the agent's integrations"> Open the agent in the Neo Dashboard and go to its **Integrations** tab. </Step> <Step title="Pick an access profile"> Under **TP-Link Omada**, pick an access profile, or set each permission group by hand. | Profile | What it does | | - | - | | **Read Only** | Reads Omada customers, sites, devices, clients, settings and logs; changes nothing | | **Helpdesk** | Reboots devices, reconnects or blocks clients, issues vouchers and resolves alerts on its own; other changes, and the changes Full Automation also asks about, ask a technician | | **IT Admin** | Makes every supported change on its own except the Firewall, VPN & Security and the Admins & Controller Settings groups, and the changes Full Automation also asks about, which ask a technician | | **Full Automation** | Makes every supported change without approval, except deleting an Omada customer or site, restoring a backup, forgetting a device, changing admins, roles, SSO or two-factor authentication, and setting a secret (a password, key, PIN, token or SNMP community) | </Step> </Steps> The [TP-Link Omada API](/agents/tools/networking/omada-api) page lists every permission group and the changes that always ask a technician. ## If Omada refuses Neo's requests | Neo says | What to do | | - | - | | The account application reaches no controller | Select the controller in the account application, and check that Cloud Access is on in the controller | | The application reaches several controllers and none has the Omada ID | Save one of the Omada IDs Neo lists | | The controller is offline in the Omada cloud | Check that the controller is running and that Cloud Access is on | | The controller runs a version older than 6.2.0 | Update the controller, then save the application again | | Omada refused the Open API application, with error -90112 or -90113 | The account application expired, was deleted or was disabled: create or enable one and save it here | | Omada refused the Open API application, with error -44106 or -90106 | The Client ID or Client Secret is wrong: copy both again | | Omada refused to list your customers or sites | Check the account type, that the Omada ID is the one shown with the application, and that its role can view them | ## Limits * Neo reaches a controller you run through Omada cloud access only, never at its own address. The controller needs version 6.2.0 or later with Cloud Access on. * With cloud access, Neo reaches one controller: the one whose Omada ID you save. * Neo cannot upload or download files (firmware images, backups, certificates, exports), run the batch processing calls that carry several operations in one call, transfer the controller's owner or change its cloud account binding. # Overview Source: https://docs.neoagent.io/integrations/omada/overview What the TP-Link Omada integration brings to your Neo Agent setup TP-Link Omada is the network hardware many MSPs run at their clients' sites: gateways, switches and access points managed from an Omada Cloud-Based Controller, or from a Software or hardware controller the MSP runs. When you connect Omada to Neo, your agents can see your Omada customers and sites, check which devices and clients are online, and make the changes you allow, without you opening the Omada console. <Info> You connect Omada once per MSP and every agent you enable can use it, with permissions you control per agent. Neo connects with an Open API application: on a Cloud-Based Controller, or through Omada cloud access for a Software or hardware controller at version 6.2.0 or later. Created in the MSP view, it reaches all your Omada customers; in one organization, it reaches that organization's sites. [Connecting TP-Link Omada to Neo](/integrations/omada/connecting-to-neo) has the steps. </Info> ## What Neo can do with Omada <CardGroup> <Card title="Customers & Sites" icon="building"> Find the Omada customer and site behind a ticket, and every device across them with its online state. </Card> <Card title="Devices" icon="wifi"> Read access points, switches and gateways with their uplinks, ports and WAN health; reboot a device or power-cycle a PoE port. </Card> <Card title="Clients" icon="laptop"> Find the user's device behind a complaint, with its access point, signal and connection history; reconnect or block it. </Card> <Card title="Networks, WiFi & Firewall" icon="shield-halved"> Read and change SSIDs, VLANs, DHCP reservations, firewall rules, port forwarding and VPN. </Card> </CardGroup> Hotspot vouchers, alerts and events, site templates and controller admins are also available. ## Why connect Omada * **Check the network before touching the ticket.** A "WiFi is slow" or "internet is down" ticket gets answered from the gateway's WAN state, the access point's load and the client's signal. * **Every client in one place.** With an application in the MSP view, an agent reaches every Omada customer you manage, and Neo maps each one to the matching company in your PSA. * **Changes follow your rules.** Each permission group is off, read-only or read and write per agent, with technician approval where you want it. Deleting an Omada customer or site, restoring a backup, forgetting a device, changing admins, roles, SSO or two-factor authentication, and setting a secret (a password, key, PIN, token or SNMP community) always ask a technician. ## Where to go next <Card title="Connecting TP-Link Omada to Neo" icon="plug" href="/integrations/omada/connecting-to-neo"> Create the Open API application, save it in Neo, and pick access per agent. </Card> # Connecting OpenText Secure Cloud to Neo Source: https://docs.neoagent.io/integrations/opentext/connecting-to-neo Generate a Secure Cloud API credential and refresh token, save them in Neo, and decide what each agent can do You connect OpenText Secure Cloud once at the MSP level, then turn it on per agent. You need three values from Secure Cloud: a **Client ID**, a **Client secret** and a **Refresh token**. ## 1. Generate the credentials in Secure Cloud <Steps> <Step title="Sign in as a partner administrator"> Sign in to OpenText Secure Cloud with a user that has the partner administrator role. The user you authorize with in step 3 is the user Neo acts as. </Step> <Step title="Generate a Client ID and Client secret"> Go to **Partner Services > Partner Integrations > API credentials management** and click **Generate credentials**. Copy the **Client ID** and the **Client secret**. Secure Cloud shows the secret only once. A partner can hold at most 20 credentials. </Step> <Step title="Authorize and copy the refresh token"> On the same page, choose **Actions > Authorize with credentials** in your user's row. Enter the Client ID and the Client secret, choose **Secure Cloud IDP**, and click **Continue**. Copy the **Refresh token**. </Step> </Steps> <Warning> **Enter the refresh token in Neo only.** A Secure Cloud refresh token works once. Each time Neo connects, Secure Cloud returns a new token and Neo stores it in place of the old one. If another tool or script uses the same token, one of the two stops working, and you must authorize again in Secure Cloud. </Warning> ## 2. Save the credentials in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **OpenText Secure Cloud**](https://dashboard.neoagent.io/integrations?open=opentext), under Cloud Marketplace. </Step> <Step title="Enter the values"> Paste the **Client ID**, **Client Secret** and **Refresh Token**. To let agents reach your Webroot sites and endpoints, also enter the **GSM Keycode**: the parent keycode of your Webroot Global Site Manager console, from **Settings > Subscription** in the GSM console. Leave it blank if you do not use Webroot. Click **Save**. Neo exchanges the refresh token with Secure Cloud before it saves. A wrong Client ID or secret, or a token that was already used, is refused on the spot. </Step> </Steps> ### Keep the connection alive A refresh token expires after 14 days without use. Neo maps your Secure Cloud customers to PSA companies after each PSA sync, and that run renews the token, so an account whose PSA keeps syncing stays connected. If Secure Cloud refuses the token, for example after 14 days without a sync or after someone used the same token elsewhere, Neo shows an action item in your inbox and emails your admin. Authorize again in Secure Cloud, as in **Authorize and copy the refresh token** above, and save the new refresh token in Neo. <Note> The Webroot console areas need a Secure Cloud user with access to your GSM console. If the user has none, or loses it later, Neo keeps the Secure Cloud areas connected, and the Webroot areas return a `403`. Neo checks which areas the user can reach when you save the connection, so after you give the user more access, save the connection again. </Note> ## 3. Turn OpenText Secure Cloud on per agent Each agent decides whether it uses OpenText Secure Cloud and which areas it can touch. Open the agent, go to the Integrations section, and configure the OpenText Secure Cloud block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area read only. The agent looks up customers, users, licences, charges and Webroot endpoints, and never changes anything. </Card> <Card title="Helpdesk" icon="headset"> Customers & Users and Webroot Endpoints & Groups read and write, each change with technician approval. Everything else read only. </Card> <Card title="IT Admin" icon="user-gear"> Every writable area read and write. The agent manages users, licences, orders, sites and endpoints on its own. Admins and roles, DNS Protection mappings and event subscriptions wait on a technician, as do the changes listed under Full Automation. </Card> <Card title="Full Automation" icon="bolt"> Every supported write runs with no approval. Only admin and role changes, changing an endpoint's keycode, uninstalling or deactivating Webroot on endpoints, suspending or deactivating a site, and cancelling a product wait on a technician. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Customers & Users** | Disabled, Read Only, Read and Write | Creating a user, changing a user's details, and adding or removing a user's services and licences follow your approval setting. A create or update that sets a role, or makes a user a Microsoft 365 administrator, uses **Admins & Roles** instead. | | **Subscriptions & Charges** | Disabled, Read Only | Subscriptions, seat counts, terms, charges and charge events. A seat quantity changes through the [Change License Seats](/agents/tools/m365/change-license-seats) tool, with that tool's own approval setting. | | **Orders & Trials** | Disabled, Read Only, Read and Write | Carts, orders and trials follow your approval setting. Cancelling a product always waits on a technician. | | **Webroot Sites** | Disabled, Read Only, Read and Write | Creating, editing and resuming a site, and converting a trial site, follow your approval setting. Suspending or deactivating a site always waits on a technician. | | **Webroot Endpoints & Groups** | Disabled, Read Only, Read and Write | Scans, cleanup, restart, isolation, moves, policies and groups follow your approval setting. Uninstalling or deactivating endpoints, and changing their keycode, always wait on a technician. | | **DNS Protection** | Disabled, Read Only, Read and Write | A mapping change can allow traffic that was blocked, so consider approval here. | | **Status & Reports** | Disabled, Read Only | Agent status, statistics, security awareness activity and usage reports. | | **Admins & Roles** | Disabled, Read Only, Read and Write | Webroot console and site administrators, any Secure Cloud user create or update that sets a role, and making a user a Microsoft 365 administrator (or removing it). Each changes who holds admin access, so each always waits on a technician. | | **Event Notifications** | Disabled, Read Only, Read and Write | A subscription sends events to the address it names, so consider approval here. | ## Safety controls * **You set the approvals.** Each area has its own approval setting, so an agent can assign a licence or scan an endpoint on its own, or ask a technician first. * **Admin access, keycode changes and removing protection always wait on a technician.** Every Admins & Roles change, changing an endpoint's keycode, uninstalling or deactivating Webroot on endpoints, suspending or deactivating a site, and cancelling a product need approval whatever the agent's automation level. This is not a setting you can turn off. * **Seat quantities change through one tool.** The Vendor API tool refuses a seat quantity change. The [Change License Seats](/agents/tools/m365/change-license-seats) tool makes it, with its own approval setting, and holds a lock so that two changes on one subscription cannot bill the wrong count. * **Endpoint actions name their targets.** Webroot applies a site-level command, move, policy change or deactivation with an empty endpoint list to every endpoint of the site. Neo refuses one that does not list the endpoints. * **Only documented operations.** Neo sends only the operations in the Unity API reference, each with its own method, and refuses any other call. * **Console sign-in links stay in Webroot.** Neo never reads the console links that sign their holder in to the Webroot console. * **Path safety.** Neo rejects suspicious URL paths (anything that contains `..`, for example) before they reach OpenText. ## If OpenText refuses Neo's requests | What comes back | Cause | Fix | | - | - | - | | An inbox action item to reconnect | The refresh token expired or was used elsewhere | Authorize again in Secure Cloud and save the new refresh token in Neo. | | `401` | The credentials lost access | Check that the user is still a partner administrator, then authorize again. | | `403` with `insufficient_scope` | The user cannot reach that area, such as the Webroot console | Authorize with a user that has access to that area. | | `403` | The user's role does not allow the operation | Give the user a role that allows it. | | `429` | Too many requests | Wait, then try again. | ## Disconnecting OpenText Secure Cloud <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the OpenText Secure Cloud card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault and stops using its cached access token. </Step> </Steps> Neo keeps your Organization Mapping, including any mapping you set by hand, so a later reconnect continues from the same state. Agents that use OpenText Secure Cloud stop working until you connect it again. ## Security * The Client secret and the refresh token are stored in Azure Key Vault, never in plaintext. * All traffic to OpenText goes over HTTPS, to `unityapi.webrootcloudav.com` only. * Write access is opt-in per agent. # Overview Source: https://docs.neoagent.io/integrations/opentext/overview What the OpenText Secure Cloud integration brings to your Neo Agent setup OpenText Secure Cloud, formerly AppRiver, is the marketplace where you buy Microsoft 365 licences, email security and backup for your clients. Its API is the Webroot Unity API, which also reaches your Webroot (OpenText Core) endpoint console. Connect it to Neo, and an agent can set up a new user with the right licence, buy a seat when none is free, take a licence away from a leaver and lower the seat count, and tell you what a client pays for, from the ticket. <Info> You connect OpenText Secure Cloud once per MSP, with an API credential and a refresh token from Secure Cloud. Every agent you enable can then use it, with permissions you control per agent. </Info> ## What Neo can do with OpenText Secure Cloud <CardGroup> <Card title="Customers & Users" icon="users"> Read your Secure Cloud customers and their users. Create a user, change a user's details, and add, change or remove a user's services and Microsoft 365 licences. Giving a user a role uses Admins & Roles. </Card> <Card title="Subscriptions & Charges" icon="file-invoice-dollar"> Read each customer's subscriptions with their seat counts, terms and renewal dates, and search charges and charge events. Seat counts change through the Change License Seats tool. </Card> <Card title="Orders & Trials" icon="cart-shopping"> Read Webroot licences and their order status, place an order and start a trial. Cancelling a product always waits on a technician. </Card> <Card title="Webroot Endpoints" icon="shield-virus"> Read sites, endpoints, groups, policies and threat history. Scan, clean up, restart or isolate named endpoints, move them between groups and apply a policy. Changing an endpoint's keycode always waits on a technician. </Card> <Card title="DNS Protection" icon="globe"> Read DNS Protection policies, blocked traffic and traffic summaries, and change a site's policy mappings. </Card> <Card title="Status & Reports" icon="chart-column"> Read endpoint agent status, console and site statistics, and the usage reports per console, site and customer. Read only. </Card> </CardGroup> Admins & Roles and Event Notifications are also available, for who administers each Webroot site, Secure Cloud users with a role, and event subscriptions. Every Admins & Roles change always waits on a technician. ## Seat counts An agent adds or removes Microsoft 365 seats with the [Change License Seats](/agents/tools/m365/change-license-seats) tool, after it finds the subscription with [List License Subscriptions](/agents/tools/m365/list-license-subscriptions). Enable Change License Seats on the agent; Neo adds List License Subscriptions with it. Both work for a company whose Microsoft 365 tenant is connected in Neo, with its **Microsoft tenant ID** on the **Companies** page, and that has an OpenText Secure Cloud customer, either matched under Organization Mapping or typed as the company's **Marketplace Company ID** (the Secure Cloud customer ID). <Note> For a company whose Microsoft 365 tenant is not connected in Neo, the agent cannot change seats. It gives the technician the subscription, its current quantity and the quantity needed, and the technician changes it in Secure Cloud. Users, licences and charges work without it. </Note> A Microsoft 365 NCE subscription takes a decrease only early in its term. After the subscription's last day for a decrease, Neo leaves the seat in place and the agent tells the technician. ## Your clients are mapped automatically Neo matches your Secure Cloud **customers** to the companies in your PSA. The mapping is on the OpenText Secure Cloud card's **Organization Mapping** tab. Neo refreshes it after each PSA sync and when you save the credentials. It reads active customers only. Neo tries an exact name match first, then a match after it removes a legal-form suffix (Ltd, Inc, LLC). Then it compares the customer's website with your companies' domains, and an AI match covers the names the first steps miss. **Your agents get a unique exact-name match, or a match you confirm, directly.** The agent then works in the ticket's client without searching for it. Every other match is only a suggestion: a match after a suffix is removed, a name two of your companies share, two customers matched to one company, a website match and an AI match. It stays on the Organization Mapping tab until someone confirms it. You can set a mapping by hand on the same tab, and it survives every later sync. ## Why connect OpenText Secure Cloud * **New starters get their licence from the ticket.** The agent reads which services and licences the client can assign, creates the user with the Microsoft 365 licence, and reads the user back to confirm it. * **Leavers lose their licence the same way.** The agent removes the service or the licence from the user, lowers the seat count when your instructions say to reclaim it, and reports what the user holds afterwards. * **Billing questions get an answer from the source.** The agent reads the client's subscriptions, seat counts, terms and charges, and when the seat count last changed. It can check Secure Cloud seats against Microsoft 365 and the quantity on your PSA contract. * **You decide how far agents go on their own.** Each area has its own approval setting. Only admin and role changes, changing an endpoint's keycode, uninstalling or deactivating Webroot on endpoints, suspending or deactivating a site, and cancelling a product always wait on a technician. The [OpenText Secure Cloud API tool](/agents/tools/marketplace/opentext-api#safety-controls) reference lists the controls. ## How agents reach OpenText Secure Cloud When you enable any OpenText Secure Cloud permission group on an agent, Neo adds the [Vendor API](/agents/tools/vendor-api) tool to that agent's toolbox. There is nothing to install. The agent uses the credentials you saved in the dashboard, and every call stays inside the areas and access levels you allowed. ## Where to go next <Card title="Connecting OpenText Secure Cloud to Neo" icon="plug" href="/integrations/opentext/connecting-to-neo"> Setup steps for the API credential and refresh token, per-agent access levels, and the safety controls that stay in place. </Card> # Connecting Proofpoint Essentials to Neo Source: https://docs.neoagent.io/integrations/proofpoint-essentials/connecting-to-neo Save a Proofpoint Essentials admin login in Neo, and decide what each agent can do You connect Proofpoint Essentials once at the MSP level, then turn it on per agent. <Info> The Proofpoint Essentials API signs in with an admin account's username and password. There is no API key. Neo stores both in Azure Key Vault. </Info> ## 1. Create an admin account for Neo <Steps> <Step title="Use a dedicated admin"> In the Proofpoint Essentials console, create an admin account for Neo, so you can see its changes in the audit trail and revoke it on its own. Use a **Channel Partner Admin** at your partner level to give Neo access to every client organization. An **Organization Admin** reaches only its own organization. </Step> <Step title="Make it the service account"> Proofpoint lets one admin account per organization be the **service account**, which is not billable and does not count toward licences. </Step> <Step title="Keep the login local"> Neo signs in with the username and password on every call. If the account signs in through SSO or MFA and Neo's login is refused, use a local admin account without them. </Step> </Steps> ## 2. Add the login in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the Proofpoint Essentials card, under Security. </Step> <Step title="Enter your stack"> Enter the stack your account is on. It is the first part of the address you sign in at: `us2` in `us2.proofpointessentials.com`. </Step> <Step title="Save the login"> Enter the admin username and password and click **Save**. Neo checks the login against Proofpoint before saving, so a wrong password or the wrong stack is rejected straight away. The **Organization Mapping** tab fills separately after the save, and again on each nightly PSA sync. </Step> </Steps> ## 3. Turn Proofpoint Essentials on per agent Each agent decides whether it uses Proofpoint Essentials and which areas it can touch. Open the agent, go to the Integrations section, and configure the Proofpoint Essentials block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area read only. The agent finds the organization, user and sender lists, and reports. </Card> <Card title="Helpdesk" icon="headset"> Sender Lists and Users set to read and write, and every change to either waits on a technician. Everything else read only. Fits the "please let this sender through" ticket. </Card> <Card title="IT Admin" icon="user-gear"> Every area read and write except Reporting & Billing, which has nothing to write. Sender lists, login and MFA, and filtering settings wait on a technician, because a change there can quietly weaken protection. </Card> <Card title="Full Automation" icon="bolt"> Every area read and write except Reporting & Billing, which has nothing to write. Nothing waits on a technician except the operations listed under Safety controls. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Sender Lists** | Disabled, Read Only, Read and Write | Safe and block lists per organization, user or group. | | **Users** | Disabled, Read Only, Read and Write | Granting a user impersonation rights always waits on a technician. | | **Organizations** | Disabled, Read Only, Read and Write | Deleting a client organization, and creating a console login token as another user, always wait on a technician. | | **Domains** | Disabled, Read Only, Read and Write | Deleting a domain always waits on a technician, because its mail loses filtering. | | **Organization Settings** | Disabled, Read Only, Read and Write | Filtering features, external-sender tagging, Azure AD user sync. | | **Login & SSO** | Disabled, Read Only, Read and Write | Console login, MFA and identity providers. | | **Licensing & Products** | Disabled, Read Only, Read and Write | Licence counts, package and products. | | **Reporting & Billing** | Disabled, Read Only | Mail flow statistics and billing figures. | ## Safety controls * **Quarantine is out of reach.** Proofpoint's published Essentials API document has no quarantine endpoint, and Neo sends only published operations, so no agent can release a message. The agent tells the user or technician how to release it. * **You decide what waits on a technician.** Each area has its own approval setting. Helpdesk asks on sender lists and users; IT Admin asks on sender lists, login and MFA, and filtering settings; Full Automation asks on nothing you can switch off. * **Always waits on a technician.** Deleting a client organization, deleting a domain, creating a console login token as another user, and granting a user impersonation rights. This holds whatever the agent's automation level or profile. * **Only published operations.** Neo sends only the operations Proofpoint documents. Suspicious URL paths (anything containing `..`, for example) are rejected before they reach Proofpoint. ## If Proofpoint refuses Neo's requests | What comes back | Cause | Fix | | - | - | - | | `401` | The password changed, the account was removed, or the saved stack is wrong | Re-enter the login in Neo and check the stack | | `403` | The admin cannot reach that organization, or the account type has no API access | Use a Channel Partner Admin for access to every client organization | | `404` | The domain is not registered to an organization this login can see | Check the client's domains in the Proofpoint console | | A failed **Proofpoint Essentials Company Mapping** row with a `401` or `403` | The same login problem, met by the nightly mapping | Fix the login as above. The next PSA sync rebuilds the mapping | Until a `401` or `403` is fixed, agents that use Proofpoint Essentials report the failure on the ticket they were working. The rest of Neo keeps running. ## Disconnecting Proofpoint Essentials <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the Proofpoint Essentials card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the login from Key Vault. Agents that use Proofpoint Essentials stop working until you connect it again. </Step> </Steps> Your Organization Mapping is kept, including any mapping you set by hand, so reconnecting later picks up where you left off. ## Security * The admin login lives in Azure Key Vault. It is never stored in plaintext. * All traffic to Proofpoint goes over HTTPS, to your stack's `proofpointessentials.com` host. * Write access is opt in per agent and per area. # Overview Source: https://docs.neoagent.io/integrations/proofpoint-essentials/overview What the Proofpoint Essentials integration brings to your Neo Agent setup Proofpoint Essentials filters email for your clients. The most common ticket it causes is "an email I need was held, please let it through". Connect Proofpoint Essentials to Neo and your agents can find the client's organization, add the sender to the right safe list, and manage users and domains from the ticket. Nobody opens the Proofpoint console for the allow-list part of the job. <Warning> Proofpoint's published Essentials API document has no quarantine endpoint. Neo can stop the sender's **next** email from being held, but it cannot release a message that is already in quarantine. The user releases it from their quarantine digest email, or a technician releases it in the Proofpoint Essentials console. The agent says this on the ticket. </Warning> <Info> Proofpoint Essentials uses one admin login per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with Proofpoint Essentials <CardGroup> <Card title="Sender Lists" icon="list-check"> Add a sender, a domain or an IP address to a client's safe list or block list, for the whole organization or for one user. </Card> <Card title="Users" icon="users"> Look up a user's filtering account, add a new starter or an alias, and deactivate a leaver. </Card> <Card title="Organizations" icon="building"> Find the client organization behind a ticket and list the organizations under your partner account. </Card> <Card title="Domains" icon="globe"> Check a domain's mail routing health, verify a new domain, and add DKIM signing. </Card> <Card title="Organization Settings" icon="sliders"> Filtering features, external-sender tagging and Azure AD user sync. </Card> <Card title="Login & SSO" icon="key"> How an organization's users sign in to the Proofpoint console: login, MFA and identity providers. </Card> </CardGroup> Licensing & Products and Reporting & Billing are also available: licence counts and products, and mail flow statistics for QBRs (read only). ## Your clients are mapped automatically Neo matches your Proofpoint Essentials customer organizations to the companies in your PSA and keeps the mapping on the Proofpoint Essentials card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Your own partner organization is not a client, so it is not mapped. Matching is by name first: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Then by domain: an organization's mail domains against the website on each PSA company. Last comes an AI match for the long tail. **A name match, or one you confirm, is handed straight to your agents**, so they know the client's Proofpoint organization without looking it up. A domain match or an AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it, and an agent that looks the company up can still find it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Proofpoint Essentials" icon="plug" href="/integrations/proofpoint-essentials/connecting-to-neo"> Save an admin login in Neo and choose what each agent can do. </Card> # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/psa/autotask/connecting-to-neo Configure the connection between your Autotask system and Neo Agent using API credentials Once you have [created your API user](/integrations/psa/autotask/creating-api-user) with the proper security level, connect it in the Neo dashboard. ## Required Information Gather the following from your Autotask system before you start: <ParamField type="string"> The API username for your Neo API User. You may need to click `Generate Key` in Autotask to obtain this. It always has the form `key@yourdomain` — one `@`, no spaces. The form rejects anything else, most often the Secret pasted into the wrong box. </ParamField> <ParamField type="string"> The API secret for your Neo API User. You may need to click `Generate Secret` in Autotask to obtain this. </ParamField> <Note> You no longer enter a tracking identifier. Neo Agent is a registered Autotask Integration Vendor and identifies itself with its own, so set your API user's **API Tracking Identifier** to **Integration Vendor → Neo Agent** in Autotask and leave it at that. Connections made before Neo Agent joined the Integration Hub use a Custom identifier and still show a **Your own API tracking identifier** box holding that value. Keep it as it is, or [move to the vendor identifier](/integrations/psa/autotask/creating-api-user). </Note> <Note> That is the whole list. You do not enter a Base URL or your API member's ID (Neo derives both from the API username), and you do not type Neo's regular user ID here. After you connect, Neo offers to set its non-API Autotask user and lists your users to pick from; see [Choosing Neo's Autotask user](#choosing-neos-autotask-user) below. </Note> ## Configuring the Integration <Steps> <Step title="Open Autotask in the Neo dashboard"> In the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations), open **Integrations**, switch to the Directory tab, and select Autotask. The connect page walks you through the same steps as this guide, one at a time. </Step> <Step title="Enter your credentials"> On the "Enter connection details" step, fill in the username and secret you gathered, then click **Save & run checks**. Neo runs the checks on the values you entered and stores the credentials only when the required checks pass. After a passing run, save registers the webhook and does not re-run the ticket-read probe. </Step> <Step title="Watch the verification checks"> Neo runs its verification checks one by one against the values you entered: authentication, the API resource Neo acts as, ticket read access, write access, webhook permission, rate-limit headroom, and data sync (sync starts after save). Each check reports as it completes. <Check> All required checks green means Neo can read and write tickets and can register the webhook. A failed check names the exact Autotask screen to fix. Fix the permission, then click **Save & run checks** again. </Check> </Step> <Step title="Choose Neo's Autotask user (optional)"> After a successful connect, Neo asks which Autotask user it should be recorded as and lists your users to pick from. Choose the regular user you created for Neo, or select "Neo has no Autotask user" to skip. The next section explains the trade-off. </Step> </Steps> ## Choosing Neo's Autotask user Optional. Autotask does not let an API-only user hold a ticket or a time entry, so Neo needs a separate non-API Autotask user (an ordinary one) to be recorded as when it: * is assigned a ticket (as owner or secondary resource) * logs its own time, including notifying a contact via a time entry Neo lists the Autotask users it can use, so API-only and disabled users do not appear. A user with no default service-desk role is fine to pick; Neo chooses a role per ticket when it logs time. If you skip it, Neo keeps working: it writes notes, updates tickets, and logs time against the technician who asked in chat. What it cannot do is take ownership of a ticket or log time under its own name. This user consumes an Autotask licence, which is why it is optional. Change it any time: **Integrations → Autotask → Neo's non-API Autotask user → Change**. Your agents switch to the new user within 15 minutes, so an agent that runs in those minutes can still use the previous one. ## Troubleshooting Connection Issues If a check fails or the save is rejected, check the following: <AccordionGroup> <Accordion title="Authentication Errors"> * Ensure the username and secret were generated correctly in Autotask * Check that the API user's **API Tracking Identifier** is set to **Integration Vendor → Neo Agent**. If Neo Agent does not appear in the vendor list, refresh the page in Autotask before trying anything else * If Neo reports that it found no resource for your API user, confirm that user still exists and is active in Resources/Users (HR) * If Neo reports duplicate resources for the username, remove the duplicate in Autotask and save again </Accordion> <Accordion title="Permission Errors"> * Review the security level permissions for your Neo API User * Ensure all required permissions listed in the [security level guide](/integrations/psa/autotask/creating-security-level) are assigned * Verify that webhook creation permissions are enabled * Check that resource impersonation is properly configured </Accordion> <Accordion title="Network Connectivity"> * Confirm your Autotask API zone (e.g. `https://webservices3.autotask.net/`) is accessible from external networks * Check if any firewall rules might be blocking API connections * [Whitelist Neo Agent's IP address](/integrations/ip-whitelisting) if your system restricts access by IP </Accordion> </AccordionGroup> ## What's Next? With your Autotask system connected, you can now: * **Create Workflows**: Build automated workflows that interact with your Autotask tickets and data * **Set Up Notifications**: Configure [ticket contact notifications](/integrations/psa/autotask/ticket-contact-notifications) to automatically email customers when Neo Agent updates tickets <Tip> Start with simple workflows to test the integration before implementing more complex automation scenarios. This helps identify any configuration issues early in the process. </Tip> # Setting Up Autotask API Access Source: https://docs.neoagent.io/integrations/psa/autotask/creating-api-member Complete guide to configuring security levels and API users for Neo Agent integration with Autotask To enable Neo Agent to interact with your Autotask system, you need to complete two main configuration tasks: creating a custom security level with appropriate permissions and setting up API user accounts. <Info> This setup process ensures Neo Agent has the necessary access to manage tickets, interact with PSA data, and automate workflows within your Autotask environment. </Info> ## Setup Overview The integration setup consists of two key steps: <CardGroup> <Card title="1. Create Security Level" icon="shield-check" href="/integrations/psa/autotask/creating-security-level"> Configure a custom security level with comprehensive permissions across all Autotask modules including Service Desk, CRM, Projects, and Web Services API. </Card> <Card title="2. Create API User" icon="user-gear" href="/integrations/psa/autotask/creating-api-user"> Set up the API member account with the security level and optionally create a regular user for operations that require non-API attribution. </Card> </CardGroup> ## What You'll Configure Through these guides, you'll set up: * **Custom Security Level**: A dedicated "Neo API User" role with broad permissions across all Autotask modules. This sets the *maximum* access available — the Neo Agent dashboard controls what Neo actually does. * **API Member Account**: A programmatic user that: * Uses the custom security level * Has API credentials for authentication * Can impersonate other resources for proper attribution * **Regular User (Optional)**: A standard user account that: * Can be assigned to tickets * Can create time entries * Triggers customer email notifications * Can be impersonated by the API member ## Prerequisites Before starting, ensure you have: * Administrator access to your Autotask instance * Permission to create security levels and user accounts * Access to the Resources/Users (HR) section * Ability to configure Web Services API settings ## Getting Started <Steps> <Step title="Create the Security Level"> Start by [creating the Neo API User security level](/integrations/psa/autotask/creating-security-level) with all necessary permissions across Autotask modules. This is the foundation that defines what Neo Agent can access and modify within your system. </Step> <Step title="Create the API User"> Next, [create the API member account](/integrations/psa/autotask/creating-api-user) and assign it the security level you just created. This provides Neo Agent with the actual credentials needed to authenticate and interact with your Autotask system. </Step> <Step title="Connect to Neo Agent"> Finally, [connect your Autotask instance to Neo Agent](/integrations/psa/autotask/connecting-to-neo) using the API credentials and configuration details. </Step> </Steps> <Warning> Complete both setup steps before attempting to connect to Neo Agent. Missing permissions or improper configuration can cause workflow failures and prevent Neo Agent from functioning correctly. </Warning> ## Estimated Time * **Security Level Creation**: 15-20 minutes * **API User Creation**: 10-15 minutes * **Total Setup Time**: 25-35 minutes <Tip> Have these details ready before you begin: * A dedicated email address for the API account * The name you want to use for the regular user (if creating one) * Your organization's naming conventions for API accounts </Tip> # Creating the API User Source: https://docs.neoagent.io/integrations/psa/autotask/creating-api-user Set up dedicated API and regular user accounts with proper impersonation settings for Neo Agent After creating the Neo API User security level, create the API member account Neo authenticates as, and optionally a regular user for operations that require a standard user account. ## Creating the API Member <Steps> <Step title="Navigate to Resources/Users section"> Go to Admin → Organization Settings & Users → Resources/Users (HR) to begin creating a new API member. <Frame> <img alt="Navigate to Resources/Users (HR) section in Autotask" /> </Frame> </Step> <Step title="Initiate API member creation"> Click to add a new resource and select the option to create an API-only member, not a regular user. <Frame> <img alt="Select API member option in Autotask" /> </Frame> </Step> <Step title="Configure basic API member details"> Fill in the form: * First Name: Neo * Last Name: API * Email: `psa-noreply@neoagent.io`, or a dedicated address on your own domain. Autotask mails resource notifications to this address, and `psa-noreply@neoagent.io` discards them. Never use another Neo address such as `team@neoagent.io` — that sends your ticket notifications to a Neo inbox * Security Level: the **Neo API User** security level you created earlier * Status: Active <Frame> <img alt="Configure API member basic information and security level" /> </Frame> </Step> <Step title="Set the API tracking identifier"> Under **API Tracking Identifier**, choose **Integration Vendor**, then select **Neo Agent**. There is no code to copy from this screen — Neo supplies its own, and its activity appears under that name in Autotask's API usage reports. <Frame> <img alt="Configure API tracking code for the API member" /> </Frame> <Warning> Do not choose **Custom (Internal Integration)**. Datto reserves that option for integrations an MSP builds for its own use. </Warning> <Note> Set Neo up before it joined the Integration Hub? Your API user is on a Custom identifier and keeps working. To move it, change it here first, then clear the **Your own API tracking identifier** box on Neo's Autotask integration page. </Note> </Step> <Step title="Generate API credentials"> After saving the API member, generate the API credentials: the username (Generate Key) and the secret (Generate Secret). <Frame> <img alt="Generate API username and secret credentials" /> </Frame> <Warning> Store these credentials securely. The API secret is displayed once and cannot be retrieved later. If you lose it, regenerate new credentials. </Warning> </Step> </Steps> ## Creating a Regular User Create this before you connect Autotask to Neo. After you save your credentials, Neo asks which Autotask user it should be recorded as and lists your users to pick from — choose the user you created, or decline by selecting "Neo has no Autotask user". If this user already exists, you pick it and you are done. Autotask does not allow API-only users to be assigned to tickets or create time entries. Neo needs a regular (non-API) user to take ticket ownership or log time under its own name. It consumes an Autotask licence, so it is optional: without it Neo still writes notes, updates tickets, and logs time against the technician who asked in chat. <Steps> <Step title="Create a regular user account"> Create a new regular user (not an API member) with a dedicated name like "Neo Agent". Neo records this user as the owner of ticket assignments and time entries. </Step> <Step title="Configure regular user security level"> Assign a security level to the regular user. This can be the Neo API User security level or a different one, based on your requirements. </Step> <Step title="Enable impersonation for the regular user"> Open the security level assigned to the regular user and enable impersonation: 1. Go to Web Services API → Resource Impersonation 2. Enable "Allow impersonation of resources with this security level" This allows the API member to act as the regular user while the audit trail still shows which operations were automated. <Frame> <img alt="Enable resource impersonation on the regular user's security level" /> </Frame> </Step> </Steps> ## Configuring Contact Notifications If Neo should email end users when it updates their tickets, configure Autotask's contact notifications: <Card title="Ticket Contact Notifications" icon="envelope" href="/integrations/psa/autotask/ticket-contact-notifications"> Configure which ticket events email the contact, and which templates Autotask uses. </Card> ## What's Next? Proceed to [connect Autotask to Neo Agent](/integrations/psa/autotask/connecting-to-neo). <Check> Before you proceed, verify you have: * The API username and secret * The API user's tracking identifier set to **Integration Vendor → Neo Agent** * (Optional) The regular user, with impersonation enabled on its security level </Check> # Creating the Security Level Source: https://docs.neoagent.io/integrations/psa/autotask/creating-security-level Create a dedicated Autotask security level for Neo Agent's API user Neo Agent needs a dedicated security level in Autotask. Create it before you create the API user. The video shows every step. <iframe title="Creating the Neo Agent security level in Autotask" /> ## Creating the Security Level <Steps> <Step title="Navigate to Security Levels"> Go to Admin → Organization Settings & Users → Resources/Users (HR) → Security Levels and create a new security level. <Frame> <img alt="Navigate to Security Levels in Autotask Admin" /> </Frame> <Tip> Copy the built-in API User (system) level. It already has the basic API permissions. </Tip> </Step> <Step title="Name the security level"> Name it **Neo API User**. Set the License Type to API User. <Frame> <img alt="Name the security level 'Neo API User'" /> </Frame> </Step> <Step title="Click Full Permission on every section"> Scroll down to the permission sections. Each section has a **Full Permission** link in its top right corner. Click it on every section: * Contracts * CRM * Inventory * Projects * Service Desk * Documents & Knowledge Base * Timesheets * Reports * Admin * Other <Frame> <img alt="Service Desk section expanded showing the Full Permission link" /> </Frame> <Warning> Scroll through each section to the bottom. Some sections have more checkboxes below the main permission grid. Verify that Full Permission set them all. </Warning> </Step> <Step title="Verify webhooks in the Other section"> Full Permission on the Other section sets these already. Verify them: * "Can create Webhooks": checked * "Maximum number of Webhooks": 5 <Frame> <img alt="Webhooks configuration" /> </Frame> Webhooks send ticket events to Neo in real time. </Step> <Step title="Click Full Permission on the Web Services API section"> One click enables API login, Resource Impersonation, and Contact Impersonation. <Frame> <img alt="Web Services API section" /> </Frame> <Info> Resource Impersonation lets Neo write [tickets and notes under a technician's name](/integrations/psa/autotask/overview#records-created-from-teams-carry-the-technicians-name). Each technician's own security level must also permit impersonation. Contact Impersonation lets Neo write notes under an end-user contact's name, which fires Autotask's "Customer note added" workflow events. </Info> </Step> <Step title="Save the security level"> Click Save & Close at the top of the page. </Step> </Steps> ## Keep Neo away from specific companies [Excluded companies](/integrations/psa/exclude-company-tickets) keeps a company's tickets out of Neo's sync and triggered agents. A scheduled agent or Chat Agent reads Autotask as the API user Neo signs in with, and on Autotask we know of no setting that narrows that user to some companies' tickets. The ticket permission that limits a user to some organizations is **Mine + Organizations**, and Autotask's API documentation says the Tickets entity will "respect the View, Add, and Edit permissions… EXCEPT the 'Mine + Companies' setting. 'Mine + Companies' will be treated as 'None.'" ([Tickets entity](https://www.autotask.net/help/developerhelp/Content/APIs/REST/Entities/TicketsEntity.htm)). We have found no other Autotask setting that hides one company's tickets from an API user, so on Autotask, **Excluded companies** is the control we document. ## What's Next? Proceed to [create the API user](/integrations/psa/autotask/creating-api-user) and assign this security level to it. <Check> Before you proceed, verify: * The security level is named "Neo API User" with License Type "API User" * Every section shows Full Permission, including Web Services API * Webhooks are enabled with a maximum of 5 </Check> # Read-Only Access for the Free Insights Report Source: https://docs.neoagent.io/integrations/psa/autotask/free-report-read-only-access Create a minimal, view-only Autotask API user for the free Neo Insights report — Service Desk view access only, no writes The [free Insights report](https://www.neoagent.io/free-report) reads a sample of your recent tickets, classifies them, and shows you what your service desk could automate. It needs far less access than a full Neo Agent connection: **view-only access to the Service Desk module**, nothing else. ## What Neo reads — and what it never does For the report, Neo makes only these read-only calls: * `Tickets/query` — the list of recent tickets (title, description, status, queue, dates) * `TicketNotes/query` — ticket notes, for better summaries * `Tickets/entityInformation/fields` — the field-label definitions (so status and queue IDs render as names) Neo does **not** read time entries, contacts, companies, contracts, configuration items, or billing data, and it does **not** write anything — no webhooks, no notes, no ticket changes. When your report is ready (or if the run fails), the credentials are **automatically purged** from our vault and the temporary workspace is disabled. If you later start a trial, you will set up a separate connection with its own credentials. ## Creating the read-only API user <Steps> <Step title="Create a minimal security level"> Go to **Admin → Account Settings & Users → Resources/Users (HR) → Security Levels** and copy the built-in **API User (system)** level. Open the copy and name it **"Neo Report (Read Only)"**. Then strip the copy down: * Click **No Permission** on every section **except Service Desk and Web Services API**: Contracts, CRM, Inventory, Workforce Management, Projects, Documents & Knowledge Base, Timesheets, Reports, Admin, and Other. * In **Service Desk**, set **Tickets → View** to **All**. Set every other dropdown in the grid (Add, Edit, Delete — for Tickets, Ticket Notes, Service Calls, Charges and Expenses) to **No** or **None**, and untick all the extra permission checkboxes below the grid. * In **Web Services API**, keep **Can login to Web Services API** ticked — without it the API user cannot authenticate. </Step> <Step title="Create the API user"> Go to **Admin → Account Settings & Users → Resources/Users (HR) → Resources/Users** and add a new **API user**: * **License Type**: API User (does not consume a regular license) * **Security Level**: Neo Report (Read Only) * **API Tracking Identifier**: choose **Integration Vendor**, then select **Neo Agent** Generate the **key (username)** and **secret** for the user and copy both. </Step> <Step title="Enter the details in the report form"> Back in the [report form](https://www.neoagent.io/free-report), enter: * **API user name** — the key you generated, for example `abc12defg3@yourcompany.com` * **API secret** — the secret for the user Neo checks the connection immediately and tells you on the spot if anything is missing. </Step> </Steps> <Tip> Prefer to deactivate the API user yourself afterwards? That works too — the report needs the credentials only for the few minutes the analysis runs. </Tip> # Overview Source: https://docs.neoagent.io/integrations/psa/autotask/overview Connect your Autotask PSA system to Neo Agent for automated ticket management and workflow automation ## Setup Overview Setting up the Autotask integration involves three main steps: <CardGroup> <Card title="Creating an API Member" icon="user-plus" href="/integrations/psa/autotask/creating-api-member"> Set up a dedicated API user with the proper permissions and security levels for Neo Agent to access your Autotask system. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/psa/autotask/connecting-to-neo"> Configure the connection between your Autotask system and Neo Agent using API credentials and integration settings. </Card> </CardGroup> <CardGroup> <Card title="Configuring End-User Email Notifications" icon="envelope" href="/integrations/psa/autotask/ticket-contact-notifications"> Configure how Neo Agent sends email notifications to your customers when updating tickets. </Card> </CardGroup> ## How Permissions Work Neo Agent uses **two layers of access control**: the Autotask security level sets the *maximum* API access (configured during setup), while the Neo Agent dashboard controls what Neo actually does — which areas it can read, write, or ignore, and whether actions require technician approval. ## Records Created From Teams Carry the Technician's Name When one of your technicians asks a chat agent — in the [Teams bot](/integrations/teams/internal-bot) or the dashboard chat — to log time or raise a ticket, Autotask records it under **them**, not under the Neo API user. A time entry lands on their own timesheet; a ticket, note or attachment they asked for shows their name in the ticket history. This is what makes Teams usable as a quick time-entry front end: *"log 20 minutes on T20260729.0031, replaced the switch"* from a phone, credited to the right person. Nothing to switch on. It applies as soon as the technician is mapped to their Microsoft account under [Microsoft Teams — Technician Mapping](/integrations/teams/workforce-availability) — the same mapping that makes "assign this ticket to me" work. <Info> **Automations are never attributed.** Only chat turns driven by a person are. Anything Neo does on its own — a triage agent, a scheduled sweep — is still recorded as Neo, so your audit trail always shows what was automated. </Info> ### What Autotask needs Autotask calls this **Resource Impersonation**, and it checks **two** security levels — this catches people out, because granting only the first looks like it should be enough: <Steps> <Step title="The Neo API user's security level"> **Admin → Account Settings & Users → Security Levels →** edit the level your Neo API user is on **→ Web Services API → Resource Impersonation → Full Permission**. This is part of the standard [security level setup](/integrations/psa/autotask/creating-security-level), so it's usually already done. </Step> <Step title="Each technician's own security level"> The level a **technician** sits on must also allow resources on it to be impersonated. Autotask states this on the same page: *"The security level of the resource being impersonated must be configured to allow impersonation."* This is the one that's usually missed, and it's **per security level, not per tenant** — so you can see most of your technicians attributed correctly while everyone on one particular level is not. Restricted or administrator-style levels are the common culprits. </Step> </Steps> ### If Autotask refuses The record is still created — it's just recorded under Neo rather than the technician. Neo never drops the work to preserve the attribution: * The **technician is told in the chat reply** that the record may need reassigning, so they find out immediately rather than a month later in their utilization figures. * An **inbox item and email go to your administrators** naming both security levels above, since the person in the chat usually can't change either. **Time entries are never affected.** They carry the technician through a normal Autotask field rather than impersonation, so they work regardless of these settings — and on every other PSA too. <Note> **Creating, not changing.** Autotask records who created a record and does not revise that on edit, so a status change, reassignment or close on an existing ticket stays recorded as the API user. This is an Autotask behaviour, not a Neo limitation. </Note> An unmapped technician isn't blocked either — their record is created under Neo and the reply tells them to ask an administrator to map their account. ## Troubleshooting ### Time entries stay Not Posted **Symptom:** time entries created by Neo show **Not Posted** and accumulate in **Contracts → Approve & Post → Labor**, while entries your technicians type in post immediately — even on the same ticket and contract. Opening a Neo entry and hitting **Save & Close** without changing anything posts it. **Cause:** Autotask posts a time entry — turns it into a billing item — only on an interactive save in the Autotask UI. Entries created through the Autotask API are always created *unposted*, and the API offers no way to post them; even a contract whose posting preference is *"Immediately without review"* auto-posts UI entries only. This is an Autotask platform rule that applies to every API integration, not a Neo behaviour, and nothing on the entry is wrong: Autotask derives the contract, role, and billable status for Neo's entries exactly as it does in the UI, and the work type too, unless you pick one for the agent's entries on the **Time Entries** permission group. Posting is the only difference. **Fix:** fold a bulk post into your existing billing routine — open **Approve & Post → Labor**, select all, post. It handles up to 500 items in one click, so it stays a one-minute task at any realistic volume. Two details worth getting right: * Don't filter that view by resource. With [technician attribution](#records-created-from-teams-carry-the-technicians-name), time logged from chat is recorded under the technician who asked — a filter on the Neo API user would miss those entries. * Editing each entry and re-saving it also posts it, but one at a time — the bulk sweep is the same action for the whole queue. <Note> If automatic posting of API-created labor matters to your billing flow, that capability has to come from Autotask — it's worth a feature request to Kaseya/Datto asking that API-created time entries honour the contract's *"Immediately without review"* posting preference. </Note> ### Autotask emails your admin mailbox about callout delays **Symptom:** a burst of Autotask emails — often a dozen or more within a minute — with subjects like **Autotask Callout - Delivery Delayed: Neo Tickets callback \[ALL]** and **Autotask Callout - Delivery Resumed: Neo Tickets callback \[ALL]**. They arrive at your Autotask administrator mailbox, and nothing in Autotask lets you switch them off: the **Admin → Extensions & Integrations → Webhooks** page is read-only by design, because webhooks are created and managed through the Autotask API. **Cause:** they are Autotask's own notice that its outbound queue for a webhook fell behind and then caught up. Autotask sends each notice to two recipients: the address recorded on the callout, and the callout's *owner resource*. The owner resource is the Neo API user, and the mailbox on that user is yours — so one copy always lands with you. Autotask does not allow the owner resource on a webhook to be changed after creation. The notices describe an Autotask-side delivery delay, and they name no action for you to take. Neo records the same delay on every callback it receives, so the information is already with us. **Fix:** turn them off in the dashboard: 1. Open [Integrations → Autotask](https://dashboard.neoagent.io/integrations?open=autotask). 2. Expand **Advanced settings** at the bottom of the panel — it is collapsed by default and summarised as *"Filters, callbacks and webhooks"*. 3. Under **PSA callbacks**, each callback row carries a **Delay emails** button reading `On` or `Off`. Click it to switch it. `Delay emails: Off` means Autotask no longer mails you about that callback's delivery delays. The dashboard does not offer you the toggle at the end of the row or the controls behind **Manage events** — Neo support owns those, and keeps the events your setup requires subscribed. Neo also no longer switches the notices on when it creates a webhook, so a newly connected Autotask tenant never receives them at all. Turning them on again uses the same switch, if you would rather see the notices. <Note> Switching the notices off changes nothing about how Neo receives your tickets. If callbacks genuinely stop arriving, Neo's scheduled sync still picks the changes up. The emails are Autotask telling you its own queue was slow, and they are not how a real delivery problem would reach you — tell your Neo support chat instead. </Note> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Full administrative access to your Autotask system * **API Permissions**: Ability to create API users and manage security levels * **Workflow Access**: Permissions to create and manage Autotask workflow rules # Configuring End-User Email Notifications Source: https://docs.neoagent.io/integrations/psa/autotask/ticket-contact-notifications Set up Neo Agent to send email notifications to ticket contacts when communicating with end users Neo Agent can notify ticket contacts via email when it adds notes or updates tickets. The configuration depends on how your team currently handles customer notifications in Autotask. For the cross-PSA overview of how Neo communicates with end users, see [End-User Communication](/integrations/psa/end-user-communication). This page is the Autotask-specific deep dive. <Info> **Terminology:** This guide refers to two types of workflows: * **Autotask Workflow** = Automation rules configured in Autotask (Admin → Automation → Workflow Rules) * **Neo Workflow** = Automation configured in Neo Agent Dashboard </Info> ## Find Your Scenario How do your technicians currently notify ticket contacts? <CardGroup> <Card title="Autotask Workflow on Notes" icon="a" href="/integrations/psa/autotask/ticket-contact-notifications#scenario-a:-autotask-workflow-on-notes"> "We have an Autotask Workflow that sends emails when notes are added" **No Autotask changes needed** </Card> <Card title="Autotask Workflow on Time Entries" icon="b" href="/integrations/psa/autotask/ticket-contact-notifications#scenario-b:-autotask-workflow-on-time-entries"> "We have an Autotask Workflow that sends emails when time entries are added" **No Autotask changes needed** </Card> <Card title="Quick Notification (Manual)" icon="c" href="/integrations/psa/autotask/ticket-contact-notifications#scenario-c:-quick-notification-manual"> "We use Quick Notification checkboxes manually" **Requires Autotask setup** </Card> <Card title="No Current Setup" icon="question" href="/integrations/psa/autotask/ticket-contact-notifications#choosing-your-notification-method"> "We don't currently send notifications" or "Not sure" **See recommendations** </Card> </CardGroup> *** ## Scenario A: Autotask Workflow on Notes **Your situation:** You already have an Autotask Workflow rule that sends emails when public ticket notes are added. ### Autotask Configuration None needed. Your existing Autotask Workflow will handle notifications automatically. ### Neo Configuration <Tabs> <Tab title="Neo Workflows"> Use the **"Notify Ticket Contact"** action with `Notification Mode = Ticket Note`. No UDF configuration needed—your existing Autotask Workflow handles notifications. </Tab> <Tab title="Neo Agent"> Grant the **Ticket Notes (Client-Facing)** permission group on the Autotask PSA integration — on the workflow's **Integrations** tab. This lets Neo add a client-facing ticket note that notifies the primary ticket contact. The group's settings also cover notifying additional contacts on the ticket. No UDF configuration needed—your existing Autotask Workflow handles notifications. </Tab> </Tabs> <Warning> Since your Autotask Workflow fires on ALL public notes, Neo's notes will automatically trigger customer emails. This is usually desired, but be aware that any note Neo adds will be sent to the customer. </Warning> ### Testing Add a test note via Neo and verify the customer receives an email through your existing Autotask Workflow. *** ## Scenario B: Autotask Workflow on Time Entries **Your situation:** You already have an Autotask Workflow rule that sends emails when time entries are added. <Info> **License Requirement:** Neo needs a Non-API Member license (regular Autotask user) to create time entries. This is an additional Autotask license cost. See [Creating an API Member](/integrations/psa/autotask/creating-api-member) for setup details. </Info> ### Autotask Configuration None needed. Your existing Autotask Workflow will handle notifications automatically. ### Neo Configuration <Tabs> <Tab title="Neo Workflows"> Use the **"Notify Ticket Contact"** action with `Notification Mode = Time Entry`. No UDF configuration needed—your existing Autotask Workflow handles notifications. </Tab> <Tab title="Neo Agent"> Grant the **Time Entries** permission group on the Autotask PSA integration — on the workflow's **Integrations** tab. This lets Neo log a time entry, which your existing Autotask Workflow delivers to the ticket contact. No UDF configuration needed—your existing Autotask Workflow handles notifications. </Tab> </Tabs> <Warning> Since your Autotask Workflow fires on ALL time entries, Neo's entries will automatically trigger customer emails. This is usually desired, but be aware that any time entry Neo adds will be sent to the customer. </Warning> ### Testing Add a test time entry via Neo and verify the customer receives an email through your existing Autotask Workflow. *** ## Scenario C: Quick Notification (Manual) **Your situation:** Your technicians use the **Quick Notification (Notify via "TO")** checkboxes manually when adding notes or time entries. You don't have Autotask Workflow rules for automatic notifications. <Frame> <img alt="Autotask Quick Notification Setting" /> </Frame> ### Why a Workaround Is Needed * Autotask doesn't let third-party tools (like Neo) toggle the Quick Notification checkboxes via API * If you simply create an Autotask Workflow "notify on all notes," ALL public notes would trigger emails—including tech notes that weren't meant to notify customers * Autotask Workflows can't filter by "created by this resource" to only send Neo's entries * **Solution:** A UDF (User Defined Field) acts as a flag that ONLY Neo sets, allowing selective notifications **Key Benefit:** Your technicians continue using Quick Notification manually as they always have. Only Neo's communications trigger the Autotask Workflow. ### Choose Your Method <Tabs> <Tab title="Option C1: Ticket Notes (Simpler)"> **Best for:** MSPs who don't need to track Neo's work time **How it works:** 1. Neo sets UDF "Notify Contact by Email" = `true` 2. Neo adds a customer-facing ticket note 3. Autotask Workflow detects UDF = `true` AND note added → sends email 4. Autotask Workflow resets UDF to `false` **Autotask Workflow Event:** "Note Added by Autotask Resource" <Tip> This is the simpler option—no additional Autotask license required. </Tip> </Tab> <Tab title="Option C2: Time Entries (Track Neo's Time)"> **Best for:** MSPs who want to track Neo's work time for ROI analysis or customer billing <Info> **License Requirement:** Neo needs a Non-API Member license (regular Autotask user) to create time entries. </Info> **How it works:** 1. Neo sets UDF "Notify Contact by Email" = `true` 2. Neo adds a time entry with public summary 3. Autotask Workflow detects UDF = `true` AND time entry added → sends email 4. Autotask Workflow resets UDF to `false` **Autotask Workflow Event:** "Time Entry Added by Autotask Resource" **Benefits of Time Entry mode:** * Track how much "time" Neo spends on tickets * Include Neo's work in billing reports * Better ROI visibility </Tab> </Tabs> ### Setting Up the User-Defined Field (UDF) <Steps> <Step title="Access User-Defined Fields"> 1. Open Autotask as an Administrator 2. Navigate to **Admin** → **Features & Settings** → **Application-Wide (Shared) Features** 3. Click on **User-Defined Fields** 4. Navigate to the **Tickets** tab </Step> <Step title="Create the notification UDF"> Click **New** and enter the following information: * **UDF Type:** Ticket * **Name:** `Notify Contact by Email` * **Description:** When changed to "true", Autotask will send email notification to the ticket contact * **Field Type:** List (Single Select) Under **List Options**, click **New** and create these two options: * Display Value/Stored Value: `true` * Display Value/Stored Value: `false` <Warning> Please double-check that: * The UDF is named exactly `Notify Contact by Email` (Neo Agent looks for this specific name) * The UDF values are `true` and `false` (lowercase) as these are the exact values Neo Agent will use </Warning> </Step> <Step title="Save the UDF"> Click **Save & Close** to create the User-Defined Field. <Check> Your UDF is now ready to be used by Neo Agent to trigger email notifications. </Check> </Step> </Steps> ### Creating the Autotask Workflow Rule <Steps> <Step title="Access Workflow Rules"> 1. Open Autotask as an Administrator 2. Navigate to **Admin** → **Automation** → **Workflow Rules** 3. Open the **Workflow Rules** page 4. Create a **New** workflow rule </Step> <Step title="Configure basic workflow settings"> Enter the following information: * **Workflow Rule Name:** `Neo Email Notification` * **Events** → Entity → **Ticket** * **Events** → Activity/Accessories: * **For Option C1 (Ticket Notes):** Select **Note Added by** → **Autotask Resource** * **For Option C2 (Time Entries):** Select **Time Entry Added by** → **Autotask Resource** <Frame> <img alt="Autotask Workflow Rule Event Configuration" /> </Frame> <Warning> Make sure you select the correct event based on your chosen option: * **C1:** "Note Added by Autotask Resource" * **C2:** "Time Entry Added by Autotask Resource" </Warning> </Step> <Step title="Set workflow conditions and updates"> Configure the following: * **Conditions** → UDF: Notify Contact by Email → **Equal to** → `true` * **Updates** → UDF: Notify Contact by Email **=** `false` <Tip> The "Update" part ensures that the UDF is always reset to "false" after the email is sent, preventing duplicate notifications. </Tip> </Step> <Step title="Configure email notifications"> 1. Navigate to the **Notification** tab at the top of the window 2. Select the user types you'd like to receive email notifications (we recommend selecting **Ticket Contact** and **Additional Contacts**) <Frame> <img alt="Autotask Workflow Notification Tab Selection" /> </Frame> </Step> <Step title="Set email sender"> Select the email address you'd like the email to come from. <Frame> <img alt="Autotask Workflow Notification Sender" /> </Frame> </Step> <Step title="Choose email template"> Select the email notification template you'd like to use for the emails. <Frame> <img alt="Autotask Workflow Notification Template" /> </Frame> <Tip> Make sure the template uses the appropriate variable: * **For C1 (Ticket Notes):** Use `[Ticket: Note Description]` to include Neo's note content * **For C2 (Time Entries):** Use `[Ticket Time Entry: Summary Notes]` to include Neo's message </Tip> </Step> <Step title="Save the workflow"> Click **Save & Close** to activate your Autotask Workflow rule. <Check> Your Autotask Workflow is now active and will automatically send emails when Neo triggers the UDF. </Check> </Step> </Steps> ### Neo Configuration for Scenario C After setting up Autotask, configure Neo based on whether you're using Neo Workflows or Neo Agent: <Tabs> <Tab title="Neo Workflows"> Configure the **"Notify Ticket Contact"** action in your Neo Workflow: 1. Set **Notification Mode**: * **For C1:** `Ticket Note` * **For C2:** `Time Entry` 2. Enable **"Use UDF field to trigger Autotask workflow"** 3. Set the UDF field name to `Notify Contact by Email` </Tab> <Tab title="Neo Agent"> Configure the permission group on the Autotask PSA integration — on the workflow's **Integrations** tab: **For C1 (Ticket Notes):** On the **Ticket Notes (Client-Facing)** permission group: 1. Enable **"Use UDF Field"** 2. Set **"UDF Field Name"** to `Notify Contact by Email` **For C2 (Time Entries):** On the **Time Entries** permission group: 1. Enable **"Use UDF Field for Email"** 2. Set **"UDF Field Name"** to `Notify Contact by Email` 3. Optional: set **"Work Type"** to put the entries the agent logs on one work type, for example the one your workflow rule or your billing expects for customer messages The **Ticket Notes (Client-Facing)** permission group's settings also cover notifying additional contacts on the ticket. </Tab> </Tabs> *** ## Choosing Your Notification Method If you don't have any notification setup yet, here's how to choose: | Want to track Neo's work time? | License cost acceptable? | Recommendation | | - | - | - | | No | N/A | **Ticket Notes** - Simplest setup | | Yes | Yes | **Time Entries** - Full time tracking | | Yes | No | **Ticket Notes** - Track time separately | ### Ticket Notes (Recommended for most MSPs) * Simplest setup—no additional Autotask license required * Works well for customer communication * Configure an Autotask Workflow rule to notify on public notes ### Time Entries * Requires a Non-API Member license for Neo (additional Autotask cost) * **Benefits:** * Track Neo's "time spent" for ROI analysis and internal auditing * Bill customers for work Neo has done * Time entries show up in standard billing/invoicing reports ### Do You Need the UDF Workaround? The UDF workaround (Scenario C) is only needed if you want **selective notifications**—where only Neo's messages trigger emails, not all tech notes/time entries. If you're starting fresh and don't need selective control, you can create a simple Autotask Workflow that notifies on all public notes or time entries, and skip the UDF setup entirely. *** ## Troubleshooting <AccordionGroup> <Accordion title="Customer not receiving emails"> * Verify the Autotask Workflow rule is active * Check that the UDF is being set to `true` (if using Scenario C) * Confirm the ticket has a valid contact email address * Review the Autotask Workflow notification settings </Accordion> <Accordion title="Duplicate emails being sent"> * Ensure the Autotask Workflow updates the UDF back to `false` * Check for multiple Autotask Workflow rules that might be triggering </Accordion> <Accordion title="Wrong email template being used"> * Verify the correct template is selected in your Autotask Workflow * Make sure the template includes the appropriate variables (`[Ticket: Note Description]` or `[Ticket Time Entry: Summary Notes]`) </Accordion> <Accordion title="UDF not resetting to false"> * Confirm the Autotask Workflow has an "Update" action to set UDF = `false` * Check that the Autotask Workflow conditions are correctly configured </Accordion> </AccordionGroup> # Company filters Source: https://docs.neoagent.io/integrations/psa/company-filters Control which of your PSA companies Neo tracks — keep active customers, leave out vendors, inactive companies, and other non-customer records Your PSA usually holds far more companies than the customers you actively service — vendors, prospects, inactive accounts, one-off records, and companies mirrored in from connected tools. **Company filters** let you decide which of those Neo keeps in its own company directory (the [**Companies**](https://dashboard.neoagent.io/end-companies) tab), so agents work against a clean list of real customers instead of your entire address book. By default Neo keeps **active customers** and leaves everything else out. ## Where to find it Open [**Integrations**](https://dashboard.neoagent.io/integrations), pick your PSA, expand **Advanced settings**, and find the **Company filters** section (next to PSA filters). ## How filtering works A company is kept when it clears every filter. Each filter targets one dimension, read from your PSA: | Dimension | What it matches | Example | | - | - | - | | **Status** | Whether the company is active in your PSA | `Active`, `Inactive` | | **Account type** | Your PSA's own company type | `Customer`, `Client`, `Vendor`, `Prospect`… | | **Company status** *(ConnectWise)* | Your PSA's own raw status label | `Active`, `Account Closed`, `Liquidated`, `Offboarding`… | Each filter is either **Include** (keep only companies whose value is in the list) or **Exclude** (keep only companies whose value is *not* in the list). The values you can choose come straight from your own PSA data, so ConnectWise sees your ConnectWise company types and statuses, Halo sees yours, and so on. ### Company status (ConnectWise) The **Status** dimension is a simple active/inactive flag. But ConnectWise company statuses are your own free text, and names like *Account Closed*, *Liquidated*, or *Offboarding* still count as **Active** — so they slip past an Active-only filter and clutter your directory. Add a **Company status** filter to include or exclude those by name. To hide closed accounts, add an **Exclude** filter and pick *Account Closed*, *Liquidated*, and any other statuses you don't service. The status names come straight from your ConnectWise data. This dimension is ConnectWise-only — other PSAs expose active/inactive as a single flag, which the **Status** dimension already covers. ## The default When you haven't configured anything, Neo applies a sensible default and shows it as editable rows: * **Status: Active** * **Account type: Customer** — where your PSA has a clear customer type. For ConnectWise, Neo pre-selects your client-style types (e.g. *Managed Services Client*, *Break Fix Client*) and leaves out vendors and prospects. Halo companies use numeric types with no standard "customer" label, so Halo starts with the **Status: Active** filter only — add an **Account type** filter to narrow it to your customer types. Edit or remove these rows like any other filter. ## Adding and removing companies Saving a change is **widening-first and safe**: <Steps> <Step title="Add companies immediately"> When your change brings *more* companies into scope, Neo adds them to the directory right away. </Step> <Step title="Confirm before removing"> When your change would take companies *out* of scope, Neo shows you exactly which ones (a count plus the list) and asks you to confirm. Choose **Keep them** to leave them in place for now, or **Remove** to take them out. </Step> </Steps> Removing a company takes it off the Companies tab, stops agents from resolving or acting on it, and prevents future syncs from bringing it back. It's reversible — re-add the matching filter (or manually map the company) to restore it. <Note> Company filters shape Neo's **company directory** — which companies agents see and can act on. They do not change which **tickets** Neo processes; that's controlled by the PSA filters (boards and queues) in the same Advanced settings section and each workflow's own conditions. To keep one company's tickets out of Neo, add it to **Excluded companies** ([exclude a company's tickets](/integrations/psa/exclude-company-tickets)). </Note> # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/psa/connectwise/connecting-to-neo Configure the connection between your ConnectWise system and Neo Agent using API credentials Once you have [created your API member](/integrations/psa/connectwise/creating-api-member) with the proper security role and permissions, connect it in the Neo dashboard. ## Required Information Gather the following from your ConnectWise system before you start: <ParamField type="string"> The text-based Member ID you created for the Neo API member (e.g., `neo_agent`). This is found in System → Members → API Members. </ParamField> <ParamField type="string"> The Public Key generated for your Neo API member. This acts as the username for API authentication. </ParamField> <ParamField type="string"> The Private Key generated for your Neo API member. This acts as the password for API authentication. </ParamField> <ParamField type="string"> Your ConnectWise API base URL (e.g., `https://api-na.myconnectwise.net/`). This is the URL used for API access to your ConnectWise instance. </ParamField> <ParamField type="string"> Your company name exactly as shown on the ConnectWise login screen. This must match precisely for authentication to work. </ParamField> <Frame> <img alt="Find company name on ConnectWise login screen" /> </Frame> <Note> You do not type Neo's regular member ID here. After you connect, Neo offers to set its non-API ConnectWise member and lists your members to pick from. It is optional; see [Choosing Neo's ConnectWise member](#choosing-neos-connectwise-member) below. </Note> ## Configuring the Integration <Steps> <Step title="Open ConnectWise in the Neo dashboard"> In the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations), open **Integrations**, switch to the Directory tab, and select ConnectWise. The connect page walks you through the same steps as this guide, one at a time. </Step> <Step title="Enter your credentials"> On the "Enter connection details" step, fill in the credentials you gathered: * Username (public key) * Password (private key) * PSA URL * Company Name, exactly as on the login screen * Neo's API-only Member ID <Frame> <img alt="ConnectWise connection form in the Neo Agent dashboard" /> </Frame> Click **Save & run checks**. Neo runs the checks on the values you entered and stores the credentials only when the required checks pass. After a passing run, save registers the webhook and does not re-run the ticket-read probe. </Step> <Step title="Watch the verification checks"> Neo runs its verification checks one by one against the values you entered: authentication, the identity Neo acts as, ticket read access, write access, webhook permission, and data sync (sync starts after save). Each check reports as it completes. <Check> All required checks green means Neo can read and write tickets and can register the webhook. A failed check names the exact ConnectWise screen to fix. Fix the permission, then click **Save & run checks** again. </Check> </Step> <Step title="Pick Neo's ConnectWise member (optional)"> After a successful connect, Neo asks which ConnectWise member it should be recorded as for assignments and time entries. You can skip this and set it later; the next section explains the trade-off. </Step> </Steps> ## Choosing Neo's ConnectWise member Optional. ConnectWise does not let an API-only member own a time entry, so Neo needs a separate non-API member (an ordinary one) to be recorded as when it: * is assigned a ticket * logs its own time, including notifying a contact via a time entry * replies to a customer (see [Who authors Neo's notes](#who-authors-neos-notes) below) Neo lists the ConnectWise members it can use, so the API member it signs in with and any disabled members do not appear. If you skip it, Neo keeps working: it writes notes, updates tickets, and logs time against the technician who asked in chat. What it cannot do is take ownership of a ticket or log time under its own name. This member consumes a ConnectWise licence, which is why it is optional. Change it any time: **Integrations → ConnectWise → Neo's non-API ConnectWise member → Change**. Your agents switch to the new member within 15 minutes, so an agent that runs in those minutes can still use the previous one. ## Who authors Neo's notes ConnectWise records a note against whichever member wrote it. Neo uses two: | Note | Author | | - | - | | Replies the customer reads, and the emails ConnectWise sends for them | Neo's non-API member | | Internal and resolution notes | The API member | So customers see the identity you chose, while your technicians can still tell which notes Neo wrote. To change the name your customers see, rename that member in ConnectWise — "Acme Support", for example. There is no setting in Neo to configure. <Note> If you have not chosen a non-API member, Neo writes every note under the API member. </Note> ## Troubleshooting Connection Issues If a check fails or the save is rejected, check the following: <AccordionGroup> <Accordion title="Authentication Errors"> * Verify that the API Member Identifier is correct and corresponds to an active API member * Ensure the Public and Private keys were generated correctly in ConnectWise * Check that the company name matches exactly what appears on the ConnectWise login screen * Confirm the ConnectWise PSA URL is correct and accessible </Accordion> <Accordion title="Permission Errors"> * Review the security role permissions for your Neo API member * Ensure all required permissions listed in the [API member creation guide](/integrations/psa/connectwise/creating-api-member) are assigned * Verify that both Inquire and Add/Edit levels are set correctly * Check that the "Neo" security role is properly assigned to the API member </Accordion> <Accordion title="Network Connectivity"> * Confirm your ConnectWise PSA URL is accessible from external networks * Check if any firewall rules might be blocking API connections * [Whitelist Neo Agent's IP address](/integrations/ip-whitelisting) if your system restricts access by IP * Test the URL accessibility from outside your network </Accordion> <Accordion title="Time entries fail with 'API member does not have access to the Time module'"> ConnectWise blocks API-only members from creating time entries. This is a ConnectWise restriction, not a permissions setting. Granting Time & Expense on the security role is necessary but not sufficient: the time entry must be owned by a *regular* (non-API) member. To fix it: 1. [Create a regular (non-API) member](/integrations/psa/connectwise/creating-api-member) for Neo and assign it the Neo security role. 2. Go to **Integrations → ConnectWise → Neo's non-API ConnectWise member → Change** and pick that member. Until then, Neo's other capabilities keep working and time-entry attempts log an action-required notice in your inbox instead of failing the workflow. </Accordion> </AccordionGroup> ## What's Next? With your ConnectWise system connected, you can now: * **Create Workflows**: Build automated workflows that interact with your ConnectWise tickets and data * **Set Up Pod Integration**: Consider setting up the [ConnectWise Pod](/integrations/psa/connectwise/pod) for seamless in-PSA access <Tip> Start with simple workflows to test the integration before implementing more complex automation scenarios. This helps identify any configuration issues early in the process. </Tip> # Creating an API Member Source: https://docs.neoagent.io/integrations/psa/connectwise/creating-api-member Create a dedicated security role and API member for Neo Agent in ConnectWise Neo Agent needs its own security role and API member in ConnectWise. Create the role first, set its permissions in one pass, then create the API member with it. ## Creating the Security Role and API Member <Steps> <Step title="Create the Neo security role"> Go to System → Security Roles and create a new role with Role ID `Neo`. Save it. <Frame> <img alt="Open Security Roles" /> </Frame> <Frame> <img alt="Add new role" /> </Frame> <Frame> <img alt="Save role" /> </Frame> </Step> <Step title="Set the permission levels, one module at a time"> Open each module once. In every module, including Sales and Marketing, set **Inquire Level to All** on every entry first. Then open the groups below and set **Add and Edit Level to All** on the chips listed. <AccordionGroup> <Accordion title="Service Desk"> <div> <span>Service Tickets</span> <span>Close Service Tickets</span> <span>Service Ticket - Dependencies</span> <span>Merge Tickets</span> <span>Resource Scheduling</span> <span>Knowledge Base Creator</span> <span>Ticket Templates</span> </div> Also set **Delete Level to All** on Resource Scheduling. </Accordion> <Accordion title="Companies"> <div> <span>Company Maintenance</span> <span>Configurations</span> <span>Contacts</span> <span>Manage Attachments</span> <span>Management</span> <span>Notes</span> </div> </Accordion> <Accordion title="Time & Expense"> <div> <span>Time Entry</span> <span>Time Entry Billable Option</span> </div> </Accordion> <Accordion title="Project"> <div> <span>Project Tickets</span> <span>Close Project Tickets</span> <span>Close Projects</span> <span>Project Headers</span> <span>Project Notes</span> <span>Project Ticket - Dependencies</span> <span>Project Ticket Tasks</span> </div> </Accordion> <Accordion title="Finance"> <div> <span>Agreements</span> <span>Billing View Time</span> </div> </Accordion> <Accordion title="Procurement"> <div> <span>Products</span> <span>Product Catalog</span> </div> </Accordion> <Accordion title="System"> <div> <span>My Company</span> <span>Table Setup</span> </div> </Accordion> </AccordionGroup> Sales and Marketing need no write access. Read access lets Neo look up context (companies, SLAs, agreements, configurations) and does not allow changes. <Tip> Three entries deserve a second look: * System → Member Maintenance needs Inquire = All. Neo reads your member list to resolve its own API member and to sync technicians. Without it, the connection checks fail with a 403 on the Identity check. * System → API Reports needs Inquire = All. ConnectWise treats this entry separately from the rest of the System module, and it lets Neo batch note history efficiently. * Companies → Manage Attachments is what enables ticket file attachments. Without Add = All there, attachments fail with a 403 permission error. </Tip> <Warning> Keep Add, Edit, and Delete at None on the financial and admin entries not listed above. Neo does not need to write to them: * Invoicing and Invoice Approval * Billing Rate Maintenance * Accounting Interface * Purchase Orders and Purchasing Approvals * Member Maintenance * Security Roles * Add Licenses Inquire stays All on every entry in this list. Only Add, Edit, and Delete go to None. The Neo dashboard's permission groups control what Neo actually does; the role only sets the maximum access. </Warning> </Step> <Step title="Create the API member and generate keys"> 1. Go to System → Members → API Members and create a new member. 2. Set the Security Role to `Neo`, the Member ID to something clear like `neo_agent`, and the email to `psa-noreply@neoagent.io`. 3. Open the member's API Keys tab and create a key pair with a description like "Neo-API". 4. Copy the Public Key and the Private Key now. ConnectWise does not show the private key again. <Warning> Use `psa-noreply@neoagent.io` here, never another `@neoagent.io` address such as `team@neoagent.io`. ConnectWise mails member notifications to the address on the member record. `psa-noreply@neoagent.io` discards everything it receives; any other Neo address delivers your ticket notifications, and the customer data inside them, to a Neo inbox instead of your team's. An address on your own domain works too. Neo never reads this field — it authenticates with the API keys. </Warning> <Check> Note the Member ID, the Public Key (username), and the Private Key (password). The connection step needs all three. </Check> </Step> <Step title="Create a regular member for time entries (optional, recommended)"> ConnectWise does not let API-only members create time entries. If Neo should log time, create a second, regular member: 1. Go to System → Members (the regular list, not API Members). 2. Create a member such as `neo_agent_member` and assign it the `Neo` security role. 3. Note its Member ID. This member needs no API keys. Neo authenticates with the API member's keys and only records this member as the author of time entries. After you connect, Neo asks which member to use and lists your members to pick from ([connection setup](/integrations/psa/connectwise/connecting-to-neo)). <Note> If you skip this step, everything else works. Neo only cannot write time entries, and an attempt surfaces an action-required notice in your inbox. </Note> </Step> </Steps> ## Keep Neo away from specific companies [Excluded companies](/integrations/psa/exclude-company-tickets) keeps a company's tickets out of Neo's sync and triggered agents. A scheduled agent or Chat Agent reads the PSA as the account Neo signs in with, so to keep those agents away from a company too, restrict that account. ConnectWise limits a member by its **Level** and each company's **Territory**: 1. In **System > My Company > Structure**, add a location the Neo API member is not under. 2. On each company to hide, set **Territory** to that location. 3. On the Neo API member, set **Level** and **Name** to the location that holds your other companies, not **Corporate**. ConnectWise says a member "will be able to search for companies at the specified level and the ones below it", and that a company with no territory is never restricted. Its documentation does not say whether the API applies this limit, so after the change, check in a chat with Neo that it cannot open one of that company's tickets. If the company's tickets sit on boards of their own, **Restrict Board Access** on the API member hides those boards' tickets instead. ## What's Next? Proceed to [connect ConnectWise to Neo Agent](/integrations/psa/connectwise/connecting-to-neo). <Check> Before you proceed, verify you have: * The API Member ID * The Public Key (username) and Private Key (password) * Your ConnectWise PSA URL * Your exact company name from the ConnectWise login screen * (Optional) The regular member's ID, if Neo should log time </Check> # Read-Only Access for the Free Insights Report Source: https://docs.neoagent.io/integrations/psa/connectwise/free-report-read-only-access Create a minimal, inquire-only ConnectWise API member for the free Neo Insights report — one permission, no write access The [free Insights report](https://www.neoagent.io/free-report) reads a sample of your recent tickets, classifies them, and shows you what your service desk could automate. It needs far less access than a full Neo Agent connection: **one inquire-only permission**, nothing else. ## What Neo reads — and what it never does For the report, Neo makes only these read-only calls: * `service/tickets` — the list of recent tickets (subject, status, board, dates) * `service/tickets/{id}/notes` — the ticket description (in ConnectWise, the description is the first note) Neo does **not** read contacts, companies, time entries, configurations, agreements, or finance data, and it does **not** write anything — no webhooks, no notes, no ticket changes. When your report is ready (or if the run fails), the credentials are **automatically purged** from our vault and the temporary workspace is disabled. If you later start a trial, you will set up a separate connection with its own credentials. ## Creating the read-only API member <Steps> <Step title="Create a security role with one permission"> Go to **System → Security Roles** and create a new role named **"Neo Report (Read Only)"**. Expand the **Service Desk** section and set **Service Tickets → Inquire Level** to **All**. Leave every other permission in every section at **None**. </Step> <Step title="Create an API member"> Go to **System → Members → API Members** and create a new API member (API members do not consume a license). Assign it the **Neo Report (Read Only)** role. </Step> <Step title="Create an API key pair"> Open the new member, go to the **API Keys** tab, and create a key pair. <Warning> The private key is shown only once — copy both keys before closing the screen. </Warning> </Step> <Step title="Enter the details in the report form"> Back in the [report form](https://www.neoagent.io/free-report), enter: * **ConnectWise site** — your API host, for example `api-na.myconnectwise.net` * **Company ID** — the company ID you type on the ConnectWise login screen * **Public / private API key** — the pair you just created Neo checks the connection immediately and tells you on the spot if anything is missing. </Step> </Steps> <Tip> Prefer to delete the member yourself afterwards? That works too — the report needs the credentials only for the few minutes the analysis runs. </Tip> # Overview Source: https://docs.neoagent.io/integrations/psa/connectwise/overview Connect your ConnectWise PSA system to Neo Agent for automated ticket management and workflow automation ## Setup Overview Setting up the ConnectWise integration involves two main steps: <CardGroup> <Card title="Creating an API Member" icon="user-plus" href="/integrations/psa/connectwise/creating-api-member"> Set up a dedicated security role and API member with the proper permissions for Neo Agent to access your ConnectWise system. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/psa/connectwise/connecting-to-neo"> Configure the connection between your ConnectWise system and Neo Agent using API credentials and integration settings. </Card> </CardGroup> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Full administrative access to your ConnectWise system * **Security Role Management**: Ability to create security roles and manage permissions * **API Member Creation**: Permissions to create API members and generate API keys * **Company Information**: Your exact company name as shown on the ConnectWise login screen * **System Access**: Access to System → Security Roles and System → Members sections ## Getting a 403 permission error ConnectWise returns `403 code=Security` when the Neo security role is missing an Inquire or write level. Open [Creating an API Member](/integrations/psa/connectwise/creating-api-member) and check the three entries under "Three entries deserve a second look", then run the connection checks again. The Identity check fails this way when System → Member Maintenance is not set to Inquire = All, even though the API member exists. ## Agents on project tickets An agent can run on ConnectWise project tickets (the tasks inside a project) as well as service tickets. In the agent builder, open **Triggers & Filters** and set **What to process** to **Project Tickets**, or ask your [Neo Support Agent](/chat-agents/neo-support-agent) to build the agent. The choice is fixed once the agent is created, so an existing ticket agent cannot move to project tickets; create a new agent instead. A project-ticket agent must be a triggered agent. Workflows and scheduled agents cannot run on project tickets. * **Triggers:** Ticket created, Ticket updated, Note added, Technician added a note, Another workflow finished and Manual only. Another project-ticket agent can also start the run; a service-ticket agent or workflow cannot. Customer replied, Technician replied and Time entry created are not available. Moving a project ticket to another phase does not start an agent: in our tests, ConnectWise sent Neo no ticket event for a phase move. * **Filters:** the project ticket's own fields, such as project, phase, board and status. Calculated fields, team and SLA are not available. The agent builder does not show custom-field filters for project tickets; ask your Neo Support Agent to add one. * **Tools:** the agent reads and changes the project ticket with the [ConnectWise PSA API](/agents/tools/psa/psa-api) tool, so give the API member the Project Tickets permissions under **Project**, with edit access when the agent changes a status or another field (see [Creating an API Member](/integrations/psa/connectwise/creating-api-member)). **Add Internal Ticket Note** and the internal Teams and approval tools work as on a service ticket. These tools use service-ticket endpoints, so a project-ticket agent does not get them: Update Ticket Fields, Add Time Entry, Add Client-Facing Ticket Note, Send Email to end user, Send SMS, Send Message to Ticket's Additional Contact, Merge Tickets, Attach File to Ticket, Create TimeZest Scheduling Link, Get Technician Context, Verify Dispatch Decision and Load Intent. To change a status or another field, the agent uses the ConnectWise PSA API tool. ## Replies from unregistered contacts This page has no setting for replies from senders who are not ConnectWise contacts. That switch is on the trigger: open an agent's **Triggers & Filters** tab with a **Customer replied** condition, and click **Configure** below the conditions, or ask the Neo Support Agent to change it. It applies to all of your ConnectWise agents and workflows. See [What counts as a customer reply on ConnectWise](/core/triggers-and-schedules/triggered-workflows). ## Additional Features <Card title="ConnectWise Pod Integration" icon="window" href="/integrations/psa/connectwise/pod"> Embed Neo Agent directly in ConnectWise as a Manage Hosted API pod for seamless access within your PSA interface. </Card> # ConnectWise Pod Source: https://docs.neoagent.io/integrations/psa/connectwise/pod Embed Neo in ConnectWise as a Manage Hosted API pod <Info> Currently available for ConnectWise PSA. Contact us to request support for other PSAs. </Info> ## Add Neo as a ConnectWise Pod 1. In ConnectWise, go to System → Setup Tables <Frame> <img alt="Open Setup Tables" /> </Frame> 2. In category General, open Manage Hosted API 3. Click the + button to create a new pod <Frame> <img alt="Create new pod" /> </Frame> 4. Configure the pod fields as shown <Frame> <img alt="Configure pod" /> </Frame> 5. Set Origin and URL to `https://pod.neoagent.io` 6. Optionally set Description and Pod Height (recommend 400px) <Frame> <img alt="Pod added" /> </Frame> # Configuring End-User Email Notifications Source: https://docs.neoagent.io/integrations/psa/connectwise/ticket-contact-notifications Set up ConnectWise to email ticket contacts when Neo Agent replies, and control which name and address the email is sent from Neo Agent does not send email to your end users. It writes a **client-facing note** or a **time entry** to ConnectWise, and ConnectWise decides whether that becomes an email and what the From line says. Everything on this page is ConnectWise configuration. For the cross-PSA overview of how Neo communicates with end users, see [End-User Communication](/integrations/psa/end-user-communication). This page is the ConnectWise-specific deep dive. <Info> **Terminology:** This guide refers to two types of workflows: * **ConnectWise Workflow Rule** = automation configured in ConnectWise (System → Setup Tables → Workflow) * **Neo Workflow** = automation configured in the Neo Agent Dashboard </Info> ## How a Neo reply becomes an email When Neo adds a client-facing note, it posts to `/service/tickets/{id}/notes` with the note text, `detailDescriptionFlag = true` and `processNotifications = true`. That puts the text in the customer-visible **Discussion** tab and asks ConnectWise to notify the contact. ConnectWise then builds the email. Neo sends no From address, no display name and no reply-to. Three ConnectWise settings decide what your end user sees, and they are read in this order: <Steps> <Step title="The service board supplies the address"> **Setup → Setup Tables → Service Board → \[your board] → Board tab → Automatic Email Options** * **Send Email From** (`notifyEmailFrom`) — the address the email is sent from. * **Display Name** (`notifyEmailFromName`) — the name shown beside that address. * **Send to Contact** (`sendToContactFlag`) — the board default for the ticket's own Automatic Email **Contact** flag (`automaticEmailContactFlag`), which is what ConnectWise reads when the note is posted. Neo does not depend on that default. Before it posts a client-facing note it enables `automaticEmailContactFlag` on the ticket, then restores the original value, so the contact is emailed even on a board where the default is off. </Step> <Step title="The board decides whose name to show"> On the same tab, **Use Member as Display Name** (`useMemberDisplayNameFlag`) replaces the board's Display Name with the name of the ConnectWise **member** who authored the note. The address does not change, so replies still reach the board. Neo authors client-facing notes as **Neo’s non-API ConnectWise member**, set on the ConnectWise panel of the Neo Dashboard's [**Integrations**](https://dashboard.neoagent.io/integrations?open=connectwise) page. That field is optional: leave it empty and ConnectWise attributes the note to the API member Neo signs in as. With **Use Member as Display Name** ticked, whichever of the two authored the note is the name your end users read. Rename that member in ConnectWise to change it. </Step> <Step title="The per-status email template can override both"> **Setup → Setup Tables → Service Board → \[your board] → Email Templates** Each ticket status on the board can have its own template, and the template carries its own sender. Two settings on it matter: * **Send to Contact** (`externalContactNotifications`) — whether this status emails the customer at all. * **Use Sender** (`useSenderFlag`) — when ticked, ConnectWise **discards the sender stored on the template** and resolves the sending identity instead. </Step> </Steps> <Warning> **Use Sender is the setting that breaks white-label branding.** When it is ticked and the sending identity has no usable name, ConnectWise falls back to your system-wide default From address — **System → Setup Tables → My Company → Default From Address** (`defaultFromAddress`) — and puts that **address** in the display-name slot. Your end user then sees a correct address with your MSP's address as the label, for example `"support@yourmsp.com" <servicedesk@endclient.com>`. Untick **Use Sender** and the template's own stored sender applies. </Warning> ## Multi-brand and white-label setups If you run separate boards for end clients who have their own support domain, each board needs its own configuration. A board-level change is the right level, because it does not affect the other boards. <Steps> <Step title="Set the board's sender"> Give each end client's board its own **Send Email From** and **Display Name** — for example `servicedesk@endclient.com` and `End Client Support`. </Step> <Step title="Untick Use Member as Display Name"> Leave **Use Member as Display Name** unticked on white-label boards. With it ticked, your own member names reach the end client's inbox. </Step> <Step title="Audit every status template on the board"> Open each template and check the two settings together. Any template where **Send to Contact** is ticked **and** **Use Sender** is ticked resolves the sending identity at send time, so it can fall back to your default From address as the label. Send a test email from that status and read the resolved From line. If the label is an address, untick **Use Sender** and confirm the stored sender name and address are the end client's. Pay particular attention to the status your email connector assigns to new tickets — often `New (Email)`. That template sends the ticket confirmation your end users see first. </Step> <Step title="Check for stale senders"> Templates keep whatever sender was stored when they were created. After a rebrand or an acquisition, templates commonly still carry the retired brand. Read the stored name and address on every template that emails a customer. </Step> </Steps> ## Auto-response on ticket creation The **email connector** and the **board email templates** are two separate senders, and MSPs often confuse them. * **Email connector auto-response** — System → Setup Tables → E-mail Connector → \[your connector]. `Never Respond` and `No Response` suppress it. When both are set, the connector sends nothing. * **Board status template** — fires on the status the connector assigns to the new ticket (`Status Override` on the connector). This still sends even when the connector's auto-response is off. If your end users receive a confirmation you cannot find, check the board template for the connector's **Status Override** status before you look at the connector. ## Neo configuration <Tabs> <Tab title="Neo Workflows"> Use the **Notify Ticket Contact** action with `Notification Mode = Ticket Note`. Neo writes the client-facing note and ConnectWise emails the contact using the settings above. `Notification Mode = Time Entry` logs a time entry instead. Neo sets `emailContactFlag` on that entry itself, so ConnectWise emails the contact without an MSP rule for time entries. </Tab> <Tab title="Neo Agent"> Grant the **Ticket Notes (Client-Facing)** permission group on the ConnectWise PSA integration — on the workflow's **Integrations** tab. This lets Neo add a customer-visible note. The group's settings control an optional send delay and whether additional contacts on the ticket are notified. Grant the **Time Entries** permission group if you also want Neo to log time. ConnectWise sets a new time entry's email flags from the ticket's Automatic Email flags (`automaticEmailContactFlag`, `automaticEmailResourceFlag`, `automaticEmailCcFlag`) when those are on. When Neo logs a time entry with an email flag off, it turns the matching ticket flag off for that one entry, then turns it back on. If either change fails, the agent's result says so: it names the email flag ConnectWise stored on the entry, or the ticket flag you must turn back on. The **Ticket Notes (Internal)** permission group is internal-only. Notes added through it are never sent to the end user. </Tab> </Tabs> <Info> **Neo cannot override the sender per workflow.** The note Neo posts carries only the text, the visibility flags, and the authoring member or contact. Every part of the From line comes from ConnectWise. To change what an end client sees, change that client's board and its templates. </Info> ## Testing <Steps> <Step title="Send a test reply"> Run a Neo Workflow or agent that adds a client-facing note on a test ticket on the board you configured. </Step> <Step title="Read the received email, not the ticket"> Open the email in the recipient's mailbox. The ConnectWise ticket does not show the From line that was sent. </Step> <Step title="Check the label and the address separately"> A correct address with the wrong label points at **Use Sender** on the status template. A correct label on the wrong address points at the board's **Send Email From**. </Step> <Step title="Repeat per status"> Templates are per status, so a reply that looks right on one status can still be wrong on another. Test at least the connector's new-ticket status and your resolved status. </Step> </Steps> ## Troubleshooting <AccordionGroup> <Accordion title="The address is correct but the display name shows an email address"> A status email template has **Use Sender** ticked. ConnectWise discarded the sender stored on the template, could not resolve a name from the sending identity, and fell back to **My Company → Default From Address**. Untick **Use Sender** on that template. Changing the Default From Address is not the fix. It holds an address, and it is shared by every end client on the system. </Accordion> <Accordion title="End users see one of our technicians' names, or an internal account name"> The board has **Use Member as Display Name** ticked, so the display name follows the ConnectWise member who authored the note. Untick it to use the board's Display Name, or rename the member. Neo authors client-facing notes as **Neo’s non-API ConnectWise member**, set on the ConnectWise panel of the Neo Dashboard's [**Integrations**](https://dashboard.neoagent.io/integrations?open=connectwise) page. When that field is empty the author is the API member instead, so an unset field is the usual cause of an internal account name reaching an end user. Set the name of whichever member authors the note. </Accordion> <Accordion title="The end user receives nothing"> Check in this order: 1. **Send to Contact** on the template for the ticket's current status. 2. The ticket has a contact with a valid email address. 3. The **Ticket Notes (Client-Facing)** permission group is enabled, and not read-only, on the ConnectWise integration. The board's **Send to Contact** is not on that list. Neo enables the ticket's own `automaticEmailContactFlag` before it posts, so the board default alone does not suppress the email. </Accordion> <Accordion title="End users receive a confirmation we did not configure"> The board's status template for the status your email connector assigns to new tickets is sending it. Turning off the connector's auto-response does not stop it — the two are separate senders. </Accordion> <Accordion title="One end client's emails are branded correctly and another's are not"> Configuration is per board and per status template. Audit each board separately, and within a board, each template that has **Send to Contact** ticked. </Accordion> </AccordionGroup> # End-User Communication Source: https://docs.neoagent.io/integrations/psa/end-user-communication How Neo Agent replies to ticket contacts — and how email delivery is configured for each PSA (Autotask, ConnectWise, HaloPSA, ServiceNow) When Neo Agent "replies to the end user" **on a ticket**, it does not send email directly. It writes a **note** or a **time entry** to your PSA, and your PSA decides whether that becomes a customer email. Whether the end user actually receives anything depends entirely on how the channel is configured for your PSA. The separate [Send Email tool](/agents/tools/communication/send-email) is the exception: it sends from Neo's own mailbox and bypasses the PSA entirely. This page explains the model. For the PSA-specific setup steps, see the Autotask and ConnectWise deep dives: [Autotask](/integrations/psa/autotask/ticket-contact-notifications), [ConnectWise](/integrations/psa/connectwise/ticket-contact-notifications). ## How Neo reaches the end user Neo has two PSA-side channels for end-user communication: * **Client-facing note** — a note on the ticket that is meant for the end user. Your PSA may deliver it as an email to the ticket contact. * **Time entry** — a logged time entry. Some MSPs configure their PSA to email the ticket contact whenever a time entry is added, which makes the time entry itself a client-facing channel. Both also have an internal-only counterpart — an **internal note** — that is never sent to the end user. <Info> **Configured by permission group, not by a tool.** Neo's communication capabilities are turned on by granting the relevant **permission group** on the PSA integration — on the workflow's **Integrations** tab — not by adding a tool to the toolbox. The client-facing notes group and the **Time Entries** group on the PSA API integration grant these capabilities, so the toolbox has no separate note or time-entry tool to add. The group names differ per PSA — the table below gives each one. </Info> | Permission group | What it lets Neo do | | - | - | | **Ticket Notes (Client-Facing)** — **Actions (Client-Facing Notes)** on HaloPSA, **Client-Facing Notes** on ServiceNow and Syncro | Add a customer-visible note. Delivery as an email depends on PSA configuration. | | **Time Entries** — **Actions (Time Entries)** on HaloPSA | Log a time entry. Becomes client-facing only if your PSA emails the contact on time entries. | | **Ticket Notes (Internal)** — **Actions (Internal Notes)** on HaloPSA, **Work Notes** on ServiceNow and Syncro | Add an internal-only note. Never sent to the end user. | If a client-facing channel is **not enabled**, Neo can still draft a message — but it is **not delivered**. The run result says so explicitly (for example, *"the end-user message was NOT sent because client-facing notes are disabled for this PSA"*), and Neo records the content on an internal note instead. The internal-notes group works the same way in reverse: set it to **Read-only** or **Disabled** and an agent also leaves the internal note off a time entry, which is still logged either way. Details, including which PSAs give a time entry its own private note field: [Add Time Entry](/agents/tools/management/add-time-entry). **A ticket with no contact has no recipient**, so neither channel delivers a message on it — a client-facing note is refused, and a time entry's customer message is left off the entry. This holds however the channels are configured, because there is nobody to write to. A ticket one of your own engineers raised is usually this shape. Neo records what it would have said on an internal note and states in the run summary that nothing was delivered; the time entry is still logged. ## By PSA <Tabs> <Tab title="Autotask"> Autotask has **two** possible client-facing channels — ticket notes and time entries — and email delivery is driven by an **Autotask Workflow rule**. Depending on how your team already notifies contacts, you may also need a User-Defined Field (UDF) so that only Neo's communications trigger emails. Grant the **Ticket Notes (Client-Facing)** permission group (for ticket-note delivery) and/or the **Time Entries** permission group (for time-entry delivery) on the Autotask PSA integration. Full setup steps, scenarios, and the UDF workaround: [Configuring End-User Email Notifications](/integrations/psa/autotask/ticket-contact-notifications). </Tab> <Tab title="ConnectWise"> ConnectWise also has two client-facing channels — a **public ticket note** and a **time entry** — but there is no UDF workaround needed. * Grant the **Ticket Notes (Client-Facing)** permission group so Neo can add a customer-visible (public) ticket note. Its settings control an optional send delay and whether additional contacts on the ticket are notified. * Grant the **Time Entries** permission group if you want Neo to log time; whether that emails the contact depends on your ConnectWise notification configuration. * The **Ticket Notes (Internal)** permission group is internal-only — notes added through it are never sent to the end user. ConnectWise builds the From line — address and display name — from the service board and its per-status email templates. Neo sends no sender of its own. Full setup steps, the multi-brand/white-label checklist, and the settings that leak your MSP's address into an end client's inbox: [Configuring End-User Email Notifications](/integrations/psa/connectwise/ticket-contact-notifications). </Tab> <Tab title="HaloPSA"> HaloPSA delivers customer emails based on the **Outcome** applied to a ticket action. Grant the **Actions (Client-Facing Notes)** permission group, then select the **Outcome(s)** that send an email to the end user in that group's settings. Without a customer-emailing outcome selected, Neo's note is added to the ticket but no email is sent. If the Outcome you select is configured in HaloPSA as **Respond Automatically** (for example, "Email User"), Neo also logs the ticket's first response — exactly as if a technician had clicked that Outcome in the HaloPSA UI. The ticket's response SLA is then marked as met, and a `Responded` entry appears on the timeline beside Neo's reply. Only the first reply logs a response; later replies on the same ticket leave it unchanged. An Outcome that is not configured to respond automatically — an internal note, for example — never marks the SLA. </Tab> <Tab title="ServiceNow"> ServiceNow separates the two channels at the field level: * **`comments`** — customer-visible "Additional comments" that notify the caller. Controlled by the **Client-Facing Notes** permission group. * **`work_notes`** — internal-only journal entries. Controlled by the **Work Notes** permission group. Grant the **Client-Facing Notes** permission group so Neo can post customer-visible comments. A single update that adds a comment or work note and also changes other ticket fields (state, assignee, priority) needs every group it touches at Read/Write: the notes group for each note, and **Tickets** for the other fields. If any of those groups requires technician approval, the whole update waits for approval. </Tab> </Tabs> ## Troubleshooting <AccordionGroup> <Accordion title="Neo's run summary says a message was not delivered to the user"> This is expected when the client-facing channel is disabled. Neo drafted a message, but your PSA's client-facing notes group is not enabled (or is read-only) on the PSA integration, so the message was not sent — it was recorded on an internal note instead. Enable the permission group to let Neo communicate with end users. </Accordion> <Accordion title="The end user is not receiving emails"> The permission group only lets Neo *write* the note or time entry. Your PSA still has to be configured to *email* the contact: * **Autotask** — verify the Autotask Workflow rule is active and (if used) the UDF is set. See the [Autotask guide](/integrations/psa/autotask/ticket-contact-notifications). * **ConnectWise** — verify **Send to Contact** on the email template for the ticket's current status, and that the ticket has a contact with a valid address. See the [ConnectWise guide](/integrations/psa/connectwise/ticket-contact-notifications). * **HaloPSA** — verify a customer-emailing **Outcome** is selected in the **Actions (Client-Facing Notes)** settings. * **ServiceNow** — verify the caller has a valid email and notifications are enabled for `comments`. </Accordion> <Accordion title="Neo logs a time entry but the customer sees only a short summary"> The time-entry summary field is customer-visible in some configurations. If you want Neo's full reply to reach the customer, enable your PSA's client-facing notes group so Neo has a dedicated end-user message path, rather than relying on the time-entry summary. </Accordion> </AccordionGroup> # Exclude a company's tickets Source: https://docs.neoagent.io/integrations/psa/exclude-company-tickets Keep one end client's tickets out of Neo on any PSA: no sync, no triggered agent runs from their webhooks, and the synced tickets deleted Some end clients must not have their tickets in Neo, for example a customer whose contract or regulator forbids a third-party AI processor. Excluding a company's tickets keeps them out on every PSA Neo supports. ## What changes when you exclude a company | | Excluded company | | - | - | | Scheduled ticket sync | Skips its tickets before Neo summarizes or indexes them | | PSA webhooks | Dropped before they start a triggered agent | | Agents | No triggered agent runs on its tickets | | Tickets already in Neo | Deleted from Neo's ticket search | | The company itself | Stays on the Companies tab with a **Tickets excluded** badge | The exclusion takes full effect within a minute of saving it. Work that had already started on one of the company's tickets, such as a webhook being processed or an agent run, finishes. In that first minute, a webhook that names the company can still reach Neo's job queue before Neo drops it, and a ticket can still be written to Neo's ticket search. A second pass, 30 minutes after you exclude the company, deletes such tickets. An agent that reads your PSA directly, such as a scheduled agent that searches tickets or a chat question about a ticket, can still read the company's tickets from the PSA. What it reads is part of that agent run, and the run's record keeps it like any other run. Most webhooks name their company, and Neo drops them on arrival. For a webhook that does not (ServiceNow, an Autotask webhook without the company field, a Syncro comment), Neo reads the ticket from your PSA first, then drops the webhook before it saves it or matches an agent. Such a webhook passes through Neo's job queue before the drop, and the queue keeps its record for 30 days. ## Exclude or include a company <Steps> <Step title="Open your PSA's settings"> On [**Integrations**](https://dashboard.neoagent.io/integrations), pick your PSA and expand **Advanced settings**. **Excluded companies** sits below **Company filters**. For ServiceNow, which has no Advanced settings, **Excluded companies** is its own card on the ServiceNow page. </Step> <Step title="Exclude a company's tickets"> Pick the company, choose **Exclude tickets** and confirm. It joins the list of excluded companies. </Step> <Step title="Include them again (optional)"> Choose **Include tickets** on the company's row. Neo syncs the company's tickets updated in the last 90 days again. An older ticket comes back when it next changes in your PSA. </Step> </Steps> You can also ask the Neo Support agent to exclude or include a company, or call `PUT /public-api/end-companies/{psa_company_id}/ticket-exclusion` with `{"excluded": true}` (see the [public API](/developers/introduction)). <Note> Deleting a company from the Companies tab removes its exclusion, and Neo processes its tickets again. Keep the company and exclude its tickets instead. </Note> ## Restrict the PSA account Neo uses Excluded companies covers Neo's sync and its triggered agents. A scheduled agent or Chat Agent reads your PSA as the account Neo signs in with, so it can still read an excluded company's tickets. Most PSAs let you restrict that account; each page says what yours allows: * [ConnectWise](/integrations/psa/connectwise/creating-api-member#keep-neo-away-from-specific-companies) * [Autotask](/integrations/psa/autotask/creating-security-level#keep-neo-away-from-specific-companies) * [HaloPSA](/integrations/psa/halopsa/creating-agent#keep-neo-away-from-specific-companies) * [ServiceNow](/integrations/psa/servicenow/creating-oauth-app#keep-neo-away-from-specific-companies) * [Syncro](/integrations/psa/syncro/creating-security-group#keep-neo-away-from-specific-customers) A restricted account also stops Neo's sync from reading the company's tickets. ## How this differs from other filters * [**Company filters**](/integrations/psa/company-filters) decide which companies are in Neo's company directory. They do not stop a company's tickets. * **PSA filters** (boards, queues, assignment groups) decide which tickets Neo syncs by where they sit in your PSA, not by company. * A triggered agent's condition on the company name stops that agent, but Neo still syncs and stores the tickets. # Webhook Events Source: https://docs.neoagent.io/integrations/psa/halopsa/configuring-webhooks The ticket events Neo Agent subscribes its HaloPSA webhook to, and how to check them When you connect HaloPSA, Neo Agent creates a webhook named **Neo Tickets callback \[ALL]** in your HaloPSA system and subscribes it to the ticket events it needs. There is nothing to add by hand. ## The events Neo subscribes to | Event | Criteria | Purpose | | - | - | - | | New Ticket Logged | None | Fires when a ticket is created | | Ticket Updated | Status: Value changed, To any value | Fires when a ticket's status changes | | Ticket Updated by Agent | None | Fires when an agent updates a ticket | | Ticket Updated by User | None | Fires when an end user updates a ticket | <Info> "Ticket Updated" fires on every property change, and HaloPSA requires at least one criterion on it. Neo narrows it to status changes so you receive one notification per status change instead of one per edited field. </Info> ## Checking the events <Steps> <Step title="Open the webhook"> In HaloPSA, go to **Configuration → Integrations → Webhooks** and click **Neo Tickets callback \[ALL]**. <Frame> <img alt="HaloPSA Webhooks page showing the Neo Tickets callback webhook" /> </Frame> </Step> <Step title="Check the Events section"> The **Events** section lists the four events above, with the Status criterion on Ticket Updated. **Enabled** is **Yes**. <Frame> <img alt="Webhook configuration showing the four events: New Ticket Logged, Ticket Updated, Ticket Updated by Agent, and Ticket Updated by User" /> </Frame> </Step> <Step title="Check a delivery"> Open the **Deliveries** tab, then create or update a test ticket. A new delivery with a `200` response means the event reached Neo Agent. </Step> </Steps> ## Adding your own events You can add further events to the webhook, for example an out-of-hours update event. Click **Edit**, then **+ Add** in the **Events** section, pick the event, and **Save**. Neo Agent leaves events you add in place. <Warning> Do not remove the four events above. A missing event means Neo Agent stops hearing about that kind of ticket activity, and agents that trigger on it stop running. </Warning> ## Webhooks created before September 2026 If you connected HaloPSA before Neo Agent created the events itself, the webhook may still carry the events you added by hand. Those keep working; nothing changes for you. If the webhook has **no** events at all, Neo Agent adds the four events on its own during its next scheduled sync of your HaloPSA data. To fix it right away, open your PSA on the Neo Agent **Integrations** page and click **Save & run checks**. ## Troubleshooting <AccordionGroup> <Accordion title="Webhook not found"> * Confirm you have [connected HaloPSA to Neo Agent](/integrations/psa/halopsa/connecting-to-neo). The webhook is created when the connection is saved. * Confirm your API application has the **admin:webhooks** scope set to **Yes** (see [Creating an API Application](/integrations/psa/halopsa/creating-api-application)). Without it, webhook creation fails with a **401 Unauthorized**. * After enabling the scope, open your PSA on the **Integrations** page and click **Save & run checks** again. </Accordion> <Accordion title="Webhook has no events"> * Neo Agent adds the four events to a Neo webhook that has none, both on the next scheduled sync and when you click **Save & run checks** on your PSA on the **Integrations** page. * If your only Neo webhook still has no events afterwards, the API application lacks the **admin:webhooks** scope. Enable it and save again. * If your HaloPSA system carries **two** webhooks pointing at Neo Agent, Neo Agent fills only one of them. Two webhooks deliver every ticket event twice, so the second one stays empty on purpose. Delete the empty one if you want a tidy list. </Accordion> <Accordion title="Webhook is missing some of the four events"> Neo Agent only adds events to a webhook that has none, because a webhook with some events looks the same as one you set up the way you want it. When a Neo webhook carries some of the four but not all, Neo Agent puts an item in your dashboard **Inbox** naming the events that are missing, and emails your workspace owners and admins. * Open **Configuration → Integrations → Webhooks** in HaloPSA, click **Neo Tickets callback \[ALL]**, then **Edit** and **+ Add** in the **Events** section to add each event the Inbox item names. Use the criteria in [the table above](#the-events-neo-subscribes-to). * The Inbox item clears once all four events are in place, at the next scheduled sync or the next time you click **Save & run checks**. * If an event later goes missing again, the item comes back unread and you are emailed again, so a webhook someone edits months from now is not a silent one. </Accordion> <Accordion title="Webhook not triggering"> * Verify the webhook is set to **Enabled: Yes**. * Verify the four events are present. * Create a test ticket and check the **Deliveries** tab. </Accordion> <Accordion title="Delivery failures"> * Check that your Neo Agent subscription is active. * Ensure no firewall rule blocks outbound connections from HaloPSA. * Review the **Deliveries** tab for the error returned. </Accordion> </AccordionGroup> ## What's Next? Neo Agent now receives ticket activity from HaloPSA as it happens. You can: * **Create Workflows**: Build automations that trigger the moment a ticket is created or updated * **Configure Responses**: Set how Neo Agent responds to each kind of ticket event * **Monitor Activity**: Follow Neo Agent's interactions with your HaloPSA tickets in Executions # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/psa/halopsa/connecting-to-neo Configure the connection between your HaloPSA system and Neo Agent using API credentials Once you have [created your agent resource](/integrations/psa/halopsa/creating-agent) and [set up your API application](/integrations/psa/halopsa/creating-api-application), connect them in the Neo dashboard. ## Required Information Gather the following from your HaloPSA system before you start: <ParamField type="string"> The unique identifier for your Neo Agent API application, shown on the application's Details tab after you save it. </ParamField> <ParamField type="string"> The secret for your API application. HaloPSA shows it once, at creation. </ParamField> <ParamField type="string"> Your HaloPSA instance URL (e.g., `https://yourdomain.halopsa.com` or `https://yourdomain.haloitsm.com`), without a trailing slash. </ParamField> <ParamField type="string"> The ID of the Neo Agent resource you created. Neo uses this agent for time entries and ticket assignments. </ParamField> <Warning> If you did not save your Client Secret when creating the API application, regenerate it in HaloPSA. The secret is only displayed once. </Warning> ## Configuring the Integration <Steps> <Step title="Open HaloPSA in the Neo dashboard"> In the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations), open **Integrations**, switch to the Directory tab, and select HaloPSA. The connect page walks you through the same steps as this guide, one at a time. </Step> <Step title="Enter your credentials"> On the "Enter connection details" step, fill in the Client ID, Client Secret, base URL, and Agent ID you gathered, then click **Save & run checks**. Neo runs the checks on the values you entered and stores the credentials only when the required checks pass. After a passing run, save registers the webhook and does not re-run the ticket-read probe. </Step> <Step title="Watch the verification checks"> Neo runs its verification checks one by one against the values you entered: authentication, the agent the application logs in as, ticket read access, write access, webhook permission (`admin:webhooks`), and data sync (sync starts after save). Each check reports as it completes. A missing `admin:webhooks` scope fails the webhook row and Neo does not store the credentials. <Check> All required checks green means Neo authenticates, logs in as your Neo Agent resource, can read and write tickets, and can register the webhook. A failed check names the exact HaloPSA screen to fix. Fix the permission, then click **Save & run checks** again. </Check> </Step> </Steps> ## Troubleshooting Connection Issues If a check fails or the save is rejected, check the following: <AccordionGroup> <Accordion title="Authentication Errors"> * Verify that the Client ID is correct and corresponds to an active API application * Ensure the Client Secret was copied correctly without extra spaces or characters * Confirm the API application is set to "Active" status in HaloPSA * Check that the authentication method is "Client ID and Secret (Services)" * Try regenerating the Client Secret if you are unsure about its accuracy </Accordion> <Accordion title="Permission Errors"> * Verify that the `all:standard`, `all:teams`, and `admin:webhooks` scopes are all set to Yes on the application's Permissions tab * `admin:webhooks` is required. If it is missing, the credentials are accepted but Neo's automatic webhook creation fails with a 401 Unauthorized, and the connection cannot complete. Enable it, then retry. * A bare 403 when an agent tries to create an email rule is a different, expected case: HaloPSA blocks configuration writes unless the optional `admin` scope is enabled. See [Letting Neo Manage Email Rules](/integrations/psa/halopsa/managing-email-rules). </Accordion> <Accordion title="Agent Resource Issues"> * Verify that the Agent ID or username is correct * Ensure the agent resource is set to "Active" status * Check that the agent has proper team assignments; the identity check confirms which agent the application logs in as * Confirm the agent has permissions to create time entries and can be assigned to tickets </Accordion> <Accordion title="Network Connectivity"> * Confirm your HaloPSA Base URL is accessible from external networks * Check if any firewall rules might be blocking API connections * [Whitelist Neo Agent's IP address](/integrations/ip-whitelisting) if your system restricts access by IP * Test the URL accessibility by opening it in a browser, and use HTTPS </Accordion> <Accordion title="URL Format Issues"> * Remove any trailing slashes from the base URL * Ensure you are using the correct domain (halopsa.com vs haloitsm.com) and your specific subdomain * Do not include `/api/` or other path segments in the base URL * Use the full URL including `https://` </Accordion> </AccordionGroup> ## What's Next? When you connect HaloPSA, Neo creates a webhook named "Neo Tickets callback \[ALL]" in your HaloPSA system and subscribes it to the ticket events it needs. Nothing to add by hand: <Card title="Webhook Events" icon="webhook" href="/integrations/psa/halopsa/configuring-webhooks"> The events Neo subscribes to, and how to check them in HaloPSA. </Card> <Tip> Start with simple workflows to test the integration before implementing more complex automation scenarios. </Tip> # Creating an Agent Resource Source: https://docs.neoagent.io/integrations/psa/halopsa/creating-agent Set up a dedicated agent in HaloPSA for Neo Agent to use when performing actions, logging time, and updating tickets To enable Neo Agent to add notes, log time, and perform actions within your HaloPSA system, you need to create a dedicated agent (resource) that Neo Agent will impersonate. ## Creating the Agent <Steps> <Step title="Navigate to the Agents section"> Go to **Configuration → Teams & Agents → Agents** to access the agent accounts list. <Frame> <img alt="HaloPSA Agents list under Configuration → Teams & Agents → Agents" /> </Frame> Click **New** to create a new agent resource. </Step> <Step title="Configure account details"> Fill in the essential account information: * **Username**: Enter a descriptive name like `Neo Agent` * **Email Address**: Set to `psa-noreply@neoagent.io`, or use an address on your own domain such as `neo@yourcompany.com` * **Password**: Set any password. Neo Agent uses API authentication, not the UI * **Roles**: Select an appropriate role (e.g., `1st Line Support` or `Administrator`) * **Account Active**: Ensure this is checked * **Is an API-only Agent**: Leave unchecked. Neo Agent needs to assign tickets to itself and create time entries, which require a full agent account <Frame> <img alt="Neo Agent account details in HaloPSA" /> </Frame> <Warning> Use `psa-noreply@neoagent.io` here, never another `@neoagent.io` address such as `team@neoagent.io`. HaloPSA mails agent notifications — "New Ticket Logged", "Ticket Updated by User", and any other rule the agent's roles subscribe it to — to whatever address sits on the agent record. `psa-noreply@neoagent.io` discards everything it receives. Any other Neo address delivers your ticket notifications, and the customer data inside them, to a Neo inbox instead of your team's. Neo itself never reads this field. The API application authenticates with its own credentials and the agent ID. </Warning> <Info> The name you choose will be visible in ticket histories, time entries, and notes. Use "Neo Agent" for clear attribution, or a real person's name if you want end-user communications to feel more personal. </Info> </Step> <Step title="Assign to a team"> Navigate to the **Departments & Teams** tab and assign the agent to the appropriate team(s) that handle tickets Neo Agent will work on. <Warning> The agent must be assigned to at least one team to appear in team-scoped ticket views and to be assignable to tickets. </Warning> </Step> <Step title="Configure working hours and timezone"> In the **Preferences** tab, set the agent's **Working Hours** and **Timezone** to match your primary support hours. <Frame> <img alt="Working hours and timezone configuration for the Neo Agent resource" /> </Frame> <Tip> The timezone setting affects how time entries are recorded. Set it to your primary service region's timezone. </Tip> </Step> <Step title="Save and note the Agent ID"> Click Save to create the agent. After saving, note the **Agent ID** in the ID column on the Agents list page. <Frame> <img alt="HaloPSA Agents list showing the ID column for each agent" /> </Frame> <Check> Record the Agent ID. You need it when creating the API application and connecting to Neo Agent. </Check> </Step> </Steps> ## Keep Neo away from specific companies [Excluded companies](/integrations/psa/exclude-company-tickets) keeps a company's tickets out of Neo's sync and triggered agents. A scheduled agent or Chat Agent reads the PSA as the account Neo signs in with, so to keep those agents away from a company too, restrict that account. In Halo, the role of the agent the API application logs in as decides which clients Neo can see: 1. In **Configuration > Teams & Agents > Roles**, create a role for Neo with the permissions it uses (a `1st Line Support`-style role), not **Administrator**: with Halo's "Give admins additional privileges" setting on, Administrator overrides every restriction. Under **Client Restrictions**, add every client except the ones to hide. 2. Give the Neo agent that role and remove every other role. Halo adds up the access of all of an agent's roles, so a remaining unrestricted role keeps every client visible. **Client Restrictions** is an allow-list: an empty list means all clients, and a new client stays hidden from Neo until you add it. Afterwards, check in a chat with Neo that it can open a ticket of a listed client and cannot open one of a hidden client. Leaving a team out of the agent's teams hides only that team's tickets, so it works for a client only when its tickets sit on a team of their own. ## What's Next? Once you've created the agent resource, proceed to [create an API application](/integrations/psa/halopsa/creating-api-application) for programmatic access to your HaloPSA system. # Creating an API Application Source: https://docs.neoagent.io/integrations/psa/halopsa/creating-api-application Create the HaloPSA API application Neo Agent authenticates with Neo Agent authenticates against HaloPSA with a dedicated API application. Create the [Neo Agent resource](/integrations/psa/halopsa/creating-agent) first; the application logs in as it. ## Creating the API Application <Steps> <Step title="Navigate to API Applications"> Go to Configuration → Integrations → HaloPSA API, click View Applications, then New. <Frame> <img alt="HaloPSA API management page" /> </Frame> </Step> <Step title="Configure application details"> Set these fields: * Application Name: `neoagent` * Active: checked * Authentication Method: Client ID and Secret (Services) * Agent to log in as: the **Neo Agent** resource you created, not the default <Frame> <img alt="Create new application, basic details" /> </Frame> <Warning> The login agent decides which tickets Neo can see: HaloPSA scopes the application's access to that agent's teams. Leave it on the default and Neo works the wrong ticket set. Neo's verification checks confirm the agent after you connect. </Warning> </Step> <Step title="Set the permissions"> On the Permissions tab, set these three scopes to Yes and leave every other scope at No: * `all:standard`: read and write access to tickets, actions, contacts, assets, and the other standard areas * `all:teams`: access to teams and agents, so Neo routes and assigns tickets correctly * `admin:webhooks`: lets Neo register its webhook automatically <Frame> <img alt="API application permissions" /> </Frame> HaloPSA's scopes are coarse, so `all:standard` grants broad access. The Neo dashboard's permission groups control what Neo actually does; the scopes only set the maximum access. Sensitive areas such as invoices, contracts, and configuration default to read-only in Neo's standard permission profiles. Two parts of Invoices stay protected even with write access enabled: Halo publishes charge rates as read-only through the API, and creating or deleting a billing template always asks a technician to approve it first — including on a Full Automation agent — because a template sets rates, free units, billing periods, and prepay top-up amounts for the clients it covers. <Warning> `admin:webhooks` is required. The `all:standard` scope does not cover webhook administration, and without it the connection fails with 401 Unauthorized when Neo creates its webhook. This is the most common reason a HaloPSA connection fails after the Client ID and Secret are accepted. </Warning> <Note> Optional: set `admin` to Yes only if Neo should manage HaloPSA email rules, for example to block a repeat spam sender with an Ignore Email rule. Everything else works without it, and you can enable it later without redoing the connection. Both required steps are in [Letting Neo Manage Email Rules](/integrations/psa/halopsa/managing-email-rules). </Note> </Step> <Step title="Save and copy the credentials"> Click Save. The Details tab shows the Client ID and the Client Secret. Copy both now; HaloPSA may not show the secret again. <Frame> <img alt="API application details showing Client ID and Client Secret" /> </Frame> </Step> </Steps> ## What's Next? Proceed to [connect HaloPSA to Neo Agent](/integrations/psa/halopsa/connecting-to-neo). <Check> Before you proceed, verify: * The application is Active with authentication method Client ID and Secret (Services) * Agent to log in as is the Neo Agent resource * `all:standard`, `all:teams`, and `admin:webhooks` are set to Yes * You saved the Client ID, the Client Secret, and your HaloPSA base URL </Check> # Read-Only Access for the Free Insights Report Source: https://docs.neoagent.io/integrations/psa/halopsa/free-report-read-only-access Create a minimal HaloPSA API application for the free Neo Insights report — the read:tickets permission only, no writes The [free Insights report](https://www.neoagent.io/free-report) reads a sample of your recent tickets, classifies them, and shows you what your service desk could automate. It needs far less access than a full Neo Agent connection: **one read-only permission**, nothing else. ## What Neo reads — and what it never does For the report, Neo makes only these read-only calls: * `/api/Tickets` — the list of recent tickets (summary, status, dates, client name) * `/api/Actions` — the ticket notes, for better summaries * Ticket lookups — statuses, priorities, ticket types and categories, so IDs render as names Neo does **not** read your client list, users, agents, assets, SLAs or invoicing data, and it does **not** write anything — no webhooks, no actions, no ticket changes. When your report is ready (or if the run fails), the credentials are **automatically purged** from our vault and the temporary workspace is disabled. If you later start a trial, you will set up a separate connection with its own credentials. ## Creating the read-only API application <Steps> <Step title="Create a new API application"> Go to **Configuration → Integrations → HaloPSA API**, click **View Applications**, then **New**. * **Application Name**: `Neo Free Report` * **Active**: checked * **Authentication Method**: **Client ID and Secret (Services)** </Step> <Step title="Pick the agent to log in as"> HaloPSA limits an API application to what its **login agent** can see. Pick an agent with access to **all teams and ticket areas** (an administrator-level agent is easiest) — otherwise the report only samples the tickets that agent can see, and the numbers come out low. </Step> <Step title="Grant only the read:tickets permission"> Open the **Permissions** tab and tick **read:tickets**. Leave every other permission — including **all**, **all:standard** and **admin** — unticked. </Step> <Step title="Enter the details in the report form"> Copy the **Client ID** and **Client Secret**, then back in the [report form](https://www.neoagent.io/free-report) enter: * **HaloPSA URL** — the web address of your instance, for example `https://yourcompany.halopsa.com` * **Client ID** and **Client secret** — from the application you just created Neo checks the connection immediately and tells you on the spot if anything is missing. </Step> </Steps> <Tip> Prefer to deactivate the application yourself afterwards? That works too — the report needs the credentials only for the few minutes the analysis runs. </Tip> # Letting Neo Manage Email Rules Source: https://docs.neoagent.io/integrations/psa/halopsa/managing-email-rules Enable Neo Agent to block repeat spam senders at source by managing HaloPSA inbound email rules HaloPSA decides what happens to mail arriving at a monitored mailbox using **email rules** (*Configuration → Email → Email Rules*). One rule type — **Ignore Email** — tells HaloPSA to discard mail from a given sender without raising a ticket. Letting Neo manage these rules turns repeat spam from a recurring chore into a one-off action: instead of an agent closing the same spam ticket every time that sender writes in, it adds an Ignore Email rule for the address and HaloPSA stops raising tickets from it. Those repeat closures also stop consuming credits. <Info> HaloPSA's built-in **treat as spam** option can't be reached from quick actions or workflows, and it's gated on agent role — so a "close as spam" action can only close the ticket, never stop the next one. Email rules are the way to automate this. </Info> ## Two things to enable Both are required. Neo can *read* your email rules as soon as the HaloPSA integration is connected, but **creating** one needs each of these. <Steps> <Step title="Enable the `admin` scope on your HaloPSA API application"> In HaloPSA, go to **Configuration → Integrations → HaloPSA API → View Applications**, open the application you created for Neo Agent, then **Permissions → Edit**. Set **admin** to **Yes** and save. Without it, HaloPSA rejects every configuration write — including email rules — with a **403 Forbidden** and an empty response body. Reads are unaffected. <Warning> `admin` is a broad HaloPSA scope. HaloPSA itself flags on that screen that `all` and `admin` "should not be used in production as they expose administration level access" — it raises the ceiling across HaloPSA configuration, not just email rules. What Neo can actually touch is still governed by the **Email Rules** permission group in step 2, which is separate from the **Configuration** group and read-only until you grant it. The dashboard layer, not the scope, is what keeps this narrow. See [Creating an API Application](/integrations/psa/halopsa/creating-api-application) for the full scope list. </Warning> </Step> <Step title="Grant the Email Rules permission group to your agent"> In the Neo Agent dashboard, open the agent that should do the blocking — typically a spam-cleanup or triage agent — and on its **Integrations** tab set the **Email Rules** permission group to **Read / Write**. Turn on **Delete** as well if the agent should be able to remove rules (that's how a wrongly-blocked sender is unblocked). To review each block before it applies, turn on technician approval for this group. The group is read-only in the **Read Only** and **Helpdesk** profiles, and read/write in **IT Admin** and **Full Automation**. Existing agents don't get it automatically — grant it deliberately, per agent. </Step> </Steps> ## What Neo does with it Given the permission, an agent that identifies a message as spam can add a rule that matches that exact sender address and ignores it. Neo reads your existing rules first so it mirrors your tenant's conventions and doesn't add a duplicate, and it records the address it blocked on the ticket — an ignore rule is invisible until someone goes looking for it. <Warning> **A rule that matches too broadly silently drops mail.** Ignored email raises no ticket, so nothing appears in HaloPSA for a technician to notice — that's the whole point of the feature, and also its risk. Neo blocks one exact sender address per rule and won't ignore a whole customer domain or a free-mail domain (gmail.com, outlook.com) on its own. If you ask it to match more broadly in an agent's custom instructions, understand that everything matching stops raising tickets until the rule is removed. </Warning> ## Unblocking a sender Delete the rule in HaloPSA (*Configuration → Email → Email Rules*) and delivery resumes immediately. An agent with **Delete** enabled on the Email Rules group can also remove it on request. ## If it isn't working | What you see | What it means | | - | - | | The agent says email rules aren't a supported area, or names the permission groups it does have | The **Email Rules** permission group isn't granted on that agent — step 2 above. | | The agent reports a **403** from HaloPSA with no further detail | The `admin` scope is missing from the HaloPSA API application — step 1 above. Reading rules will still work, which is why this shows up only on the first create. | | Neo can list rules but you expected it to add one unprompted | Blocking is driven by the agent's instructions. Tell the agent when to block — for example, only for senders it has already classified as spam with high confidence. | ## Related * [Creating an API Application](/integrations/psa/halopsa/creating-api-application) — full OAuth scope list for the HaloPSA integration * [PSA API tool](/agents/tools/psa/psa-api) — how permission groups gate everything Neo does in your PSA * [Technician-in-the-Loop](/core/technician-in-the-loop) — requiring approval before a write # Overview Source: https://docs.neoagent.io/integrations/psa/halopsa/overview Connect your HaloPSA system to Neo Agent for automated ticket management and workflow automation ## Setup Overview Setting up the HaloPSA integration involves three main steps: <CardGroup> <Card title="Creating an Agent Resource" icon="user-plus" href="/integrations/psa/halopsa/creating-agent"> Set up a dedicated agent in HaloPSA that Neo Agent will use for time entries, ticket assignments, and action attribution. </Card> <Card title="Creating an API Application" icon="key" href="/integrations/psa/halopsa/creating-api-application"> Configure API credentials with the right scopes for Neo Agent to access your HaloPSA system programmatically. </Card> </CardGroup> <CardGroup> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/psa/halopsa/connecting-to-neo"> Configure the connection between your HaloPSA system and Neo Agent using API credentials and integration settings. </Card> <Card title="Webhook Events" icon="webhook" href="/integrations/psa/halopsa/configuring-webhooks"> The ticket events Neo Agent subscribes its webhook to, created for you on connect. </Card> </CardGroup> ## Optional Capabilities <CardGroup> <Card title="Letting Neo Manage Email Rules" icon="shield-ban" href="/integrations/psa/halopsa/managing-email-rules"> Let an agent block repeat spam senders at source with an Ignore Email rule, instead of closing the same spam ticket over and over. Needs one extra OAuth scope. </Card> </CardGroup> ## How Permissions Work Neo Agent uses **two layers of access control**: the HaloPSA API application's OAuth scopes set the *maximum* API access (configured during setup), while the Neo Agent dashboard controls what Neo actually does — which areas it can read, write, or ignore, and whether actions require technician approval. ## Projects and Project Tasks HaloPSA stores projects and project tasks as tickets, so an agent or workflow that processes tickets also runs on them. Its ticket filter decides whether it does. Filter on **Ticket Type ID**: * **Only project work:** add a rule **Ticket Type ID** **is in list** with your project ticket types, such as *Project* and *Project Task*. * **No project work:** add one rule **Ticket Type ID** `!=` per project ticket type, all joined with **AND**. The Ticket Type ID picker lists every ticket type in your HaloPSA, project types included. ## Mandatory Fields HaloPSA lets you mark any field mandatory, and it enforces that on API writes as well as in the web interface. When an agent creates something that omits one — an action on a ticket, a new ticket, a contact, a knowledge base article — Halo refuses the write with a message such as `Categories is mandatory`. Neo reads that refusal, tells the agent which field Halo asked for, and lets it look up the valid values for your instance and retry. Two things follow from this: * **Keep the picklist behind a mandatory field populated.** If Halo requires a category but the list has no option the agent may select, the write cannot succeed and the agent reports the refusal instead. * **`Categories is mandatory` on an action is about the ticket.** An action that carries an outcome makes Halo re-validate the ticket the outcome applies to, and Category is a ticket field. So this refusal usually means the ticket's own Category 1 is empty, or holds a value that is not valid for the ticket's type — a category the ticket kept after its type changed, for example. Halo shows such a ticket with a category ID but no category name. * **That one needs a person, or permission.** Category is a triage field, and most dispatch agents are told not to change a ticket's triage fields. When the agent may not set it, the agent reports the blocker in its run summary and the ticket stays where it is until someone sets a valid Category. A note on the ticket is not a dependable record of that blocker: a note that carries an outcome is itself an action, and Halo refuses it for the same reason. Correcting the ticket, or allowing the agent to set categories, unblocks it. A ticket that Neo itself creates works differently. The end-user Chat Agent and the Create New Ticket action fill a fixed set of fields, so no agent can add a missing one. When Halo refuses such a ticket because the ticket type makes a field mandatory (a Category, for example), the ticket is not created and your Neo Inbox gets a warning that names the field and the ticket type. Every ticket Neo creates with that ticket type and without that field fails the same way until you make the field optional for it in HaloPSA, or choose a ticket type that does not require it in the Neo setting that creates the ticket. If you would rather agents never have to supply a field, clear its mandatory flag in HaloPSA under Configuration for that entity. ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Administrative access to your HaloPSA system (Configuration section) * **API Access**: An active HaloPSA subscription with API access enabled * **Named Licence**: An available agent licence for the Neo Agent resource # Overview Source: https://docs.neoagent.io/integrations/psa/intro Connect your Professional Services Automation system — Neo reads tickets, writes updates, and orchestrates workflows through it <Warning>Connecting your PSA first is mandatory. Neo reads incoming tickets, writes notes and time entries, drives state transitions, and triggers workflows entirely through your PSA.</Warning> Neo speaks every supported PSA's API natively and treats them uniformly — the same workflows, agents, actions, and triggers work across every one. Pick yours below to begin setup. ## Supported PSA Platforms <CardGroup> <Card title="Autotask" icon="ticket" href="/integrations/psa/autotask/overview"> Connect via API user + security level. Three-step setup with end-user notification controls. </Card> <Card title="ConnectWise" icon="briefcase" href="/integrations/psa/connectwise/overview"> Connect via dedicated security role + API member. Optional Pod integration to embed Neo inside ConnectWise. </Card> <Card title="HaloPSA" icon="circle-half-stroke" href="/integrations/psa/halopsa/overview"> Connect via Agent Resource + OAuth API application with scoped permissions. </Card> <Card title="ServiceNow" icon="gear" href="/integrations/psa/servicenow/overview"> Connect via OAuth 2.0 — Neo provisions Business Rule + System Property webhooks automatically. Supports the full task family (incidents, requests, RITMs, catalog tasks, change requests, problems). </Card> <Card title="Syncro" icon="wrench" href="/integrations/psa/syncro/overview"> Connect via a Syncro API token. The token identifies its own user, so there is no separate username to enter. </Card> </CardGroup> ## What Neo Does With Your PSA Neo reads incoming tickets in real time, then writes back the results of agent work: * **Read** — tickets and time entries (with all custom fields), companies, contacts, configurations, statuses, queues, ticket types * **Triage** — status, priority, queue, type/subtype, owner, custom fields * **Communicate** — internal notes, customer-facing notes, email replies routed through the PSA * **Time tracking** — time entries attributed to a dedicated Neo agent resource * **Lifecycle** — create new tickets, merge duplicates, schedule entries, state transitions * **Webhooks** — real-time callbacks on ticket events so workflows fire the moment they need to <Tip>Your PSA usually holds far more companies than you actively service. [**Company filters**](/integrations/psa/company-filters) let you keep Neo's company directory to real customers — active customers by default.</Tip> ## Connection Checks and Integration Health Connecting a PSA now runs a **verification check suite** the moment you save your details, and the connect page walks you through the PSA-side setup step by step before you ever type a credential: * **Setup walkthrough** — the connect page shows the setup steps for your PSA (create the API member/agent/application, generate keys) inline, with the full guide one click away. Returning users land on the filled form as before. * **Verification checks** — saving runs a per-PSA sequence: authentication, the identity Neo acts as (e.g. HaloPSA's "Agent to log in as", the ConnectWise API member), ticket read coverage, a write probe that changes nothing, the webhook registration, and sync state. A failed check names the exact screen in your PSA to fix, and the checks can be re-run without re-entering credentials. * **Health heartbeat** — once connected, a small heartbeat icon appears beside the integration's name (on its page and in the integrations list). Green and pulsing means the integration is healthy; red means something needs attention. Each time the icon loads, and when you return to the tab (at most once a minute), Neo asks your PSA whether Neo's webhook is active, so the icon follows the webhook state in your PSA. Hover it for the last ticket event, webhook state, sync state, and recent errors. On the integration's own page, the heartbeat also offers **Run checks now** to re-run the full suite. ## How Permissions Work Neo uses **two layers of access control**: 1. The PSA-side permissions on the API user, security role, or OAuth app set the *maximum* possible access (configured during setup). 2. The Neo dashboard's per-agent permission groups control what each agent actually does — read-only vs read/write, with optional technician approval for destructive operations. A junior helpdesk agent can be allowed to add notes but not change priority, while a senior dispatch agent can do both — all from the same PSA connection. ## Prerequisites Before connecting any PSA you'll need: * Administrative access to create an API user, security role, or OAuth application (varies by PSA — see the per-platform guide above) * A dedicated agent resource or service account that Neo's writes will be attributed to (improves your audit trail) * The Neo Agent dashboard at [dashboard.neoagent.io](https://dashboard.neoagent.io/integrations) Select your PSA above for the step-by-step setup guide. # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/psa/servicenow/connecting-to-neo Configure the connection between your ServiceNow instance and Neo Agent using OAuth Once you have [created your OAuth Application Registry entry](/integrations/psa/servicenow/creating-oauth-app), connect it in the Neo dashboard. <Info> Unlike ConnectWise or Halo, ServiceNow uses an OAuth consent flow. After you enter your credentials, a popup opens on your own ServiceNow instance where the Neo service account approves access. The popup closes itself when consent completes. </Info> ## Required Information Gather the following from the previous step: <ParamField type="string"> Your ServiceNow instance URL, for example `https://acme.service-now.com`. Must use HTTPS, no trailing slash, no path. FedRAMP / Government Community Cloud customers can also use `*.servicenowservices.com` instances. </ParamField> <ParamField type="string"> The Client ID auto-generated when you saved your OAuth Application Registry entry. </ParamField> <ParamField type="string"> The Client Secret from your OAuth Application Registry entry. Treat this like a password. Neo stores it encrypted and uses it only to refresh access tokens. </ParamField> ## Configuring the Integration <Steps> <Step title="Open ServiceNow in the Neo dashboard"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations), open the **Directory** tab, and click the ServiceNow tile. <Frame> <img alt="Neo Agent integrations directory with ServiceNow tile" /> </Frame> </Step> <Step title="Sign in to ServiceNow as the service account, then enter your credentials"> First, in another tab, sign in to ServiceNow as the dedicated Neo service account you created. The next step opens a consent popup, and the signed-in user at that moment becomes Neo's identity. Then fill in the three fields: * Instance URL, e.g. `https://acme.service-now.com` * Client ID * Client Secret <Frame> <img alt="ServiceNow connect form with instance URL, client ID, client secret" /> </Frame> Click **Connect ServiceNow**. The dashboard opens a popup pointed at your ServiceNow instance's OAuth consent page. <Tip> If your browser blocks the popup, the dashboard falls back to a full-page redirect. Either flow works. </Tip> </Step> <Step title="Approve in ServiceNow"> The popup shows the consent screen. Confirm the signed-in user is the Neo service account, then click Allow. The popup closes automatically and the dashboard runs its verification checks before the connected card appears. <Frame> <img alt="ServiceNow OAuth consent screen for Neo Agent" /> </Frame> <Warning> The user who clicks Allow becomes Neo's identity in ServiceNow. Every note, state change, and time entry Neo creates is attributed to that user, and tickets Neo claims are assigned to it. If you click Allow as your personal admin account, Neo looks like *you* in every audit log, your assignment queue fills with Neo-claimed tickets, and the integration breaks the day your account is disabled. If the wrong user is signed in, log out of ServiceNow, sign in as the service account, and click **Reconnect** in the Neo dashboard. </Warning> </Step> <Step title="Verify the connection"> Back in the Neo dashboard, Neo runs its verification checks: authorization, incident read access, write access, the webhook registration, and data sync. Each check reports as it completes. <Check> All checks green means Neo has API access for reads and writes and webhook delivery for real-time events. No further ServiceNow-side configuration is required. </Check> <Accordion title="What Neo provisions behind the scenes"> 1. Validates the OAuth refresh token by fetching an access token 2. Provisions a Business Rule on the parent `task` table (named "Neo Agent — Task Webhook"), which fires on every task-family subclass via table inheritance 3. Creates a System Property (`x_neoagent.callback_url`) holding the per-tenant callback URL the Business Rule POSTs to 4. Sets the integration's sync state to READY\_TO\_SYNC Details: [Webhook Architecture](/integrations/psa/servicenow/webhook-architecture). </Accordion> </Step> </Steps> ## Troubleshooting Connection Issues If you encounter issues during the connect flow, check the following: <AccordionGroup> <Accordion title="Instance URL Rejected"> The error names the rule: `instance_url must be a service-now.com or servicenowservices.com domain`. * Make sure the URL starts with `https://` (not `http://`) * The hostname must end with `.service-now.com` or `.servicenowservices.com` (FedRAMP/GovCloud customers) * Do not include a path. `https://acme.service-now.com` is correct, `https://acme.service-now.com/now` is not * Vanity URLs are not supported here. Use the canonical platform admin URL even if your end users access ServiceNow via a custom hostname </Accordion> <Accordion title="OAuth Callback Failed: invalid_client"> * Verify the Client ID matches the OAuth Application Registry entry exactly. Copy-paste, do not retype * Check the Client Secret was copied correctly without extra spaces or newline characters * Confirm the OAuth application is set to Active in ServiceNow * If you regenerated the Client Secret in ServiceNow, update it in Neo via the **Reconnect** button </Accordion> <Accordion title="Popup Closes With No Consent Screen"> * The Redirect URL on your OAuth Application Registry entry probably does not match. Verify it is exactly `https://dashboard.neoagent.io/oauth/servicenow/callback` * Extra trailing slashes, query parameters, or `http://` (instead of `https://`) cause this. The match must be byte-for-byte </Accordion> <Accordion title="Insufficient Privileges After OAuth Completes"> * The user that approved consent does not have the `itil` role, so Neo can authenticate but cannot read tickets * In ServiceNow, open the user record and assign the `itil` role (or your equivalent role with Table API read/write on the `task` family) * Click **Reconnect** in the Neo dashboard to retry </Accordion> <Accordion title="403 When Neo Sends an Email via PSA"> * Neo's "Email (sent via PSA)" notification mode calls `/api/now/v1/email`, which requires the `email_api_send` role on the integration user (separate from `itil`) * In ServiceNow, open the user record and assign the `email_api_send` role * No reconnect needed. The next workflow run picks it up, and Neo raises an inbox alert with this exact remediation when it sees the 403 </Accordion> <Accordion title="Connected But Webhooks Are Not Arriving"> * Check System Definition → Business Rules in ServiceNow for a rule named "Neo Agent — Task Webhook" on the `task` table. It should exist and be Active * Verify System Definition → System Properties contains `x_neoagent.callback_url` pointing at a `https://...neoagent.io/callback/servicenow?...` URL * If either is missing, click **Reconnect** in the Neo dashboard. The webhook provisioning step is idempotent, so re-running it is safe and fixes most provisioning failures (including removing the legacy incident-only rule on instances connected before mid-May 2026) * See [Webhook Architecture](/integrations/psa/servicenow/webhook-architecture) for the full provisioning flow </Accordion> <Accordion title="Network Connectivity"> * Confirm your ServiceNow instance is reachable from the public internet over HTTPS * If you have IP allowlisting enabled in ServiceNow, [whitelist Neo Agent's IP address](/integrations/ip-whitelisting) * The OAuth round-trip happens in the user's browser, but the ongoing API calls and webhook deliveries flow between Neo's backend and your ServiceNow instance directly </Accordion> </AccordionGroup> ## What's Next? Once connected, every task-family record on your instance (incidents, requests, request items, tasks, change requests, and problems) flows through Neo's event pipeline. From here you can: * **Build workflows**: create automated workflows that triage, route, comment, and resolve ServiceNow tickets. Use the Ticket Type filter in the rules-builder to scope a workflow to specific subclasses * **Configure permissions**: fine-tune which areas Neo can read versus write in the Neo dashboard's permission groups <Tip> Start with simple workflows (e.g., auto-acknowledge a new incident with a courteous note) before enabling more autonomous behavior. </Tip> # Creating the OAuth Application Source: https://docs.neoagent.io/integrations/psa/servicenow/creating-oauth-app Register the ServiceNow OAuth application Neo Agent connects with Neo Agent connects to ServiceNow with the OAuth 2.0 Authorization Code grant. You register a dedicated OAuth application in your own instance; Neo never sees your credentials directly. ## Creating the OAuth Application <Steps> <Step title="Find Application Registry"> In ServiceNow, use the navigation search (top left) to find System OAuth → Application Registry and open it. <Frame> <img alt="Searching for System OAuth, Application Registry" /> </Frame> </Step> <Step title="Create a new OAuth integration"> Click New (top right). When ServiceNow asks what kind of OAuth application, choose **New Inbound Integration Experience** (the first option). On the Inbound Integrations page, click New integration. <Frame> <img alt="Application Registry list page" /> </Frame> <Frame> <img alt="OAuth application kind selector" /> </Frame> <Frame> <img alt="Inbound Integrations list page" /> </Frame> </Step> <Step title="Pick the OAuth grant type"> Choose **OAuth - Authorization code grant** (the first option). <Frame> <img alt="OAuth application connection type selector" /> </Frame> <Info> Neo uses the Authorization Code grant so every action it takes (notes, state changes, time entries) is attributed to the OAuth user in your audit logs. The other grant types either lose user attribution or require Neo to know the user's password. </Info> </Step> <Step title="Configure the details and save"> Fill in the form: <ParamField type="string"> A clear name like `Neo Agent`. It appears in your audit logs whenever Neo authenticates. </ParamField> <ParamField type="string"> Exactly `https://dashboard.neoagent.io/oauth/servicenow/callback`. Extra trailing slashes or query parameters make the consent step fail. </ParamField> <ParamField type="integer"> Keep the default of `8,640,000` seconds (100 days). Shorter lifespans force more frequent reconnects. </ParamField> <ParamField type="integer"> Keep the default of `1800` seconds. Neo refreshes access tokens automatically. </ParamField> Leave Active checked and save. ServiceNow generates a **Client ID** and **Client Secret**. Copy both now, together with your instance URL (for example `https://acme.service-now.com`, no trailing slash). The connect step needs all three. <Frame> <img alt="OAuth application form filled in" /> </Frame> <Warning> Copy the Client Secret as soon as it is generated. In some configurations ServiceNow re-encrypts the field after you navigate away, and you have to regenerate it. </Warning> </Step> </Steps> ## Create the Neo service account The Authorization Code grant runs as a specific user, and every note, state change, time entry, and assignment is attributed to that user for the lifetime of the connection. Create a dedicated Neo Agent service account before you connect; do not reuse a personal admin account or a shared integration user. Create the user with: | Setting | Value | | - | - | | User name | `neo.agent`, display name `Neo Agent (Service Account)` | | Role | `itil`, so it can read and update task-family records, take assignments, and post customer-visible comments | | Table API read and write | `task` plus every subclass your agents work with: `incident`, `sc_request`, `sc_req_item`, `sc_task`, `change_request`, `problem` | | Table API read and write | `sys_journal_field` (notes), `task_time_worked` (time entries), `sys_user`, `sys_user_group` (assignment lookups), and any custom `u_*` columns your agents set | | Optional role | `email_api_send`, only if you plan to use Neo's "Email (sent via PSA)" notification mode | | Account state | Active = true, email notifications off | | Password | One you can sign in with; you log into ServiceNow as this user during the connect step | <Warning> The user who is signed in during OAuth consent becomes Neo's identity, not the user who created this OAuth app. If a different person is signed in when they click Allow, their account becomes Neo's identity. See the [connect step](/integrations/psa/servicenow/connecting-to-neo). </Warning> ## Keep Neo away from specific companies [Excluded companies](/integrations/psa/exclude-company-tickets) keeps a company's tickets out of Neo's sync and triggered agents. A scheduled agent or Chat Agent reads the PSA as the account Neo signs in with, so to keep those agents away from a company too, restrict that account. Neo signs in as its service account, so a ServiceNow administrator can hide a company from that account with a **before-query business rule** on the **task** table. ServiceNow also runs a task rule for queries on the tables that extend it (incident, sc\_request, sc\_req\_item, sc\_task, change\_request, problem), so one rule covers Neo's ticket searches. The rule runs only for Neo's service account and adds `current.addEncodedQuery('company!=<sys_id>^ORcompanyISEMPTY')`, so the company's records never come back and records with no company still do. A rule hides the company only on the tables it covers. Neo can also read related tables that do not extend task: comments and work notes, time worked, users and companies, catalog variables, interactions, CMDB records, attachments, SLAs and approvals. Add a rule to each one you need hidden; ServiceNow warns that many before-query rules can slow queries. An extra read ACL does not do this job: ServiceNow grants access when any matching ACL passes, so the ACLs Neo's role already has keep the company visible. Domain separation also works, but it changes the whole instance. ## What's Next? Proceed to [connect ServiceNow to Neo Agent](/integrations/psa/servicenow/connecting-to-neo). <Check> Before you proceed, verify: * The OAuth application is Active with the exact Redirect URL above * You saved the Client ID, the Client Secret, and your instance URL * The Neo Agent service account exists with the `itil` role and task-family table access * You know the service account's password; you sign in as it on the next page </Check> # Overview Source: https://docs.neoagent.io/integrations/psa/servicenow/overview Connect your ServiceNow instance to Neo Agent for automated ticket management Neo Agent connects to ServiceNow over OAuth 2.0 and emulates webhooks using a Business Rule and System Property — ServiceNow does not have native webhook support like ConnectWise or Halo, so Neo creates these artifacts on your behalf the first time you connect. Once connected, every insert and update on any task-family record — incidents, service requests, request items, catalog tasks, change requests, and problems — is POSTed to Neo's callback endpoint in real time, where it flows into the same event pipeline as Halo, ConnectWise, and Autotask tickets. ## Setup Steps <CardGroup> <Card title="1. Create the OAuth App" icon="key" href="/integrations/psa/servicenow/creating-oauth-app"> Create an OAuth Application Registry entry in your ServiceNow instance and copy the Client ID and Client Secret. </Card> <Card title="2. Connect to Neo" icon="plug" href="/integrations/psa/servicenow/connecting-to-neo"> Enter your instance URL and OAuth credentials in the Neo dashboard, consent in ServiceNow, and Neo provisions the webhooks automatically. </Card> </CardGroup> <Card title="Webhook Architecture (reference)" icon="webhook" href="/integrations/psa/servicenow/webhook-architecture"> Understand the Business Rule and System Property that Neo provisions in your ServiceNow instance, the payload it sends, and how to verify deliveries. </Card> ## Prerequisites Before connecting ServiceNow, ensure you have: * **Admin access** to your ServiceNow instance — required to create the OAuth Application Registry entry. * **A ServiceNow user account** that the agent will run as — typically a dedicated service account with the `itil` role and Table API read/write permissions on the task family. Neo's writes (notes, state changes, time entries) are attributed to this user in your audit trail. Add the `email_api_send` role too if you want Neo to be able to send outbound email via SN's `/api/now/v1/email` endpoint (the "Email (sent via PSA)" notification mode). * **A ServiceNow edition** with the `task` table family and OAuth 2.0 enabled (Standard, ITSM, or higher — all current editions qualify). * **The Neo Agent dashboard** at [dashboard.neoagent.io](https://dashboard.neoagent.io/integrations). ## Supported Ticket Types Neo treats every record that inherits from ServiceNow's `task` parent table as a ticket — agents read, write, search, and trigger workflows on each of the six stock subclasses uniformly: | Type | SN table | Number prefix | | - | - | - | | Incident | `incident` | `INC*` | | Request | `sc_request` | `REQ*` | | Request Item | `sc_req_item` | `RITM*` | | Catalog Task | `sc_task` | `TASK*` | | Change Request | `change_request` | `CHG*` | | Problem | `problem` | `PRB*` | Workflows can scope to specific types via the **Ticket Type** filter in the rules-builder (e.g., *"fire on incidents and changes only"*). Without a filter, a workflow trigger fires across every type. <Tip> If your instance uses plugin-gated subclasses (HR Service Delivery, Customer Service Management, Field Service Management, Security Incident, etc.), Neo currently treats those rows as generic tickets via the parent `task` table. Native enum support for plugin-gated types is filed as a follow-up — let your account team know if you need it prioritized. </Tip> ## Capabilities The integration covers the full ticket lifecycle on every supported type: * **Triage** — assignment group, urgency, impact, priority, category, subcategory, configuration item * **Notes** — `comments` (customer-facing) and `work_notes` (internal) journal appends * **State transitions** — open → in-progress → resolved → closed (using the right terminal state per type; change requests close via `state=4` to bypass the Change Model) * **Time entries** — written to `task_time_worked` and attributed to the OAuth user * **Custom fields** — read/write access to any `u_*` column on the row. A custom field condition in a ticket filter names the column, such as `u_asset_tag`; Neo also reads `asset_tag` as `u_asset_tag` and ignores case. Neo checks the name against the columns of an incident it can read. When the name matches no column, the run stops and your Inbox names the column, because ServiceNow would ignore that condition and return every ticket. When Neo can read no incident, the filter matches no ticket * **Webhook triggers** — real-time callbacks on insert and update for every task-family subclass On the agent's **Tickets** permission group, the **Fields** selector limits which ticket fields an update may change, such as State, Assignment Group or Assigned To. The ServiceNow sections of [PSA API](/agents/tools/psa/psa-api) list every option and what the list does not limit. ### Dependent choice lists ServiceNow can make one choice field depend on another: each `sys_choice` row names its parent in the `dependent_value` column, and only that parent's children are valid. `incident.subcategory` depends on `incident.category` this way. Triage reads that column. When it picks a subcategory, the options are narrowed to the subcategories configured under the category in effect for that run — the one triage just chose, or the one already on the ticket. A subcategory belonging to a different category is then not among them, and one already on the ticket that the narrowed list does not carry is replaced whenever the model names a replacement. The narrowing needs a category to scope by. When the ticket has none and the run does not set one, or when your instance has no subcategory configured under that category, triage offers the full subcategory list rather than an empty one, and the pair it writes is only as good as the model's reading of the ticket. Enable Category in the same Ticket Triage action so the run has a category to scope by. <Note> ServiceNow's Table API accepts a category/subcategory pair that its own configuration forbids, because `dependent_value` drives the UI picker rather than API validation. So the option list is the only place this can be enforced. </Note> This reads your instance live, so a dependent choice list you add or re-parent later is picked up with no configuration in Neo. ## How long does setup take? Most customers complete connection in under 10 minutes: * Creating the OAuth Application Registry entry: \~5 minutes * Connecting in the Neo dashboard and consenting: \~2 minutes * First sync run (in the background, no action needed): a few minutes depending on instance size The webhook artifacts (Business Rule + System Property) are created automatically the moment the OAuth flow completes — no manual ServiceNow configuration is required after the OAuth app exists. # Webhook Architecture Source: https://docs.neoagent.io/integrations/psa/servicenow/webhook-architecture How Neo Agent receives real-time ticket events from ServiceNow ServiceNow does not have native webhook support the way ConnectWise, Autotask, or Halo do. Instead of asking you to wire one up by hand, Neo Agent provisions a **Business Rule** plus a **System Property** in your ServiceNow instance the first time you connect — these together emulate a webhook. <Info> You don't need to configure anything in ServiceNow yourself. Both artifacts are created, kept up to date, and removed automatically when you connect or disconnect Neo Agent in the dashboard. </Info> ## What Neo Provisions When you connect ServiceNow, Neo creates two records in your instance: | Artifact | Table | Name | Purpose | | - | - | - | - | | System Property | `sys_properties` | `x_neoagent.callback_url` | Stores the Neo Agent callback URL. The Business Rule reads this at runtime so the URL can be updated without editing the script. | | Business Rule | `sys_script` | `Neo Agent — Task Webhook` | Fires `after` insert and update on the parent `task` table. POSTs the changed record to the callback URL above. Because every task-family subclass (incident, sc\_request, sc\_req\_item, sc\_task, change\_request, problem) inherits from `task`, a single rule captures all of them. | Both records are tagged in their description as **auto-managed; do not edit**. If you do edit them, Neo will overwrite your changes the next time it re-provisions. <Info> If your instance was connected before mid-May 2026, you may also have a legacy `Neo Agent — Incident Webhook` rule on the `incident` table. Neo's re-provisioning step deletes it automatically on the next reconnect; if you've never reconnected, you can safely delete it yourself — the new task-table rule supersedes it. </Info> ## The Webhook Payload Each insert or update on any task-family record POSTs a JSON body shaped like this: ```json theme={null} { "sys_id": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "number": "INC0010001", "sys_mod_count": "7", "table": "incident", "action": "insert", "current": { "short_description": "Printer is offline", "description": "User reports the 3rd-floor MFP is unresponsive.", "state": "1", "priority": "3", "urgency": "2", "impact": "3", "assignment_group": "<sys_id>", "assigned_to": "<sys_id>", "caller_id": "<sys_id>", "company": "<sys_id>", "category": "hardware", "sys_updated_on": "2026-04-29 14:30:00", "sys_created_on": "2026-04-29 14:30:00" }, "previous": { "state": "1", "priority": "2", "assignment_group": "<sys_id>", "assigned_to": "<sys_id>" } } ``` * `table` reflects the row's actual `sys_class_name` — one of `incident`, `sc_request`, `sc_req_item`, `sc_task`, `change_request`, or `problem`. Workflow triggers can filter on this via the **Ticket Type** rule in the rules-builder. * `number` carries the corresponding human-friendly prefix: `INC*`, `REQ*`, `RITM*`, `TASK*`, `CHG*`, or `PRB*`. * `sys_mod_count` is ServiceNow's monotonic per-record version counter. Neo uses it to tiebreak the rare case where two updates land on the same record inside the same wall-clock second — without it the two callbacks would collide and one diff would be lost. Older Business Rule revisions (pre-v2) don't emit this field; Neo accepts both shapes. * `action` is `"insert"` for newly created rows and `"update"` for any field change. * `previous` is only included on updates and reflects the values immediately before the change. * All reference fields (`assignment_group`, `caller_id`, `company`, etc.) are sent as ServiceNow `sys_id`s — Neo resolves them on the receiving side. * Subclass-specific fields (`urgency`, `impact`, `caller_id`, `category`) only exist on `incident`; on other subclasses they come back as empty strings — Neo treats those as `null` and ignores them in workflow matching. ## Locating the Artifacts in ServiceNow If you ever need to inspect or temporarily disable the integration from the ServiceNow side: <Steps> <Step title="Find the System Property"> Navigate to **System Properties → All Properties** (or browse to `sys_properties.list`) and filter by `Name` `is` `x_neoagent.callback_url`. The **Value** column shows the exact URL Neo Agent will be POSTed to. </Step> <Step title="Find the Business Rule"> Navigate to **System Definition → Business Rules** (or browse to `sys_script.list`) and filter by `Name` `is` `Neo Agent — Task Webhook`. The rule should be **Active**, run **after** insert and update on the `task` table. </Step> <Step title="Disable temporarily (optional)"> To pause webhook delivery without disconnecting Neo Agent, untick **Active** on the Business Rule. Re-tick it to resume. <Warning> Disabling the Business Rule stops all event delivery to Neo Agent. Any automation that depends on ticket events — across every task-family subclass, not just incidents — will idle until it is re-enabled. </Warning> </Step> </Steps> ## Delivery Semantics — Best-Effort The Business Rule POSTs the webhook payload using ServiceNow's `RESTMessageV2.executeAsync()` so the user save in ServiceNow doesn't block on Neo's response. This is by design — without it, every save would wait for Neo's Azure Functions to reply, which would add visible latency to technician edits. The trade-off: * **No automatic retries on Neo's side.** If Neo's endpoint returns 4xx/5xx, is restarting, or is temporarily unreachable, ServiceNow does not retry the delivery. The event is lost from the Business Rule's perspective. * **No 4xx/5xx body capture in the Business Rule's logs.** `executeAsync` doesn't expose the response synchronously, so `[NeoAgent]` syslog entries cover errors raised during the script itself (missing System Property, exception inside the rule) but not Neo-side rejections. For comparison: ConnectWise, Autotask, and Halo all retry failed deliveries on their side. ServiceNow does not, so the loss window is exactly the duration of any Neo-side outage. In practice, callbacks landing during a Neo outage are rare and have a self-correcting fallback: the next legitimate update on the same record sends a fresh callback that carries the current state. If you suspect a missed event, edit the affected record (e.g. add a one-character work note, then revert) to force a new callback. ## Verifying Deliveries ServiceNow logs every Business Rule execution. To confirm webhooks are firing: 1. Navigate to **System Logs → All** (or browse to `syslog.list`). 2. Filter by `Message` contains `[NeoAgent]` to see entries written by the rule. These cover rule-side errors only (missing callback URL, exceptions inside the script). Successful deliveries and Neo-side response codes are not logged here because `executeAsync` is fire-and-forget — see the **Delivery Semantics** section above. 3. Update any task-family record — change priority, state, or assignment on an incident, request item, change request, etc. 4. If nothing is logged and Neo doesn't see the event, check the **REST Outbound** logs at `sys_outbound_rest_message_log.list` for the most recent POST to the Neo callback URL. The response status is captured by SN's outbound logging even though the Business Rule itself doesn't inspect it. ## Troubleshooting <AccordionGroup> <Accordion title="No events reach Neo Agent"> * Confirm the **Active** flag on the Business Rule is set to `true`. * Confirm the System Property value is non-empty and points at a `https://...neoagent.io/callback/servicenow?...` URL. * Check `sys_outbound_rest_message_log` for a recent attempt — if the POST is failing with a `401` or `403`, the token in `?code=` is stale. Disconnect and reconnect ServiceNow in the Neo dashboard to refresh it. </Accordion> <Accordion title="OAuth refresh failed"> ServiceNow refresh tokens are long-lived (default 100 days) but can be revoked when the OAuth Application Registry is regenerated or the user who consented loses admin rights. If Neo reports an authentication failure in the inbox, the fix is to reconnect ServiceNow from the Neo dashboard — this re-runs the OAuth Authorization Code flow and captures a fresh refresh token. </Accordion> <Accordion title="Webhook fires too often"> The Business Rule fires on every update, including system-driven updates from workflows or other Business Rules. If you only want to react to specific changes, raise a ticket with us — Neo can filter at the receive side, but we may also be able to tighten the rule's `condition` field for your instance. </Accordion> <Accordion title="Disconnect leaves orphaned artifacts"> Disconnecting ServiceNow in the Neo dashboard runs an unprovision step that deletes both the System Property and the Business Rule. If you can still see them after disconnecting, the unprovision call failed mid-flight — open the artifacts and delete them manually, or reconnect and disconnect once more. </Accordion> </AccordionGroup> ## Related Pages * [ServiceNow Overview](/integrations/psa/servicenow/overview) # Switching your PSA Source: https://docs.neoagent.io/integrations/psa/switching-psa Move Neo from one PSA to another — disconnect the old one, connect the new one, and bring your workflows and agents across Neo connects to one PSA at a time. To move from one to another, disconnect the first, then connect the second. ## Before you disconnect Disable every workflow and agent that uses the PSA. Left enabled, they do not quietly stop matching — each fires on tickets and fails on every one. That is the only thing that cannot wait. Everything else below needs the new PSA connected anyway. ## Disconnect your current PSA <Steps> <Step title="Sign in as the workspace owner"> Only the owner can disconnect a PSA — leaving one is a decision about the business, so it sits with the owner, beside owner management. Anyone else who selects **Disconnect** is told the owner holds it, and nothing changes. </Step> <Step title="Open your PSA on the Integrations page"> Go to [**Integrations**](https://dashboard.neoagent.io/integrations) and select your connected PSA. </Step> <Step title="Select Disconnect"> **Disconnect** sits beside **Edit** on the connection card. </Step> <Step title="Decide what happens to your ticket history"> **Keep my ticket history** is selected for you. Leave it selected and Neo keeps its copy of the tickets it already synced, so your agents can search them to find how a similar problem was solved. Clear it and Neo deletes that copy. Your PSA keeps its own records either way, but nothing brings Neo's copy back — a new sync reads the new PSA, and cannot reach the PSA you have left. </Step> <Step title="Type the PSA name, then confirm"> Type the name of the PSA you are leaving to enable the button. Neo stops reading tickets from it straight away. </Step> </Steps> ## What Neo does for you * Turns off the old PSA's webhooks, so it stops sending ticket events. * Resets the sync timestamps, so the new PSA's first sync reads your companies, contacts and users in full. * Removes the old PSA's stored credentials. * Keeps or deletes Neo's copy of the tickets it already synced, whichever you chose on the modal. * Clears the old PSA's companies, so your company list is read fresh from the new PSA instead of holding entries that point at a PSA you no longer use. Your company exclusions and Microsoft 365 links go with them — see [Build your workflows and agents again](#build-your-workflows-and-agents-again). <Note> Moving **to ServiceNow** is one exception. You sign in to ServiceNow in the browser, and that sign-in replaces the stored PSA address before the disconnect runs, so the old PSA's webhooks need removing by hand on that PSA. </Note> ## Connect the new PSA Return to [**Integrations**](https://dashboard.neoagent.io/integrations), select your new PSA, and follow its setup guide — [Autotask](/integrations/psa/autotask/connecting-to-neo), [ConnectWise](/integrations/psa/connectwise/connecting-to-neo), [HaloPSA](/integrations/psa/halopsa/connecting-to-neo), [ServiceNow](/integrations/psa/servicenow/connecting-to-neo) or [Syncro](/integrations/psa/syncro/connecting-to-neo). Create the Neo user in the new PSA first; each guide says what it needs. A large PSA takes a few hours for its first sync. ### Start the first sync yourself Neo's scheduled sync runs overnight, between 23:00 and 03:59 in your own timezone. So if you connect during the day and wait, nothing usually happens until that night. Select **Trigger sync** on the integration to start one now. It brings in your companies and contacts straight away. Your **tickets** are not part of that manual run after a switch, because Neo counts the syncs your old PSA completed and treats this as a routine re-sync rather than a first one. They arrive with the first overnight sync. Until a sync starts, the integration's badge reads **Ready to sync**. ### What you see while it runs Callbacks are the last thing a sync does, after your companies, contacts and tickets. So under **Advanced settings → PSA callbacks**, the callback reads **Pending events** for as long as the import runs, and does not send Neo your ticket changes until the sync subscribes them. Judge it by the sync rather than by the clock: while the badge says **Sync in progress**, nothing is wrong. Tell us if the sync reports **Sync failed**, or if it finished and the callback still reads **Pending events**. ## Rebuild your workflows, keep your chat agents This part needs the new PSA connected, because every picker offers only the connected PSA's fields. **A workflow or agent that fires on tickets has to be built again.** Its filter is written in your old PSA's vocabulary — a ConnectWise board or sub-type has no Autotask equivalent, and a board, status or queue is stored as the number the old PSA gave it. Neither is in any dropdown once the new PSA is connected, so there is nothing to point them at. Build each one again, then delete the old. **A chat agent or scheduled agent you keep.** Neither has a ticket filter. Grant it the new PSA's permissions, re-choose any setting that names a PSA record, and enable it again. The old PSA's permissions can stay as they are; Neo stops offering that PSA's tools once a different one is connected. Never delete and recreate one that is bound to a Microsoft Teams channel: the channel points at that agent, so a replacement is a different agent and the channel stops reaching one. An agent that never touches your PSA needs nothing. ### Let your Neo Support Agent do it You do not have to work through these yourself, or wait for our team. Your [**Neo Support Agent**](/chat-agents/neo-support-agent) — on the [**Chat**](https://dashboard.neoagent.io/chat) page and in Microsoft Teams — reads your actual configuration, so it can tell you what in *your* workspace still names the old PSA, and do the work: > Rebuild my Ticket Triage workflow on our new Autotask connection. Give it **one workflow or agent at a time**. Naming the old one is usually enough, and it creates each replacement **disabled** — review it, then enable it yourself. Expect it to ask which board, queue or status to use — the new PSA's records are not the old one's, so that choice is yours. ### Company exclusions and Microsoft 365 links Your companies are read fresh from the new PSA, so a company you had excluded comes back **included** and Neo starts working its tickets. This is the one item that changes what Neo acts on by itself, so redo it before your new PSA's first sync finishes if you can. On the [Companies](https://dashboard.neoagent.io/end-companies) page, exclude the companies you do not want Neo to manage, and re-link any company you had connected to Microsoft 365. Your customers' Microsoft consent still stands in their own tenants — Neo asks for the link again, not for the consent. ### The phone agent If you use the [phone agent](/phone-agent/intro), it also holds identifiers from the old PSA for the company, queue, status and source it writes to. This one your Neo Support Agent cannot do — contact our support team and we will repoint them. ## Switching to a different instance of the same PSA Moving between two instances of the *same* PSA — sandbox to production, or one ConnectWise instance to another — changes every record ID, so the old instance's data no longer matches anything. Disconnect and reconnect exactly as above. **Your workflows and agents need every stored record checked.** This case is lighter than a move to a different PSA. The field names survive, because the PSA is the same, so the pickers still offer them and nothing has to be built from scratch. What does not survive is the IDs: every board, queue, status, priority and type is stored as the number the old instance issued, and the new instance issues its own. A workflow kept from the sandbox points at records production does not have. So open each workflow and agent and re-select every PSA record it names, rather than rebuilding it. Your Neo Support Agent can do this pass for you as well. Clear **Keep my ticket history** when you disconnect. The old instance's tickets point at IDs the new instance does not have, so keeping them leaves your agents searching records nobody can open. # Configuring Webhooks Source: https://docs.neoagent.io/integrations/psa/syncro/configuring-webhooks Create the Syncro Notification Set that sends ticket events to Neo Agent in real time This is the last step of the Syncro setup, and the one you have to do yourself. Syncro has no API for creating webhooks, so unlike ConnectWise, Autotask and HaloPSA — where Neo creates the webhook for you when you connect — this one is created by hand, once, in the Syncro admin UI. Do it before you put the integration to work. Without it, Neo only sees ticket changes on its scheduled sync, so agents and workflows that trigger on a ticket event fire on the next sync rather than as the event happens. ## Step 1 — Copy your webhook URL from the Neo dashboard Neo shows the URL — with these setup steps — right after you first connect Syncro. After that, find it any time on **Integrations → Syncro**: the **Webhook URL** row on the connected card (click **Setup guide**), or **Advanced settings → Webhook URL**. The URL is unique to your account. Only dashboard admins can see it. <Warning> Treat the URL as a credential — anything holding it can post ticket events into your Neo tenant. Don't share it outside your team, and paste it only into the Syncro field below. If it may have leaked, click **Generate new URL…** next to it — the old URL stops working immediately, so paste the replacement into Syncro right away. </Warning> ## Step 2 — Open the Notification Center In Syncro, go to **Admin → Syncro Administration → Notification Center**, then click **+ New Notification Set**. <Frame> <img alt="Notification Sets Manager in Syncro with the New Notification Set button" /> </Frame> ## Step 3 — Name it and paste the URL Name it something recognisable — `Neo Agent Webhook` — and paste your URL into **Webhook URL**. <Frame> <img alt="The Edit Notification Set form showing Name, Notify these Users, and Webhook URL fields" /> </Frame> <Warning> Leave **Notify these Users**, **Additional Emails to notify** and **Additional SMS Notify** empty. This set fires on every ticket event across your whole account. Naming a user here would email or text them each time — and as the page itself warns, those count toward your Syncro usage limits. Neo only needs the webhook. </Warning> ## Step 4 — Tick the four events, in the Webhook column only The event list has five columns — Email, SMS, In-App Notify, Mobile Push Notification, and **Webhook**. Tick **only the Webhook column**, for these four events: | Event | What Neo does with it | | - | - | | **Ticket - created (for anyone)** | Triggers agents and workflows that run on new tickets | | **Ticket - Status was changed on any Ticket** | Triggers agents and workflows that run when a ticket's status changes | | **Ticket - A customer-facing comment was added to any Ticket** | Distinguishes a customer reply from a technician reply | | **Ticket - A hidden comment was added to any Ticket** | Internal notes — never treated as a reply to the customer | <Warning> Pick the **"any Ticket"** variants, not the "my Ticket" or "subscribed Ticket" ones. Those two only fire for tickets assigned to — or subscribed by — the user the notification set belongs to. Neo is neither, so they would almost never fire and the integration would look broken while quietly missing events. </Warning> Save the set. ## Step 5 — Confirm it works Create a test ticket in Syncro, or change the status of an existing one. Within a few seconds it should appear in Neo: * Open the ticket's execution history in the Neo dashboard, or * Check whether an agent configured to trigger on that event ran. If nothing arrives, work through the table below. ## Troubleshooting | Symptom | Cause | | - | - | | No events reach Neo at all | The URL is wrong or incomplete — it must be pasted whole, including everything after the `?`. Re-copy it rather than retyping. | | Nothing fires, but the set looks right | You ticked a column other than **Webhook**, or you picked a "my Ticket" / "subscribed Ticket" event. | | Only new tickets arrive | Only **Ticket - created** was ticked. Add the other three. | | Status changes arrive but comments don't | The two comment events are separate — both need ticking, customer-facing *and* hidden. | | A technician gets emailed on every ticket | A user is named under **Notify these Users**, or an address sits in **Additional Emails**. Clear both. | ## What Neo does not receive Only the four events above are sent, so nothing else reaches Neo in real time — assignment changes, priority changes, time entries, and attachments included. Those still reach Neo through the scheduled sync; they just aren't instant. Adding more events is safe, and Neo won't break on one it doesn't recognise — it treats an unfamiliar event as a general ticket update. But it won't gain a new trigger from it either, so there's no benefit unless a Neo release says otherwise. The status-change event reports the **new** status only, not the previous one. Build status triggers on the new status ("changed to Resolved"). A trigger that also pins the old status ("from In Progress to Resolved") won't fire on Syncro. # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/psa/syncro/connecting-to-neo Enter your Syncro URL and API token in the Neo Agent dashboard Before you start, create your API token: [Creating an API Token](/integrations/psa/syncro/creating-api-token). <Steps> <Step title="Open Syncro in the Neo dashboard"> In the [Neo dashboard](https://dashboard.neoagent.io/integrations), open **Integrations**, switch to the **Directory** tab, and select Syncro. The connect page walks you through the setup one step at a time, with a step rail on the left; returning users land on the filled form. <Frame> <img alt="Syncro in the Neo integrations directory" /> </Frame> </Step> <Step title="Enter your credentials"> On the "Enter connection details" step, fill in the two fields: <Frame> <img alt="The Connect Syncro form" /> </Frame> <ParamField type="string"> The Custom token you created in Syncro. </ParamField> <ParamField type="string"> Exactly `https://<subdomain>.syncromsp.com`. </ParamField> Click **Save & run checks**. Neo saves the token only if it authenticates against Syncro; if something is wrong, the error names what to fix in Syncro. <Note> There is no username field. Syncro tokens identify their own user, so Neo reads that from Syncro and shows it as the connected account. </Note> </Step> <Step title="Watch the verification checks"> After the save, Neo runs its verification checks one by one: authentication, the identity Neo acts as, ticket read access, write access, the webhook registration, and data sync. Each check reports as it completes. <Check> All checks green means Neo can read and write tickets, receives ticket events, and has synced your data. A failed check names what to fix in Syncro, and you can run the checks again without re-entering the token. </Check> </Step> <Step title="Copy the webhook URL Neo shows you"> When you click **Continue** after the checks, Neo opens the "One more step — connect Syncro webhooks" dialog, which contains your webhook URL. Copy it and paste it into a Syncro Notification Set. [Configuring Webhooks](/integrations/psa/syncro/configuring-webhooks) is the full walkthrough. <Note> Do this before you put the integration to work. Until the Notification Set exists, ticket events only reach Neo on the scheduled sync. </Note> If you close the dialog, nothing is lost. The URL stays on the Syncro card in two places: click **Setup guide** to reopen the dialog, or open **Advanced settings**. It contains a credential, so only dashboard admins can see it. </Step> <Step title="Confirm the first sync"> Saving the integration starts the first sync, and the data-sync check above reflects it. The Syncro integration page shows the sync status, and **Trigger sync** starts one manually. The first sync pulls in your tickets, customers, contacts, ticket statuses and ticket types. Once it completes, your Syncro companies appear under **Companies** and your Syncro users under **Technicians**. </Step> </Steps> ## Troubleshooting | Symptom | Cause | Fix | | - | - | - | | "Could not authenticate against Syncro" | Wrong subdomain, or the token is inactive or expired | Check Admin → API → API Tokens in Syncro | | "This Syncro API token is limited to its own tickets" | The token's user has the "mine only" ticket restriction | Clear the restriction, or use a token from a user without it | | "This Syncro API token is missing permissions" | The token lacks required permissions | Grant the named permissions. Syncro only lets you tick permissions the token's own user holds | | "This API token belongs to the Syncro tenant *x*, but the URL points at *y*" | The token and URL are from different Syncro accounts | Use the token from the same account as the URL | | Sync succeeds but covers fewer tickets than expected | The "mine only" restriction, or company filters excluding customers | Check Company filters on the integration page | ## Changing the token later Open the Syncro integration and click **Edit**. The API key is masked. Leave it as-is to keep the stored token, or paste a new one to replace it. Do this before the token's expiry date if you set one. ## Next Steps <Card title="Configuring Webhooks" icon="webhook" href="/integrations/psa/syncro/configuring-webhooks"> Point a Syncro Notification Set at Neo so ticket events arrive in real time. </Card> # Creating an API Token Source: https://docs.neoagent.io/integrations/psa/syncro/creating-api-token Create a dedicated Syncro user for Neo Agent and generate a Custom API token with the right permissions Syncro authenticates with a single API token. Unlike ConnectWise or Autotask, Syncro has no API-only user type: every token belongs to a real Syncro user, and everything the token does is recorded as that user's work. <Warning> Create a dedicated Syncro user for Neo first, and generate the token while signed in as that user. Without one, Neo's comments, ticket edits and time entries appear as a named technician's own work. The token also dies with the user: deactivate that person and the integration stops. </Warning> ## Before you start Complete [Creating a Security Group](/integrations/psa/syncro/creating-security-group) first. The `Neo Agent SG` group must exist and be assigned to your Neo user. <Note> Syncro limits a token to the permissions of the user creating it: *"The permissions available for selection are limited by the permissions of the current user."* The Neo user must already hold every permission you want on the token; anything it lacks is greyed out. </Note> <Steps> <Step title="Open API Tokens"> Signed in as the Neo user, go to Admin → API → API Tokens. <Frame> <img alt="Admin → API → API Tokens in Syncro" /> </Frame> </Step> <Step title="Create a new token"> Click **New Token**. <Frame> <img alt="The New Token button on the API Tokens page" /> </Frame> </Step> <Step title="Choose Custom Permissions"> Select the **Custom Permissions** tab, not App Integration. Name the token `Neo Agent`. <Frame> <img alt="The New Token screen with the Custom Permissions tab selected" /> </Frame> <Warning> Expiration: leave it blank for a token that does not expire, or set a date and diarise the renewal. Syncro tokens are static, with no refresh. When a token expires, the integration stops working until you paste a new one into Neo. </Warning> </Step> <Step title="Select the token permissions"> Tick **Select All Permissions**. Syncro only offers permissions the Neo user holds, so "all" means all of the security group you scoped in the previous step; nothing beyond it can be granted. <Tip> Selecting all also means you never revisit the token as you enable more automations in Neo. To tighten or widen what Neo can reach, change the security group; that is the single place access is controlled. </Tip> <Accordion title="If you would rather tick individual boxes"> Neo refuses to save a token without these seven: * Tickets - List/Search * Tickets - View Details * Tickets - Create * Tickets - Edit * Ticket Comments - New * Customers - List/Search * Customers - View Detail The rest back capabilities you can enable later in the dashboard (time logging, scripts, RMM alerts, documentation, billing reads). Granting them now means you do not have to come back to the token. **Tickets** * Tickets - List/Search * Tickets - View Details * Tickets - View 'Their Ticket' Details (assigned to them) * Tickets - Create * Tickets - Edit * Tickets - Merge * Tickets - Use Ticket Charges * Ticket Comments - New * Ticket Custom Fields - Manage * Ticket Canned Responses - Manage * Ticket SLA - Edit * Ticket Blueprints - Manage * Ticket Blueprints - Create Ticket From Blueprint * Ticket Timers - Overview * Timelogs - Manage **Customers and contracts** * Customers - List/Search * Customers - View Detail * Contracts - List/Search * Contracts - Edit **Assets, RMM and scripts** * Assets - List/Search * Assets - View Details * RMM Alerts - List * RMM Alerts - Create * RMM Alerts - Clear/Manage * Scripts - Execute * Policies - List **Billing and inventory** * Products - List/Search * Products - Create * Products - Edit * Products - Edit Quantities * Products - View Cost * Pending Orders - View All * Estimates - List/Search * Estimates - View Details * Estimates - Create * Estimates - Edit * Invoices - List/Search * Invoices - View Details * Line Item - View Cost **Other** * Appointments - View All (see-own never restricted) * Documentation - Allow Usage * Documentation - Create * Documentation - Edit * Reports - View </Accordion> </Step> <Step title="Save and copy the token"> Save the token, then copy its value from the tokens list. Paste it straight into Neo. Syncro will not show it again in full. </Step> </Steps> Neo validates the token when you connect and names anything missing. The [troubleshooting table on the connect page](/integrations/psa/syncro/connecting-to-neo#troubleshooting) lists the exact messages. ## Next Steps <Card title="Connecting to Neo Agent" icon="link" href="/integrations/psa/syncro/connecting-to-neo"> Enter your Syncro URL and this token in the Neo dashboard. </Card> # Creating a Security Group Source: https://docs.neoagent.io/integrations/psa/syncro/creating-security-group Create a Syncro security group for Neo Agent with the permissions it needs, then assign it to the Neo user Start here. Syncro limits an API token to the permissions of the user who creates it. The Neo user must therefore hold everything you want the token to have, and that comes from its security group. <Steps> <Step title="Open Security Groups"> In Syncro, go to Admin → Syncro Administration → Security Groups, then create a new group. <Frame> <img alt="Security Groups under Syncro Administration in the Admin menu" /> </Frame> </Step> <Step title="Name the group and set Access Type to All Customers"> Name it `Neo Agent SG`. Under Access Type, leave **All Customers** selected. <Frame> <img alt="The New Security Group form with All Customers selected" /> </Frame> <Warning> Choose "All Customers" unless you must keep Neo away from specific customers. "Select Customers" scopes the group to the customers you list, so Neo syncs and automates only those, and a new customer stays hidden until you add it. See [Keep Neo away from specific customers](#keep-neo-away-from-specific-customers) below. </Warning> </Step> <Step title="Tick the permissions"> Every permission is off by default. Open each group below and tick the chips listed; anything not listed stays off. Then create the group as the final section describes. </Step> </Steps> ## Permissions <AccordionGroup> <Accordion title="Tickets"> The core of the integration. <div> <div><div>Tickets</div><div><span>Create</span><span>Edit</span><span>List/Search</span><span>Merge</span><span>Use Ticket Charges</span><span>View Details</span><span>View Their Ticket Details (Assigned To Them)</span></div></div> <div><div>Ticket Comments</div><div><span>New</span><span>Shareable Calendar Links (Manage)</span></div></div> <div><div>Ticket Custom Fields</div><div><span>Manage</span></div></div> <div><div>Ticket Tags</div><div><span>Create</span><span>View</span></div></div> <div><div>Ticket SLA</div><div><span>Edit</span></div></div> <div><div>Ticket Parent-Child</div><div><span>Edit</span></div></div> <div><div>Ticket Attachments</div><div><span>View</span></div></div> <div><div>Ticket Canned Responses</div><div><span>Manage</span></div></div> <div><div>Ticket Blueprints</div><div><span>Create Ticket From Blueprint</span><span>Manage</span></div></div> <div><div>Ticket Workflows</div><div><span>Manage</span></div></div> <div><div>Ticket Worksheets</div><div><span>Add</span><span>Manage</span></div></div> <div><div>Ticket Automations</div><div><span>Create</span><span>List</span><span>Run Now</span></div></div> <div><div>Recurring Tickets</div><div><span>Create</span><span>Edit</span><span>List</span></div></div> </div> </Accordion> <Accordion title="Time tracking"> <div> <div><div>Ticket Timers</div><div><span>Add For Another Technician</span><span>Overview</span><span>Toggle Time Entry Billable State</span></div></div> <div><div>Timelogs</div><div><span>Manage</span></div></div> </div> </Accordion> <Accordion title="Customers and contacts"> <div> <div><div>Customers</div><div><span>Edit</span><span>List/Search</span><span>View Detail</span></div></div> <div><div>Customer Tags</div><div><span>Create</span><span>View</span></div></div> <div><div>Customer Mapping</div><div><span>View</span></div></div> <div><div>Contact Tags</div><div><span>Create</span><span>View</span></div></div> <div><div>Contracts</div><div><span>Edit</span><span>List/Search</span></div></div> </div> <Note> Contacts has only Export and Import options; leave both off. Neo reads contacts through the customer permissions above, so there is no separate contact-view permission to find. </Note> </Accordion> <Accordion title="Assets and RMM"> <div> <div><div>Assets</div><div><span>Allow Backgrounding Tools</span><span>Assets Pending Approval</span><span>Bulk Script Execute</span><span>Edit</span><span>Install Windows Patches Manually</span><span>List/Search</span><span>Reboot</span><span>View Archived Assets</span><span>View Details</span><span>View Thumbnail</span><span>Wake On Lan</span></div></div> <div><div>Asset Custom Fields</div><div><span>Create</span><span>Edit</span><span>View</span></div></div> <div><div>RMM Alerts</div><div><span>Clear/Manage</span><span>Create</span><span>List</span></div></div> <div><div>Automated Remediation</div><div><span>Create</span><span>Edit</span><span>List</span></div></div> <div><div>Policies</div><div><span>List</span></div></div> <div><div>Network Discovery</div><div><span>Run Profile</span><span>View Profile</span></div></div> </div> <Note> Assets → Create, Delete, Archive, Allow Remote Access and Edit Policy stay off. Neo works on assets Syncro already knows about. </Note> </Accordion> <Accordion title="Scripts"> <div> <div><div>Scripts</div><div><span>Edit</span><span>Execute</span><span>Favorite</span><span>List</span><span>New</span></div></div> <div><div>Script Categories</div><div><span>Edit</span><span>List</span><span>New</span></div></div> <div><div>Script Categories Access</div><div><span>All Categories</span></div></div> </div> </Accordion> <Accordion title="Billing and inventory"> Needed only if you want Neo to reason about billing. Safe to leave off otherwise. <div> <div><div>Products</div><div><span>Create</span><span>Edit</span><span>Edit Quantities</span><span>List/Search</span><span>View Cost</span></div></div> <div><div>Estimates</div><div><span>Create</span><span>Edit</span><span>List/Search</span><span>View Details</span></div></div> <div><div>Invoices</div><div><span>List/Search</span><span>View Details</span></div></div> <div><div>Purchase Orders</div><div><span>List/Search</span><span>View Details</span></div></div> <div><div>Parts Orders</div><div><span>List/Search</span><span>View</span></div></div> <div><div>Line Item</div><div><span>View Cost</span></div></div> </div> <Note> Invoices are read-only here: no Create, Edit, Delete or Refund. Neo can reference invoices without being able to change what a customer is billed. </Note> </Accordion> <Accordion title="Other"> <div> <div><div>API Tokens</div><div><span>Manage</span></div></div> <div><div>Appointments</div><div><span>View All (See-Own Never Restricted)</span></div></div> <div><div>Documentation</div><div><span>Allow Usage</span><span>Create</span><span>Edit</span></div></div> <div><div>Reports</div><div><span>View</span></div></div> </div> <Warning> API Tokens → Manage is required. Without it the Neo user cannot create its own API token, and you would have to create the token as an admin, which binds it to the admin account and defeats the point of a dedicated user. </Warning> </Accordion> </AccordionGroup> ## Create the group and assign it Click **Create Group**. Then create your dedicated Neo user (or edit it) and set its security group to `Neo Agent SG`. ## Keep Neo away from specific customers [Excluded companies](/integrations/psa/exclude-company-tickets) keeps a company's tickets out of Neo's sync and triggered agents. A scheduled agent or Chat Agent reads the PSA as the account Neo signs in with, so to keep those agents away from a company too, restrict that account. In Syncro, set the Neo security group's **Access Type** to **Select Customers** and move every customer except the ones to hide into **Accessible**. Syncro says a group scoped this way cannot use Billing & Invoicing, Chat, Calendar, Documentation, Leads, Mailer, Policies or script creation, so Neo loses those features for every customer ([Security Groups](https://docs.syncrosecure.com/security/security-group)). ## Next Steps <Card title="Creating an API Token" icon="key" href="/integrations/psa/syncro/creating-api-token"> Sign in as the Neo user and generate the API token. </Card> # Overview Source: https://docs.neoagent.io/integrations/psa/syncro/overview Connect Syncro to Neo Agent for automated ticket management and workflow automation ## Setup Overview Setting up the Syncro integration involves four steps, in this order: <CardGroup> <Card title="1. Creating a Security Group" icon="shield-halved" href="/integrations/psa/syncro/creating-security-group"> Create a Syncro security group with the permissions Neo needs, and assign it to a dedicated Neo user. </Card> <Card title="2. Creating an API Token" icon="key" href="/integrations/psa/syncro/creating-api-token"> Signed in as the Neo user, generate a Custom API token. </Card> <Card title="3. Connecting to Neo Agent" icon="link" href="/integrations/psa/syncro/connecting-to-neo"> Enter your Syncro URL and API token in the Neo dashboard, then verify the first sync. </Card> <Card title="4. Configuring Webhooks" icon="bolt" href="/integrations/psa/syncro/configuring-webhooks"> Create a Syncro Notification Set so ticket events reach Neo as they happen. This is the one step Neo cannot do for you. </Card> </CardGroup> <Warning> The order matters. Syncro limits an API token to the permissions of the user creating it, so the security group has to exist and be assigned to the Neo user *before* you generate the token — otherwise the permissions you need are greyed out and cannot be ticked. </Warning> <Warning> **Step 4 is set up by hand, and the integration isn't finished without it.** Syncro has no API for creating webhooks, so Neo can't create one for you the way it does for ConnectWise, Autotask and HaloPSA — you create the [Notification Set](/integrations/psa/syncro/configuring-webhooks) yourself, once, in Syncro. Until it exists, Neo only sees ticket changes on its scheduled sync, so event-triggered agents fire on the next sync instead of the moment something happens. </Warning> ## How Permissions Work Neo Agent uses **two layers of access control**, and both have to allow something before it happens. The Syncro API token's Custom Permissions decide which areas of Syncro Neo can reach at all. Within that, the Neo Agent dashboard decides what Neo actually does — which areas it reads, which it writes to, which it leaves alone, and whether an action needs technician approval first. So ticking a permission on the token does not put it to use. It makes the matching capability available to switch on in the dashboard, and until you switch it on, Neo leaves that area alone. On the agent's **Tickets** permission group, the **Fields** selector limits which ticket fields an update may change, such as Status, Priority or Assigned Technician. The Syncro section of [PSA API](/agents/tools/psa/psa-api) lists every option and what the list does not limit. ## Prerequisites * **Admin access** to Syncro (the **Admin** tab) * **An available Syncro user seat** for the dedicated Neo user — see [Creating an API Token](/integrations/psa/syncro/creating-api-token) for why a dedicated user matters * **Your Syncro URL**, in the form `https://<subdomain>.syncromsp.com` # Connecting QuoteWerks to Neo Source: https://docs.neoagent.io/integrations/quotewerks/connecting-to-neo Create a QuoteWerks Web API key and save it in Neo You connect QuoteWerks once at the MSP level. One API key covers your whole QuoteWerks Web account. ## 1. Create the API key <Steps> <Step title="Open Zapier and API"> Sign in to QuoteWerks Web as a user with Master Rights and open **Setup > Options > Zapier and API**. </Step> <Step title="Create a key"> Click **New**, enter a description such as "Neo", and click **OK**. </Step> <Step title="Allow writes, if Neo should create quotes"> Open the key and turn on **Allow write access**. Without it Neo can read, and every create or update is refused by QuoteWerks. </Step> <Step title="Copy the key"> Click the key in the list to copy it. </Step> </Steps> <Warning> Do not delete the key in QuoteWerks after you connect it. Neo loses access until you save a new key here. </Warning> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the QuoteWerks card, under Sales & Quoting. </Step> <Step title="Save the key"> Paste the API key and click **Save**. Neo checks it against QuoteWerks before saving, so a wrong key is rejected straight away. </Step> </Steps> ## 3. Turn QuoteWerks on per agent Open the agent, go to the Integrations section, and configure the QuoteWerks block. Pick a profile, or set each area yourself: | Area | Access levels you can pick | Notes | | - | - | - | | **Quotes and Documents** | Disabled, Read Only, Read / Write | Quotes, orders and invoices with their lines. This is the area a quoting agent needs. Documents carry your cost, profit and internal notes. | | **Products, Contacts and Other Tables** | Disabled, Read Only, Read / Write | Every other table in your QuoteWerks database except the settings tables: products, contacts, purchase orders. | | **Reports and Account** | Disabled, Read Only | Saved Management Reports, the list of tables, and the user the key belongs to. | | Profile | What it does | | - | - | | **Read Only** | Reads everything and changes nothing | | **Helpdesk** | Creates and updates quotes after a technician approves; other tables stay read-only | | **IT Admin** | Creates and updates quotes on its own; writes to other tables ask a technician first | | **Full Automation** | Every write runs on its own | ## 4. Link quotes to your PSA, for QuoteValet links Neo reads a quote's QuoteValet customer link from the opportunity in Autotask or ConnectWise PSA. QuoteWerks puts the link there when a quote that was saved with **Create/Update Sales Opportunity** is uploaded to QuoteValet. The same opportunity link lets Neo find a customer's quotes by the ticket's opportunity or contact. For this: * Connect QuoteWerks to your PSA in QuoteWerks, and save quotes with **Create/Update Sales Opportunity**. * Give the agent read access to the PSA area that holds the link: **Opportunities** and **Companies** in Autotask, or **Documents** in ConnectWise PSA. On another PSA, or when a quote has no opportunity, Neo asks your sales rep for the link. See [QuoteWerks API](/agents/tools/sales/quotewerks-api) for what the agent can do. # Overview Source: https://docs.neoagent.io/integrations/quotewerks/overview What the QuoteWerks integration brings to your Neo Agent setup QuoteWerks Web holds your quotes, orders and invoices. Connect your QuoteWerks Web API key to Neo once, at the MSP level. The integration uses the QuoteWerks Web REST API, which QuoteWerks marks as beta. ## What Neo can do with QuoteWerks * Find a customer's open quotes, by the ticket's PSA opportunity or contact, and read a quote's status, lines and total * Tell whether the customer accepted a quote on QuoteValet * Create a quote from a customer's request: the quote, then one line per product, priced from your product table when you have one. QuoteWerks calculates the totals * Ask your sales rep to upload a new quote to QuoteValet, then give the customer its link from the Autotask or ConnectWise opportunity * Update a quote or a line, such as its status or a quantity * Look up products and contacts in the other tables of your QuoteWerks database * Run a saved Management Report and summarise it A quote holds its sold-to company as text and the ids of your PSA's opportunity and contact, so the QuoteWerks card has no Organization Mapping tab. See [QuoteWerks API](/agents/tools/sales/quotewerks-api) for the permission groups. ## Next steps <Card title="Connect QuoteWerks" icon="plug" href="/integrations/quotewerks/connecting-to-neo"> Create an API key in QuoteWerks Web and save it in Neo. </Card> # Request an integration Source: https://docs.neoagent.io/integrations/request-an-integration Name a tool Neo does not support yet, and Neo's team reviews it for a native integration Neo's team reviews each request. When the vendor has a usable API, the team builds the integration from it within 5 working days, with permission groups, technician approval for writes and a setup guide, like the native integrations Neo already has. When it is ready, it appears in the **Directory** and you connect it there. ## Send a request Open [**Integrations**](https://dashboard.neoagent.io/integrations?tab=directory\&build=) and click **Neo builds it**. You can also click the first tile in the **Directory** tab. If you search for a tool that Neo does not list, that tile offers to build it, with your search already filled in. The form asks for: | Field | What to give | | - | - | | **Tool or vendor** | The product name, e.g. "SecureShield AV". | | **What should Neo do with it?** | The work you want agents to do there, in your own words. For example: "When a user reports a blocked email, release it from quarantine and allow the sender." | | **Link to its API docs** | Required. The vendor's API reference, as a full `http://` or `https://` address. | | **API spec file** | Optional. An OpenAPI, Postman, PDF or text file, up to 10 MB. | | **I can give Neo a test API key when asked** | Optional. A test key lets Neo check the integration against your account before it ships. | Click **Build integration** to send it. You can also ask the Neo Support agent: "Can Neo connect to SecureShield AV?" If Neo does not support the tool, the agent confirms the details with you and sends the same request. <Info> Your team can send 5 requests in any 7 days. </Info> ## What happens next * Neo's team reviews every request. When the vendor has a usable API, Neo builds the integration within 5 working days of the request; a request from several MSPs for the same tool is built once. * A vendor whose API needs a partner agreement, or has no public API, can take longer or be out of reach. * If Neo already supports the tool, we tell you in your Neo support chat where to connect it. * If the tool is your own or an in-house API, connect it with [Custom API](/integrations/custom-api/overview), which works with any REST API. ## Through the API `POST /public-api/integrations/requests` sends a request. See the [API introduction](/developers/introduction) for keys and the reference. # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/rmm/addigy/connecting-to-neo Add your Addigy API key to Neo Agent and check the first device sync The only field is the API key from [Creating an API key](/integrations/rmm/addigy/creating-api-key). Addigy has one API host for every organization, so Neo needs no URL. ## Connect <Steps> <Step title="Open the Addigy card"> In the Neo dashboard, open [**Integrations** → **Addigy**](https://dashboard.neoagent.io/integrations?open=addigy). </Step> <Step title="Paste the key"> Paste the key into the **API key** field. </Step> <Step title="Save"> Click **Save Integration**. Neo checks with Addigy that the key can read devices and policies before it saves the connection. If a check fails, Neo shows the error and saves nothing. If the key cannot read child organizations, Neo saves the connection and shows a warning: devices in child organizations are not synced until you connect a key with that access. </Step> </Steps> ## Check the first sync Devices appear after the next sync. To check, open the card's [**Device Mapping**](https://dashboard.neoagent.io/integrations?open=addigy\&subtab=device-mapping) tab and confirm that your devices appear under the right PSA company. [Device mapping](/integrations/rmm/device-mapping) explains how to assign a device that Neo left **Unmapped**. ## Troubleshooting If Addigy rejects the key: * Copy the key again, with no spaces before or after it. * Check in Addigy that nobody deleted the key. * Check that the key has **View Devices** and read access to policies. # Creating an API key Source: https://docs.neoagent.io/integrations/rmm/addigy/creating-api-key Create an Addigy API v2 key with the permission Neo Agent needs Create the key in your top-level Addigy organization. Neo syncs devices from that organization and its child organizations, and maps them through your client organizations and policies. Addigy shows a new key once. Have a password manager open before you start. ## Create the key <Steps> <Step title="Open the Addigy API settings"> In Addigy, switch to your top-level organization, then go to [**Account** → **Integrations**](https://app.addigy.com/integrations) → **API & Webhooks**. In the **Addigy API** section, click **New API Token**. Your Addigy user needs the **View Integrations API Keys** and **Create Integrations API Keys** permissions. Without them, ask an Addigy admin to create the key. </Step> <Step title="Name the key"> Give the key a name you will recognize later, such as `Neo Agent`. </Step> <Step title="Choose the permissions"> Select the permission in [Permissions to grant](#permissions-to-grant) below. </Step> <Step title="Copy the key"> Create the key and copy it at once. Addigy does not show it again; if you lose it, delete the key and create a new one. </Step> </Steps> ## Permissions to grant | Permission | What Neo uses it for | | - | - | | **View Devices** | Device sync and device lookup. Neo checks for it when you connect. | The key also needs read access to policies. Read access to child organizations is optional. Without it, Neo syncs and maps only the devices in the key's own organization, and shows a warning when you connect. Scripts need two more permissions. **View Predefined Commands** lets Neo sync your script library, so agents can [find scripts](/agents/tools/rmm/find-rmm-scripts), and lets the [RMM API](/agents/tools/rmm/rmm-api) tool's **Scripts & Commands** group read it. Without it, Neo syncs devices and skips the script library. **Execute Commands** lets agents run a script, through [Execute RMM Script](/agents/tools/rmm/run-rmm-script) or the RMM API tool, and lets the RMM API tool's **MDM Device Actions** group send device commands. Neo also reads the installed software of each Mac, which Addigy's API documentation lists with no extra permission. ## Next step [Connect the key to Neo Agent](/integrations/rmm/addigy/connecting-to-neo). # Overview Source: https://docs.neoagent.io/integrations/rmm/addigy/overview Connect Addigy to Neo Agent for Apple device context Addigy manages Apple devices only. Neo connects to it with one API key, and every call goes to Addigy's cloud API, so there is no server URL to enter. ## Setup <CardGroup> <Card title="Creating an API key" icon="key" href="/integrations/rmm/addigy/creating-api-key"> Create an API v2 key in Addigy with the permission Neo needs. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/rmm/addigy/connecting-to-neo"> Paste the key into the Addigy card on the Neo Integrations page. </Card> </CardGroup> ## Prerequisites * An Addigy user in your top-level organization who can create API keys. Addigy asks for the **View Integrations API Keys** and **Create Integrations API Keys** user permissions. ## What Neo does with Addigy * **Device sync**: on each sync, Neo reads every device in the key's organization and, when the key can read them, in each of its child organizations. * **Device lookup**: while it works a ticket, an agent reads the details of a device in the key's organization, and the installed software of a Mac. * **Company mapping**: Neo links each synced device to its PSA company through your Addigy client organizations and policies. A device in a child organization maps through that organization. Any other device in exactly one policy maps through the top-level policy above it, and a device in several policies has no policy route. If Addigy's own Autotask or ConnectWise integration links those policies to an account in your active PSA, Neo uses that link. See [Device mapping](/integrations/rmm/device-mapping) to check and correct the result. ## No Windows devices Neo flows that need a Windows machine, such as [on-prem AD and Exchange](/integrations/m365/on-prem), cannot run through Addigy. Connect a second RMM for those devices: Neo [connects several RMMs at once](/integrations/rmm/intro), and each device stays with the RMM it came from. # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/rmm/connectwise-automate/connecting-to-neo Configure the connection between your ConnectWise Automate system and Neo Agent using API credentials Once you've [created your API user](/integrations/rmm/connectwise-automate/creating-api-user) with the proper user class and permissions, you can configure the connection to Neo Agent through the integrations dashboard. <Info> You'll need the credentials and configuration details from your ConnectWise Automate system integrator account to complete this setup. </Info> ## Required Information Before starting the connection process, gather the following information from your ConnectWise Automate system: <ParamField type="string"> Your ConnectWise Automate server hostname or URL (e.g., `automate.yourcompany.com`). This is the address you use to access your ConnectWise Automate instance. </ParamField> <ParamField type="string"> The username you created for the system integrator account (e.g., `neo_agent`). </ParamField> <ParamField type="string"> The password for your system integrator account. </ParamField> ## Configuring the Integration <Steps> <Step title="Access the Neo Agent Dashboard"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and log in with your credentials. </Step> <Step title="Select ConnectWise Automate Integration"> From the integrations page, find and select **ConnectWise Automate** from the list of available RMM integrations. </Step> <Step title="Enter Your Credentials"> Submit the credentials you gathered from your ConnectWise Automate system: * **Hostname**: Enter your ConnectWise Automate server address * **Username**: Enter the system integrator username * **Password**: Enter the system integrator password <Warning> Double-check all credentials for accuracy. Incorrect information will prevent Neo Agent from connecting to your ConnectWise Automate system. </Warning> </Step> <Step title="Test the Connection"> Once you've entered all credentials, Neo Agent will attempt to establish a connection to your ConnectWise Automate system to verify the configuration. <Check> A successful connection test confirms that Neo Agent can access your ConnectWise Automate system with the provided credentials and permissions. </Check> </Step> <Step title="Save Configuration"> After successful testing, save your integration configuration to enable Neo Agent workflows to interact with your ConnectWise Automate system. </Step> </Steps> ## IP Whitelisting If you have IP address restrictions in place on your ConnectWise Automate instance, you'll need to add Neo Agent's IP addresses to your allowed list. <Card title="IP Whitelisting Guide" icon="shield" href="/integrations/ip-whitelisting"> View Neo Agent's IP addresses for whitelisting in your firewall or access control settings. </Card> ## Troubleshooting Connection Issues If you encounter issues during the connection process, check the following: <AccordionGroup> <Accordion title="Authentication Errors"> * Verify that the username and password are correct * Ensure the **Integrator** checkbox is enabled for the user account * Check that the hostname is accessible and correctly formatted </Accordion> <Accordion title="Permission Errors"> * Review the user class permissions for your Neo Automation user class * Ensure all required permissions listed in the [API user creation guide](/integrations/rmm/connectwise-automate/creating-api-user) are assigned * Verify that the user class is properly assigned to the integrator account * Check that client-level permissions are correctly configured </Accordion> <Accordion title="Customers Not Appearing"> If customers or devices are not showing up when Neo refreshes options: * This is typically a permission issue on the user class * Verify the user class has proper access to customers * Check that **Clients → Show All** permission is set to Access * Ensure **Locations → Show All** permission is enabled </Accordion> <Accordion title="Network Connectivity"> * Confirm your ConnectWise Automate server is accessible from external networks * Check if any firewall rules might be blocking API connections * [Whitelist Neo Agent's IP address](/integrations/ip-whitelisting) if your system restricts access by IP * Test the hostname accessibility from outside your network </Accordion> </AccordionGroup> ## What's Next? With your ConnectWise Automate system successfully connected to Neo Agent, you can now: * **Execute Scripts**: Configure workflows to run scripts on managed devices * **Automate Remediation**: Set up automated ticket resolution using RMM scripts * **Access Device Data**: Pull device information into your ticket workflows <Tip> Start with simple script execution workflows to test the integration before implementing complex automation scenarios. This helps identify any configuration issues early in the process. </Tip> # Creating an API User Source: https://docs.neoagent.io/integrations/rmm/connectwise-automate/creating-api-user Set up a dedicated user class and system integrator account with proper permissions for Neo Agent To enable Neo Agent to interact with your ConnectWise Automate system, you need to create a dedicated user class with appropriate permissions and then create a system integrator account using that class. <Info> This process involves creating a custom user class called "Neo Automation", configuring detailed permissions, and setting up system integrator credentials. </Info> ## Creating the User Class and API User <Steps> <Step title="Create a new user class"> Log in to ConnectWise Automate Control Center using your administrator credentials and create a new user class: 1. Navigate to **Users and Contacts → User Class Manager** in the **System** menu 2. Click **+** at the bottom left corner of the **User Class Manager** window 3. Enter `Neo Automation` as the name for the new user class 4. Click **OK** to create the class <Tip> Using a descriptive class name like "Neo Automation" makes it easy to identify and manage permissions specifically for the Neo Agent integration. </Tip> </Step> <Step title="Configure Core permissions"> Select the new user class and configure the following permissions on the **Core** tab: ### Agent and Alert Permissions | Entry | Permission | | - | - | | Agent Templates | Read | | Alerts | Update | ### Client and Contact Permissions | Entry | Permission | | - | - | | Clients | Read, Update, Delete | | Clients → Show/Hide Passwords | Access | | Clients → Show All | Access | | Contacts | Read, Update, Delete | ### Computer Permissions | Entry | Permission | | - | - | | Computers → Force Update | Access | | Computers → Retired Assets | Delete | | Computers → Show All | Access | ### Group and Location Permissions | Entry | Permission | | - | - | | Groups | Create, Update, Delete | | Groups → Scheduled Scripts | Update | | Locations → Show All | Access | ### Script and Patch Permissions | Entry | Permission | | - | - | | Patch Manager | Read, Update | | Scripts | Read, Update, Delete | | Scripts → Schedule Scripts | Update | | Searches → Send Commands | Access | ### Ticket Permissions | Entry | Permission | | - | - | | Tickets | Create, Read, Update, Delete | | Tickets → Ticket Requests | Access | <Warning> Ensure all permissions are properly assigned. Missing permissions can cause Neo Agent workflows to fail when trying to execute scripts or access device information. </Warning> </Step> <Step title="Configure Plugin permissions (if applicable)"> If your ConnectWise Automate instance uses plugins, configure permissions for specific plugins on the **Plugin** tab as needed for your workflows. <Info> The specific plugin permissions required depend on which plugins you have installed and want Neo to interact with. </Info> </Step> <Step title="Configure client level permissions"> Ensure the user class has access to clients with the following permissions: | Entry | Permission | | - | - | | Locations | Read, Edit, Delete | | Projects | Read | | Product Keys | Read | | Documents | Read | | Passwords | Read | <Note> If customers are not showing up when refreshing options, this is typically a permission issue. Validate that the user class has proper access to customers. </Note> </Step> <Step title="Configure default computer permissions"> Enable the following default computer permissions for the user class: | Entry | Permission | | - | - | | Command Prompt | Access | | Software and Tools | Install | | History | Access | | Commands | View, Send | | Scripts | Schedule | | Information | Edit | | Alerts | Clear | | Scheduled Scripts | Delete | </Step> <Step title="Save the user class"> Click **Save** to apply all permission changes to the user class. </Step> <Step title="Create the system integrator account"> Create a new user that will be used for API access: 1. Click **Settings** in the bottom left corner 2. Navigate to **User Management** 3. Click **Add** in the top left 4. Configure the user with the following settings: * **First Name**: Neo * **Last Name**: Agent * **Email**: Your preferred email for notifications * **User Name**: Choose a descriptive username (e.g., `neo_agent`) * **Password**: Create a strong password <Warning> Store the username and password securely. You'll need these credentials to configure the integration in Neo Agent. </Warning> </Step> <Step title="Assign the user class"> Associate the new user with the Neo Automation user class: 1. Click the **User Classes** tab 2. Click **Edit User Classes** 3. Select the **Neo Automation** user class you created earlier </Step> <Step title="Enable integrator access"> Enable API access for the user: 1. Check the **Integrator** box at the bottom of the user configuration 2. Click **Save** to apply the changes <Check> The Integrator checkbox is essential for API access. Without it, the user cannot authenticate via the API. </Check> </Step> </Steps> ## What's Next? Once you've successfully created the API user with proper permissions, you're ready to [connect it to Neo Agent](/integrations/rmm/connectwise-automate/connecting-to-neo) using the credentials from your new system integrator account. <Check> Before proceeding, ensure you have: * The username you created for the integrator account * The password for the integrator account * Your ConnectWise Automate hostname/URL </Check> # Overview Source: https://docs.neoagent.io/integrations/rmm/connectwise-automate/overview Connect your ConnectWise Automate RMM to Neo Agent for automated script execution and device management ## Setup Overview Setting up the ConnectWise Automate integration involves two main steps: <CardGroup> <Card title="Creating an API User" icon="user-plus" href="/integrations/rmm/connectwise-automate/creating-api-user"> Set up a dedicated user class and system integrator account with proper permissions for Neo Agent to access your ConnectWise Automate system. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/rmm/connectwise-automate/connecting-to-neo"> Configure the connection between your ConnectWise Automate system and Neo Agent using API credentials. </Card> </CardGroup> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Administrator credentials for ConnectWise Automate Control Center * **User Class Management**: Ability to create and configure user classes * **API User Creation**: Permissions to create system integrator accounts * **Network Access**: Ability to configure IP whitelisting if required ## What Neo Can Do with ConnectWise Automate When connected, Neo Agent gains visibility into your scripts and registered devices, enabling powerful automation capabilities: <AccordionGroup> <Accordion title="Script Discovery and Execution"> Neo can browse your entire script library and suggest or execute relevant scripts based on ticket context: * **Automated remediation** — Execute scripts to resolve common issues without technician intervention * **Intelligent suggestions** — Recommend appropriate scripts to technicians based on ticket details * **Job monitoring** — Track script execution status and take follow-up actions based on results </Accordion> <Accordion title="Device Management"> Access device information and perform management tasks: * **Device lookup** — Find devices associated with tickets or end users * **Service management** — Start, stop, or restart services on managed devices * **Patch management** — View patching status and trigger patch operations * **Hardware inventory** — Access device specifications and configurations </Accordion> <Accordion title="Alert and Ticket Integration"> Streamline alert handling and ticket workflows: * **Alert clearing** — Automatically clear alerts after successful remediation * **Ticket updates** — Update PSA tickets with script results and device information * **Escalation handling** — Route complex issues to appropriate technicians </Accordion> </AccordionGroup> <Tip> Configure Neo's automation rules to match your business processes. You decide which actions Neo takes automatically and which require human approval. </Tip> ## Available Actions Neo Agent can perform the following actions through the ConnectWise Automate integration: | Category | Actions | | - | - | | **Computers** | List computers, get devices, services, drives, patching stats, patch jobs, retired assets | | **Contacts** | List contacts, list system contacts | | **Extra Data Fields** | Get/update EDFs for locations, computers, clients, and contacts | | **Groups** | List groups | | **Network Devices** | List network devices | | **Scripts** | Schedule and execute scripts on devices | | **Searches** | List and execute saved searches | | **Users** | List users, user folders, user classes | | **Patch Management** | View patch information, schedule patch operations | <Info> Neo Agent uses the ConnectWise Automate REST API to perform these actions. Ensure your API user has the necessary permissions for the actions you want Neo to perform. </Info> # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/rmm/connectwise-rmm/connecting-to-neo Configure the connection between your ConnectWise Asio system and Neo Agent using API credentials Once you've [generated your API credentials](/integrations/rmm/connectwise-rmm/creating-api-key) in ConnectWise Asio, you can configure the connection to Neo Agent through the integrations dashboard. <Info> You'll need the Client ID, Client Secret, and region information from your ConnectWise Asio portal to complete this setup. </Info> ## Required Information Before starting the connection process, gather the following information from your ConnectWise Asio system: <ParamField type="string"> Your ConnectWise Asio region. This determines which API endpoint Neo Agent will use. Available options: **US**, **EU**, or **AU**. </ParamField> <ParamField type="string"> The Client ID from your generated API access credentials in ConnectWise Asio. </ParamField> <ParamField type="string"> The Client Secret from your generated API access credentials in ConnectWise Asio. </ParamField> ## Configuring the Integration <Steps> <Step title="Access the Neo Agent Dashboard"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and log in with your credentials. </Step> <Step title="Navigate to RMM Integrations"> From the dashboard: 1. Click **Integrations** in the left sidebar 2. Select the **RMM** tab at the top of the page 3. Find and select **ConnectWise Asio** from the list of available RMM integrations <Frame> <img alt="Neo Agent dashboard showing Integrations menu with RMM tab selected and ConnectWise Asio option visible" /> </Frame> </Step> <Step title="Enter Your Credentials"> Complete the ConnectWise Asio Integration Setup form: 1. **RMM**: Ensure **CWASIO** is selected 2. **ConnectWise Asio Region**: Select your region (US, EU, or AU) 3. **RMM Client Id**: Enter your Client ID from ConnectWise Asio 4. **RMM Client Secret**: Enter your Client Secret from ConnectWise Asio <Frame> <img alt="ConnectWise Asio Integration Setup form showing region dropdown and credential fields" /> </Frame> <Warning> Double-check all credentials for accuracy. Incorrect information will prevent Neo Agent from connecting to your ConnectWise Asio system. </Warning> </Step> <Step title="Submit Configuration"> Click **Submit** to save your integration configuration. Neo Agent will validate the credentials and establish a connection to your ConnectWise Asio system. <Check> A successful connection confirms that Neo Agent can access your ConnectWise Asio system with the provided credentials and scopes. </Check> </Step> </Steps> ## Determining Your Region If you're unsure which region your ConnectWise Asio instance uses, check the URL you use to access the portal: | Portal URL Pattern | Region | | - | - | | `*.itsupport247.net` (US domain) | US | | `*.eu.itsupport247.net` | EU | | `*.au.itsupport247.net` | AU | <Info> ConnectWise Asio (formerly ITSupportPortal/Continuum) uses region-specific API endpoints. Selecting the wrong region will cause authentication failures. </Info> ## Troubleshooting Connection Issues If you encounter issues during the connection process, check the following: <AccordionGroup> <Accordion title="Authentication Errors"> * Verify that the Client ID and Client Secret are correct * Ensure you copied the full credentials without any extra spaces * Check that the API access hasn't been revoked in ConnectWise Asio * Confirm you've selected the correct region </Accordion> <Accordion title="Permission Errors"> * Review the scopes assigned to your API access in ConnectWise Asio * Ensure all required scopes listed in the [API credentials guide](/integrations/rmm/connectwise-rmm/creating-api-key) are assigned * If scopes are missing, generate new API access with the required permissions </Accordion> <Accordion title="Region Mismatch"> * Double-check your portal URL to confirm the correct region * If you're unsure, try each region option to identify the correct one * Contact ConnectWise support if you cannot determine your region </Accordion> <Accordion title="Devices or Scripts Not Appearing"> If devices or scripts are not showing up after successful connection: * Verify the API access has the `Platform - Agent - Read` scope * Ensure the `Platform - Automation - Read` scope is included for script access * Wait a few minutes for initial synchronization to complete * Try refreshing the connection in Neo Agent settings </Accordion> </AccordionGroup> ## Configuring Permission Groups Once the integration is connected, open **Agent Settings → Permission Groups** to choose what the agent is allowed to do in ConnectWise Asio. Each group can be set independently to **Disabled**, **Read-only**, or **Read & Write**: | Group | Read | Write | | - | - | - | | **Tickets & Ticketing Lookups** | List and read tickets, notes, statuses, priorities, types, categories, sources, service boards, tags | Create/update tickets and notes | | **Companies & Sites** | List and read companies and sites | Create/update companies and sites | | **Contacts** | List and read contacts | Create/update contacts | | **Device Endpoints** | List and read endpoints (v2 company/site hierarchy) | — | | **Custom Fields** | List definitions and read values | Write values on companies/sites/endpoints | | **Policies** | Read policy groups, categories, effective policy, overrides | — | | **Patching** | Read OS patch catalog and status | — | | **Alerting** | Read alerts and suspension rules | — | | **Incidents** | Read Security360 incidents | — | | **Backup Dashboard** | Read alarms, DR readiness, backup instances | — | | **Network Devices** | Read network-device inventory | — | | **Mappings** | Read endpoint/site/integrator mappings | — | | **Billing** | Read unified product usage | — | | **Automation** | Read script, shell-script, and task catalog | Execute scripts on managed endpoints | Write-capable groups default to **Read-only** on existing agents so the expanded v2.5.7 surface is opt-in per tenant — no agent that was previously read-only suddenly starts making changes. ## What's Next? With your ConnectWise Asio system successfully connected to Neo Agent, you can now: * **Ticketing workflows**: Neo can triage and create tickets, add notes, and update statuses in ConnectWise Asio * **Company/site/contact maintenance**: Keep CW Asio CRM data in sync with the agent's workflows * **Device lookup**: Access endpoint information associated with tickets or end users * **Script suggestions**: Neo surfaces relevant scripts from your automation catalog <Info> Grant **Write** on the **Automation** area and Neo can run scripts on managed endpoints directly (via Asio's built-in PowerShell template) and read back the results, not just suggest them. The area stays read-only unless you opt in, and you can require technician approval before any run. </Info> <Tip> Test the integration by asking Neo to find scripts for common issues or by enabling Read & Write on **Tickets** and letting Neo resolve a low-priority ticket end to end. </Tip> # Generating API Credentials Source: https://docs.neoagent.io/integrations/rmm/connectwise-rmm/creating-api-key Create API access credentials in ConnectWise Asio for Neo Agent integration To enable Neo Agent to interact with your ConnectWise Asio system, you need to generate API access credentials with the appropriate scopes. <Info> This process involves generating API access credentials (Client ID and Client Secret) in your ConnectWise Asio portal with specific permissions that allow Neo to access your scripts and devices. </Info> ## Creating API Access Credentials <Steps> <Step title="Navigate to API Access"> Log in to your ConnectWise Asio portal and navigate to the API Access section: 1. Click **Integrations** in the left navigation menu 2. Select **API Access** from the submenu <Frame> <img alt="ConnectWise Asio navigation showing Integrations menu expanded with API Access option highlighted" /> </Frame> </Step> <Step title="Generate API Access"> Click the **Generate API Access** button in the top right corner of the API Access page to create new API credentials. <Frame> <img alt="API Access page showing the Generate API Access button" /> </Frame> </Step> <Step title="Configure API Access Details"> Fill in the API access configuration form: 1. **API Key Name**: Enter a descriptive name (e.g., `neoagent`) 2. **Description**: Add a description for reference (e.g., `Neo Agent Integration`) 3. **Scopes**: Select the required scopes for Neo Agent: * `Platform - Agent - Read` * `Platform - Assets - Read` * `Platform - Automation - Read` * `Platform - Automation - Create` * `Platform - Companies - Read` * `Platform - Contacts - Read` * `Platform - Devices - Read` * `Platform - Sites - Read` * `Platform - Tickets - Read` 4. **Consent**: Check the consent box to acknowledge the API access terms <Frame> <img alt="Generate API Access form showing API Key Name, Description, Scopes dropdown, and Consent checkbox" /> </Frame> <Warning> Ensure all required scopes are selected. Missing scopes can cause Neo Agent to fail when attempting to execute scripts or access device information. </Warning> </Step> <Step title="Generate and Save Credentials"> Click **Generate API Access** to create your credentials. A panel will appear showing your Client ID and Client Secret. <Frame> <img alt="Generated API Access panel showing Client ID and Client Secret with copy buttons" /> </Frame> <Warning> **Important**: Copy both the **Client ID** and **Client Secret** immediately and store them securely. The Client Secret cannot be recovered if lost—you will need to regenerate new credentials. </Warning> <Check> Before closing this panel, ensure you have saved: * The **Client ID** (visible in the form) * The **Client Secret** (hidden by default, click to reveal) </Check> </Step> </Steps> ## Required Scopes Reference The following scopes are required for Neo Agent to function properly: | Scope | Purpose | | - | - | | `Platform - Agent - Read` | Access agent information | | `Platform - Assets - Read` | Access asset and hardware inventory | | `Platform - Automation - Read` | List available scripts and automation policies | | `Platform - Automation - Create` | Execute scripts on devices | | `Platform - Companies - Read` | Access company/client information | | `Platform - Contacts - Read` | Access contact information | | `Platform - Devices - Read` | Access device details and status | | `Platform - Sites - Read` | Access site configurations | | `Platform - Tickets - Read` | Access ticket information for device correlation | <Info> If you need Neo to perform additional actions in the future, you may need to regenerate API credentials with additional scopes. </Info> ## What's Next? Once you've successfully generated your API credentials, you're ready to [connect them to Neo Agent](/integrations/rmm/connectwise-rmm/connecting-to-neo) using the Client ID and Client Secret from your ConnectWise Asio portal. <Check> Before proceeding, ensure you have: * The **Client ID** from your generated API access * The **Client Secret** from your generated API access * Your ConnectWise Asio **region** (US, EU, or AU) </Check> # Overview Source: https://docs.neoagent.io/integrations/rmm/connectwise-rmm/overview Connect your ConnectWise Asio RMM to Neo Agent for automated script execution and device management ## Setup Overview Setting up the ConnectWise Asio integration involves two main steps: <CardGroup> <Card title="Generating API Credentials" icon="key" href="/integrations/rmm/connectwise-rmm/creating-api-key"> Create API access credentials in your ConnectWise Asio portal with the required scopes for Neo Agent. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/rmm/connectwise-rmm/connecting-to-neo"> Configure the connection between your ConnectWise Asio system and Neo Agent using your API credentials. </Card> </CardGroup> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Administrator credentials for the ConnectWise Asio portal * **API Access Permissions**: Ability to generate API access keys in your organization * **Region Information**: Know which ConnectWise Asio region your organization uses (US, EU, or AU) <Info> ConnectWise Asio was formerly known as ITSupportPortal/Continuum. If your organization used either of these products, you're already on ConnectWise Asio. </Info> ## What Neo Can Do with ConnectWise Asio Neo Agent supports the full ConnectWise Asio v2.5.7 surface: 96 operations across 68 API paths covering tickets, companies, endpoints, custom fields, policies, patching, incidents, backup dashboard, network devices, and more. Both read and write operations are supported and gated by per-area permission groups you configure in Agent Settings. <AccordionGroup> <Accordion title="Ticketing"> Full read/write access to the service-ticketing surface: * **Create and update tickets** — summary, description, priority, status, assignee, tags * **Notes and replies** — add technician-facing or customer-facing notes * **Lookups** — statuses, priorities, categories, types, sources, service boards, tags </Accordion> <Accordion title="Device Management"> Access device information and perform management tasks: * **Device lookup** — find endpoints by company, site, or endpoint ID (v2 nested paths) * **Hardware inventory** — device specifications, operating system, network adapters * **Device groups and hypervisors** — read membership and state </Accordion> <Accordion title="Companies, Sites, Contacts"> Read and write on the CRM-style surface: * **Companies** — create, update, list * **Sites** — create, update, list under a company * **Contacts** — create and update contact records </Accordion> <Accordion title="Custom Fields, Policies, Patching"> * **Custom fields** — read definitions, read and write values across companies/sites/endpoints * **Policies** — read groups, categories, effective policy, and overrides * **Patching** — list OS patches, classifications, approval status </Accordion> <Accordion title="Incidents, Alerting, Backup Dashboard"> * **Incidents** — read Security360 incidents * **Alerts and suspensions** — read active alerts and suspension rules * **Backup Dashboard** — backup alarms, DR readiness, backup instances </Accordion> <Accordion title="Automation"> * **Script discovery** — browse the script and shell-script catalog * **Task discovery** — list task definitions * **Script execution** — run a script on one or more managed endpoints and read back the results (requires Write) <Info> Grant **Write** on the **Automation** area and Neo can run scripts on managed endpoints directly — it schedules a script on one or more endpoints via Asio's built-in PowerShell template and reads back the results. The area stays read-only unless you opt in, and you can require technician approval before any run. </Info> </Accordion> </AccordionGroup> <Tip> Write access is opt-in per area. In Agent Settings → Permission Groups, set the relevant CW Asio groups to **Read & Write** to enable creates, updates, and deletes. </Tip> ## Available Actions Neo Agent can perform the following actions through the ConnectWise Asio integration: | Category | Actions | Status | | - | - | - | | **Tickets** | Create, update, close tickets; add notes; read lookups (status, priority, type, category, source, board, tag) | Available (read/write) | | **Device Endpoints** | List devices by company/site/endpoint, get device details and inventory | Available | | **Device Groups & Hypervisors** | Read membership and virtualisation state | Available | | **Companies** | Create, update, list companies and clients | Available (read/write) | | **Sites** | Create, update, list sites under a company | Available (read/write) | | **Contacts** | Create, update, list contacts | Available (read/write) | | **Custom Fields** | Read definitions, read and write values | Available (read/write) | | **Policies** | Read groups, categories, effective policy, and overrides | Available | | **Patching** | List OS patches, classifications, approval status | Available | | **Alerting** | Read alerts and suspension rules | Available | | **Incidents** | Read Security360 incidents | Available | | **Backup Dashboard** | Read alarms, DR readiness, backup instances | Available | | **Network Devices** | Read network-device inventory | Available | | **Mappings** | Read endpoint / site / integrator mappings | Available | | **Billing** | Read unified product usage | Available | | **Automation** | Search and suggest scripts, shell scripts, and tasks | Available (read) | | **Automation** | Execute scripts on managed endpoints (via the built-in PowerShell template), monitor job status | Available (write) | <Info> Neo Agent uses the ConnectWise Asio v2.5.7 API to perform these actions. Ensure your API credentials have the necessary scopes for the areas you want Neo to act in — see the [API credentials guide](/integrations/rmm/connectwise-rmm/creating-api-key) for the scope list. </Info> # Overview Source: https://docs.neoagent.io/integrations/rmm/datto/overview Connect your Datto RMM to Neo Agent for automated script execution and device management ## Prerequisites Before starting the integration setup, you need: * **Admin Access**: Administrator access to your Datto RMM portal * **API Access Enabled**: Ability to enable API access in Global Settings * **User Management**: Permissions to create or modify users and generate API keys ## Setup Guide <Steps> <Step title="Enable API access"> Navigate to **Setup → Global Settings → Access Control** and enable API access for your account. <Info> API access must be enabled at the account level before individual users can generate API keys. </Info> </Step> <Step title="Generate API keys"> Go to **Setup → Users**, select a user (or create a dedicated API user), and generate API keys for authentication. When applying Security levels, configure the following: | Setting | Value | | - | - | | Component Level | Super (5) | | Security Levels | administrator | | Default security level | administrator | <Frame> <img alt="Datto RMM Security Settings" /> </Frame> <Check> Make note of both the **API Key** and **Secret Key** as you'll need these to configure the integration in Neo Agent. </Check> </Step> <Step title="Configure in Neo Agent"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and select **Datto RMM** from the RMM integrations. Enter your credentials: * **API Key**: The API key generated from your Datto RMM user * **Secret Key**: The secret key associated with your API key * **API URL**: Your Datto RMM API endpoint (based on your region) </Step> <Step title="Test and save"> Neo Agent will validate your credentials and establish the connection. Once successful, save the configuration. <Check> A successful connection allows Neo to access your scripts, devices, and alerts. </Check> </Step> </Steps> ## API Regions Datto RMM uses different API endpoints based on your region. Select the appropriate URL when configuring: | Region | API URL | | - | - | | US (Concord) | `https://concord-api.centrastage.net` | | US (Pinotage) | `https://pinotage-api.centrastage.net` | | US (Merlot) | `https://merlot-api.centrastage.net` | | US (Syrah) | `https://syrah-api.centrastage.net` | | EU (Zinfandel) | `https://zinfandel-api.centrastage.net` | | EU (Vidal) | `https://vidal-api.centrastage.net` | <Tip> You can find your region by looking at the URL when logged into Datto RMM. The region name appears in the domain. </Tip> ## Known Limitations <Warning> Neo Agent cannot create or edit Datto RMM components. The Datto RMM API lets Neo list and read components, and run them on devices, but Datto publishes no endpoint to create, update or delete one — so no permission setting in Neo enables it. Create a component yourself in Datto RMM under **Automation → Components → New Component**. When an agent is asked to build a new automation, it delivers the script and the component definition (name, category, description, and each variable with its default) for you to paste in, and reports that the component still needs manual creation. </Warning> <Warning> Neo Agent does not enroll devices in Apple MDM, create or edit MDM policies, send MDM commands, or update iPhones and iPads, in Datto RMM or Kaseya MDM. When an agent is asked for one of these, it gives your technician the device and the exact settings to apply in the Datto RMM or Kaseya MDM console, and reports that the change still needs a person. </Warning> <Warning> Neo Agent cannot automatically resolve variables where the type is "Selection" in Datto RMM due to a limitation in the Datto RMM API. Avoid using "Selection" type variables when you want Neo to automatically run scripts and choose the right variables. If you must use Selection variables, provide Neo with custom instructions to handle the mapping: ```text theme={null} For the variable named "InstallType", we have the following mapping and you must only choose the value for each mapping which makes sense: - Silent Install: 1 - Interactive Install: 2 - Repair: 3 ``` <Frame /> </Warning> ## Troubleshooting ### "Datto RMM refused Neo access" in your Inbox Datto accepted your API key and secret, then refused the user they belong to access to the data Neo asked for. Neo posts this to your [Inbox](/product/inbox) as an action-required message and stops the sync for that data; it does not retry until the next sync. The API key and secret are correct, so re-entering them does not help. Open **Setup → Users** in Datto RMM, find the user whose API key Neo signs in with, and check its security level. Neo reads the account's devices, sites and components, so the security level must allow all three — the setup guide above uses the **administrator** security level. Neo picks the sync up on its own once the permission is in place. ### "No devices found" after a sync The sync finished, but Neo received no devices from Datto. Open **Setup → Users** in Datto RMM, find the user whose API key Neo signs in with, and check that its security level can see your sites. Then select **Trigger sync** on the Datto RMM integration in Neo. ## What Neo Can Do With Datto RMM connected, Neo Agent can: <AccordionGroup> <Accordion title="Script Execution"> * Browse and search your script library * Execute scripts on specific devices * Monitor job status and results * Take automated actions based on script outcomes </Accordion> <Accordion title="Device Management"> * Look up devices by name, serial number, or other identifiers * Access device details and specifications * View installed software and services * Check device status and alerts </Accordion> <Accordion title="Alert Handling"> * Receive and process RMM alerts * Clear alerts after successful remediation * Correlate alerts with PSA tickets </Accordion> <Accordion title="Patch Review and Updates"> * Find the devices that need updates, by patch status (approved and pending, install error, reboot required, no policy) * List the pending, unapproved or installed patches on a device, or across a site, with severity and KB number * Install updates now by running an update component on a device (for example **Install Updates with SUPER \[MAC]** on a Mac), with technician approval when your agent requires it <Info> Neo Agent does not run a Patch Management policy, press **Patch Now** or approve a patch. When no update component fits, Neo gives your technician the devices and their pending patches to install from the Datto RMM console. </Info> </Accordion> </AccordionGroup> ## External Resources <Card title="Datto RMM API Documentation" icon="link" href="https://rmm.datto.com/help/en/Content/2SETUP/APIv2.htm"> Official Datto documentation for detailed API setup and reference. </Card> # Device Mapping Source: https://docs.neoagent.io/integrations/rmm/device-mapping How Neo maps RMM devices to PSA companies — automatically, and how to correct it from the dashboard When Neo syncs devices from your RMM, it links each device to the matching **PSA company** so reports, automations, and agents know which customer a device belongs to. Most devices map automatically; the **Device Mapping** tab lets you see the result and fix any that didn't. <Note> This works the same across every supported RMM — Datto, NinjaOne, N-central, N-Sight, ConnectWise Automate, ConnectWise Asio, and Kaseya VSA X. The mapping is keyed on devices, not on vendor-specific sites or organizations. </Note> ## How Neo maps devices automatically On every RMM sync, Neo resolves each device's PSA company using the strongest signal available: 1. **Exact name match** — the device's RMM organization or site name is matched (case-insensitive) against your synced PSA company names. 2. **Asset overlap** — for devices an exact name can't place, Neo looks up their hostnames among your PSA configuration items and maps the device to the company that owns them, but only when the evidence is near-unanimous. A device that neither signal can place is left **Unmapped**. <Info> Automatic mapping can't resolve every device. Common cases: an RMM organization named differently from the PSA company (a rebrand), sites named by location code rather than company, or a PSA with few or no configuration items to match against. Those devices stay **Unmapped** until you assign them on the Device Mapping tab. </Info> ## The Device Mapping tab Open [**Integrations**](https://dashboard.neoagent.io/integrations), select your connected RMM, and choose the **Device Mapping** tab. The header shows **Total devices**, **Mapped**, and **Unmapped** counts. The table lists each device with: | Column | What it shows | | - | - | | Device | The device name | | Organization / Site | RMM context, where the vendor provides it | | PSA Company | The mapped company (or "—" when unmapped) | | Source | How it was mapped — **Auto**, **Manual**, or **Unmapped** | | Mapped by | Who set a manual mapping, and when | Filter by status (**All**, **Mapped**, **Unmapped**, **Manual**), by company, or by device name. If the sync status on the **Settings** tab shows **No devices found**, Neo received no devices from the RMM. The usual cause is an RMM user that can see no sites or organizations: give the user that Neo signs in with that access, then select **Trigger sync**. ## Assign devices to a company <Steps> <Step title="Filter to what you need"> Use the **Unmapped** status filter to find devices that still need a company (or search by name). </Step> <Step title="Select the devices"> Tick individual rows, or use the header checkbox to select the current page. When more devices match than fit on one page, click **Select all N matching** to select the entire filtered set across pages. </Step> <Step title="Assign to a company"> In the action bar, click **Assign to company**, pick a PSA company, and confirm. Filtering to *Unmapped*, selecting all, and assigning is a single action — no paging through devices one screen at a time. </Step> </Steps> <Tip> The company picker lists your synced PSA companies — the same set Neo uses everywhere else. If a company is missing, run a PSA sync first. </Tip> ### Manual assignments stick A manually assigned device is marked **Manual** and **keeps its company through every future RMM sync** — Neo's automatic mapping never overwrites a manual choice. ### Reset to automatic To hand a device back to automatic mapping, select it and choose **Reset to auto** in the action bar. Neo recomputes the device's company on the next sync. # Overview Source: https://docs.neoagent.io/integrations/rmm/intro Connect your Remote Monitoring and Management tools to allow Neo to find and run scripts When you connect your RMM with Neo, Neo gains visibility into all of your scripts and registered devices. Neo can then suggest relevant scripts to technicians working on tickets, or execute scripts directly against devices—monitoring jobs and taking automated actions based on the results. Neo also links each synced device to its PSA company so reports, automations, and agents know which customer it belongs to — see [Device mapping](/integrations/rmm/device-mapping) for how that works and how to correct it. You can connect **more than one RMM at the same time** — for example your main RMM plus ScreenConnect, or two RMMs during a migration. Each connected RMM gets its own card on the Integrations page with independent credentials, sync, and last-sync status, and every synced device and script stays tied to the RMM it came from, so agents always act through the right platform. <Tip> Setting up your RMM with Neo is a simple process. You will need to generate API credentials for your RMM and then configure the integration in Neo. </Tip> ## Use Cases Neo's RMM integration enables two powerful categories of automation: ### Issue Remediation — Zero Human Touch Neo can automatically execute scripts to resolve common issues without technician intervention: * **Software management** — Installing, updating, or repairing applications * **Device maintenance** — Rebooting devices, clearing caches, removing temp files * **Service management** — Starting, stopping, or restarting services and processes * **Any typical RMM task** — If you have a script for it, Neo can run it <Info> You control the level of automation. Neo can either execute scripts automatically or request approval from a technician before taking action. </Info> After executing a script, Neo monitors the job and takes intelligent follow-up actions based on the result: * **Success** — Close the ticket and notify the end user * **Failure** — Escalate to a technician or try an alternative remediation * **Partial success** — Document findings and recommend next steps ### Revenue & Opportunity Creation Neo can identify upsell and service opportunities by combining RMM data with intelligent automation. <AccordionGroup> <Accordion title="Example: Disk space alert triggers upgrade opportunity"> When a device triggers an alert for 95% disk usage: 1. Neo receives the ticket and runs a cleanup script 2. Neo waits for the result (disk usage drops to 90%) 3. Neo checks the device age from your RMM 4. If the device is over 5 years old, Neo automatically messages the customer: > "Your device is over 5 years old and running low on storage. Would you like a quote for an upgrade?" This transforms a routine maintenance ticket into a potential hardware sale. </Accordion> <Accordion title="Example: Recurring issues trigger service review"> When Neo detects a pattern of repeated issues on a device: 1. Neo resolves the immediate issue 2. Neo analyzes ticket history for the device 3. Neo identifies the recurring pattern 4. Neo reaches out to the customer suggesting a proactive maintenance plan or device refresh </Accordion> </AccordionGroup> <Tip> Configure Neo's automation rules to match your business processes. You decide which actions Neo takes automatically and which require human approval. </Tip> ## Supported RMM Platforms Select your RMM platform to view the complete setup guide: <CardGroup> <Card title="ConnectWise Automate" icon="gear" href="/integrations/rmm/connectwise-automate/overview"> Connect using API credentials with dedicated user class permissions. </Card> <Card title="ConnectWise Asio" icon="diagram-project" href="/integrations/rmm/connectwise-rmm/overview"> Connect using API access credentials. Script suggestions and execution supported. </Card> <Card title="Datto RMM" icon="shield" href="/integrations/rmm/datto/overview"> Integrate using API key and secret with administrator security levels. </Card> <Card title="N-Able N-Sight" icon="eye" href="/integrations/rmm/n-able-n-sight/overview"> Connect using API key authentication with monitoring permissions. </Card> <Card title="N-Able N-Central" icon="server" href="/integrations/rmm/n-able-n-central/overview"> Integrate using role-based permissions and dedicated API user. </Card> <Card title="NinjaOne" icon="bolt" href="/integrations/rmm/ninjaone/overview"> Connect using secure OAuth authentication flow—no API keys required. </Card> <Card title="Kaseya VSA X" icon="key" href="/integrations/rmm/vsax/overview"> Connect using a Third-Party Token (Token ID + Token Secret) from your VSA X tenant. </Card> <Card title="Syncro RMM" icon="wrench" href="/integrations/rmm/syncro/overview"> Connects automatically with the Syncro PSA. Note Neo cannot run or report on scripts through Syncro's API. </Card> <Card title="Addigy" icon="apple" href="/integrations/rmm/addigy/overview"> Connect with one API key. Manages Apple devices only. Agents find and run Addigy scripts through the shared RMM script tools, and run ad-hoc commands through the RMM API tool. </Card> </CardGroup> ## Quick Setup Summary | RMM Platform | Authentication Method | Typical Setup Time | | - | - | - | | ConnectWise Automate | User Class + API Credentials | 10-15 minutes | | ConnectWise Asio | Client ID + Client Secret | 5-10 minutes | | Datto RMM | API Key + Secret | 5-10 minutes | | N-Able N-Sight | API Key | 5-10 minutes | | N-Able N-Central | Role-Based API User | 10-15 minutes | | NinjaOne | OAuth (No API Keys) | 2-5 minutes | | Kaseya VSA X | Third-Party Token (ID + Secret) | 5-10 minutes | | Syncro RMM | Shares the Syncro PSA token | Automatic with the PSA | | Addigy | API Key | — | ## When an agent reports the RMM is not fully configured An agent that tries to read from your RMM may answer with a message like: > NinjaOne is connected for this client but not fully configured: its region is missing. Retrying will not help — every NinjaOne call fails the same way until an administrator reconnects NinjaOne on the Integrations page of the Neo dashboard. This means the RMM card shows as connected, but Neo cannot build a single call to that platform. Either a credential it needs is not stored — the NinjaOne region, or an API URL, key, or secret for a credential-based RMM — or, for NinjaOne, the stored authorization has expired or been revoked. The message tells the agent to stop calling that RMM for the rest of the run, carry on with the checks it can still do, and record the ones it could not. To fix it, open the [Integrations page](https://dashboard.neoagent.io/integrations), disconnect the RMM named in the message, and reconnect it — the connect flow writes the full credential set in one step. Scheduled agents pick the RMM up on their next run. Reconnecting does not replay a run that already finished, so for a ticket an agent handled without its RMM checks, open the agent in **Executions** and use **Run now** on that ticket (see [Agents](/core/agents)). <Info> Neo names the platform and what is wrong with it in the message rather than reporting a server error, so the message can tell the agent to stop calling that RMM instead of retrying a call that cannot succeed. </Info> <Tip> All integrations can be configured from the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations). Navigate to the RMM section and select your platform to begin. </Tip> # Overview Source: https://docs.neoagent.io/integrations/rmm/n-able-n-central/overview Connect your N-Able N-Central to Neo Agent for automated script execution and device management Neo Agent accesses your automation policies, devices, and monitoring data through the N-Able N-Central integration. ## Prerequisites Before starting the integration setup, ensure you have: * Administrator access to your N-Central instance * Ability to create users and configure role-based permissions * Permissions to create dedicated API users ## Setup Guide <Steps> <Step title="Create API user"> Set up a dedicated API user account with appropriate role-based permissions: 1. Navigate to **Administration → User Management** 2. Click **Create User** or **Add New User** 3. Configure the user details: * **Username**: Use a descriptive name (e.g., `neo_agent_api`) * **Email**: Set to a monitored email for notifications * **Authentication**: Configure for API access </Step> <Step title="Configure role-based permissions"> Assign the necessary permissions for monitoring, alerting, and automation tasks: 1. Navigate to **Administration → Role Based Permissions** 2. Create a new role or modify an existing one for Neo Agent 3. Enable the following permission categories: * **Devices**: Read and manage device information * **Automation**: Execute scripts and automation policies * **Monitoring**: Access monitoring data and alerts * **Alerts**: View and manage alerts <Warning> Insufficient permissions will cause Neo Agent to fail when attempting certain operations. Start with broader permissions and narrow down as needed. </Warning> </Step> <Step title="Generate API credentials"> Generate the authentication credentials for your API user: 1. Access the API user settings 2. Generate an API key or JWT token based on your N-Central configuration 3. Securely store the credentials <Check> Note down the API endpoint URL for your N-Central instance as you'll need this during configuration. </Check> </Step> <Step title="Configure in Neo Agent"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and select **N-Able N-Central** from the RMM integrations. Enter your credentials: * **API URL**: Your N-Central instance URL * **API Key/Token**: The authentication credential generated * **Additional settings**: Any region or instance-specific configuration </Step> <Step title="Test and save"> Neo Agent will validate your credentials and establish the connection. <Check> A successful connection allows Neo to access your devices, automation policies, and monitoring data. </Check> </Step> </Steps> ## Role-Based Permissions Reference Configure the following permissions for the Neo Agent API user: ### Device Management | Permission | Level | Purpose | | - | - | - | | View Devices | All | Access device inventory and details | | Manage Devices | All | Execute management tasks on devices | | Device Properties | Read/Write | Access and update device properties | ### Automation | Permission | Level | Purpose | | - | - | - | | View Scripts | All | Browse available automation scripts | | Execute Scripts | All | Run scripts on managed devices | | Automation Policies | Read | Access automation policy configurations | ### Monitoring and Alerts | Permission | Level | Purpose | | - | - | - | | View Monitoring | All | Access monitoring check results | | View Alerts | All | Access active and historical alerts | | Manage Alerts | All | Clear and acknowledge alerts | <Info> Permission levels may vary based on your N-Central version. Consult the N-Central documentation for your specific version's permission structure. </Info> ## What Neo Can Do With N-Able N-Central connected, Neo Agent can: <AccordionGroup> <Accordion title="Automation Policy Execution"> * Browse available automation policies and scripts * Execute automation on specific devices * Monitor automation job status * Take follow-up actions based on results </Accordion> <Accordion title="Device Management"> * Look up devices across your managed clients * Access device details, status, and properties * View software inventory and installed applications * Identify devices related to tickets or end users </Accordion> <Accordion title="Monitoring and Alerts"> * Access real-time monitoring data * Process and respond to alerts * Clear alerts after successful remediation * Correlate monitoring status with ticket context </Accordion> </AccordionGroup> ## Troubleshooting <AccordionGroup> <Accordion title="Authentication Errors"> * Verify the API credentials are entered correctly * Check that the API user account is active * Ensure the API URL is correct for your instance * Confirm the authentication method matches your configuration </Accordion> <Accordion title="Permission Denied"> * Review the role-based permissions for your API user * Ensure all required permission categories are enabled * Check for any customer/site level permission restrictions </Accordion> <Accordion title="Devices or Scripts Not Visible"> * Verify the API user has access to the relevant customers/sites * Check device-level and script-level permissions * Ensure automation policies are not restricted </Accordion> </AccordionGroup> ## External Resources <Card title="N-Able N-Central API Documentation" icon="link" href="https://documentation.n-able.com/N-central/userguide/Content/User_Management/Role%20Based%20Permissions/role_based_permissions_create_APIuser.htm"> Official N-Able documentation for creating API users with role-based permissions. </Card> # Overview Source: https://docs.neoagent.io/integrations/rmm/n-able-n-sight/overview Connect your N-Able N-Sight RMM to Neo Agent for automated script execution and device management ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Administrator access to your N-Sight RMM dashboard * **API Permissions**: Ability to generate and manage API keys * **Account Access**: Access to the API configuration section ## Setup Guide <Steps> <Step title="Access API settings"> Log into your N-Sight RMM dashboard and navigate to the API configuration section. 1. Go to **Settings** in the main navigation 2. Select **API Settings** or **Manage API Keys** <Info> The exact location may vary slightly based on your N-Sight RMM version and configuration. </Info> </Step> <Step title="Generate API key"> Create a new API key with the appropriate permissions for monitoring and automation: 1. Click **Generate New API Key** or **Add API Key** 2. Provide a descriptive name (e.g., "Neo Agent Integration") 3. Configure the key permissions to include: * Device access (read/write) * Script execution * Alert management * Monitoring data access 4. Generate the key and securely store both the **API Key** and **Secret** <Warning> The API secret is only shown once during generation. Store it securely as you cannot retrieve it later. </Warning> </Step> <Step title="Configure in Neo Agent"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and select **N-Able N-Sight** from the RMM integrations. Enter your credentials: * **API Key**: The key generated from N-Sight * **API Secret**: The secret associated with your API key <Check> Make sure to enter the credentials exactly as provided - they are case-sensitive. </Check> </Step> <Step title="Test and save"> Neo Agent will validate your credentials and establish the connection to your N-Sight RMM instance. <Check> A successful connection allows Neo Agent to access your devices, scripts, and monitoring data. </Check> </Step> </Steps> ## Required Permissions Ensure your API key has the following permissions enabled: | Permission | Purpose | | - | - | | Devices - Read | Access device information and inventory | | Devices - Write | Execute scripts and management tasks | | Scripts - Execute | Run automation scripts on devices | | Alerts - Read | Access and process monitoring alerts | | Alerts - Write | Clear alerts after remediation | | Monitoring - Read | Access monitoring data and status | <Tip> Create a dedicated API key specifically for Neo Agent rather than using an existing key. This makes it easier to manage permissions and audit API access. </Tip> ## What Neo Can Do With N-Able N-Sight connected, Neo Agent can: <AccordionGroup> <Accordion title="Script Execution"> * Browse available scripts in your library * Execute scripts on specific devices or device groups * Monitor script execution status * Process script results for automated follow-up actions </Accordion> <Accordion title="Device Management"> * Look up devices by various identifiers * Access device details, hardware specs, and software inventory * View device status and health metrics * Identify devices associated with end users or tickets </Accordion> <Accordion title="Monitoring and Alerts"> * Access monitoring check results * Process and respond to alerts * Clear alerts after successful remediation * Correlate monitoring data with ticket context </Accordion> </AccordionGroup> ## Troubleshooting <AccordionGroup> <Accordion title="Connection Failed"> * Verify the API Key and Secret are entered correctly * Check that the API key has not expired * Ensure the API key has the required permissions * Confirm API access is enabled for your account </Accordion> <Accordion title="Permission Denied Errors"> * Review the API key permissions in N-Sight * Ensure all required permissions are enabled * Regenerate the API key if permissions were changed after creation </Accordion> <Accordion title="Devices Not Appearing"> * Check that the API key has device read permissions * Verify the devices are active and checking in * Ensure site/client access permissions are configured </Accordion> </AccordionGroup> ## External Resources <Card title="N-Able N-Sight API Documentation" icon="link" href="https://developer.n-able.com/n-sight/docs/generate-an-api-key"> Official N-Able developer documentation for API key generation and reference. </Card> # Overview Source: https://docs.neoagent.io/integrations/rmm/ninjaone/overview Connect your NinjaOne RMM to Neo Agent for automated script execution and device management NinjaOne integration enables Neo Agent to access your scripts, devices, and monitoring data through a streamlined OAuth authentication flow. <Info> NinjaOne uses OAuth 2.0 for authentication, which provides a secure and simple setup process. No API keys to manage—just authenticate through the consent flow. </Info> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Administrator access to your NinjaOne instance * **OAuth Consent**: Ability to approve third-party application access * **Region Information**: Know which region your NinjaOne instance is hosted in ## Setup Guide <Steps> <Step title="Select your region"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and select **NinjaOne** from the RMM integrations. Select your NinjaOne region from the dropdown. This must match the region where your NinjaOne instance is hosted: | Region | Description | | - | - | | US | United States data center | | EU | European Union data center | | OC | Oceania (Australia/New Zealand) data center | <Warning> Selecting the wrong region will cause authentication to fail. Check your NinjaOne login URL to confirm your region. </Warning> </Step> <Step title="Authenticate with NinjaOne"> Click the **Authenticate** button to start the OAuth consent flow. A popup window will open directing you to NinjaOne's authentication page: 1. Log in with your NinjaOne administrator credentials 2. Review the permissions Neo Agent is requesting 3. Click **Authorize** or **Allow** to grant access <Info> You must be an administrator of your NinjaOne instance to complete the consent flow. Standard users cannot authorize third-party integrations. </Info> </Step> <Step title="Complete the consent flow"> Once you've authorized access, you'll be redirected back to Neo Agent. <Check> The integration status will update to show NinjaOne is connected. Neo Agent now has access to your devices and scripts. </Check> </Step> </Steps> ## OAuth Permissions When authorizing Neo Agent, you'll grant access to the following: | Permission | Purpose | | - | - | | Devices - Read | Access device information and inventory | | Devices - Manage | Execute scripts and management tasks | | Scripts - Read | Browse available automation scripts | | Scripts - Execute | Run scripts on managed devices | | Alerts - Read | Access monitoring alerts | | Alerts - Manage | Clear and acknowledge alerts | | Organizations - Read | Access client/organization information | <Tip> Neo Agent only requests the permissions necessary for automation. Your NinjaOne data remains secure, and you can revoke access at any time from your NinjaOne settings. </Tip> ## What Neo Can Do With NinjaOne connected, Neo Agent can: <AccordionGroup> <Accordion title="Script Execution"> * Browse your script library organized by categories * Execute scripts on specific devices or device groups * Monitor script job status in real-time * Process script output for automated decision-making </Accordion> <Accordion title="Device Management"> * Search devices by name, serial number, or other attributes * Access comprehensive device details and specifications * View installed software and running processes * Identify devices associated with end users or organizations </Accordion> <Accordion title="Monitoring and Alerts"> * Access active alerts and monitoring conditions * Process alerts for automated remediation * Clear alerts after successful resolution * Correlate device status with ticket context </Accordion> <Accordion title="Organization Management"> * Access organization/client information * Map organizations to PSA companies * Filter devices and scripts by organization </Accordion> </AccordionGroup> ## Managing the Integration ### Refreshing Authorization OAuth tokens automatically refresh, but if you encounter authentication issues: 1. Navigate to the NinjaOne integration in Neo Agent 2. Click **Reconnect** or **Re-authenticate** 3. Complete the OAuth flow again ### Revoking Access To disconnect Neo Agent from NinjaOne: 1. In Neo Agent: Navigate to integrations and click **Disconnect** for NinjaOne 2. In NinjaOne: Go to **Administration → Apps** and revoke access for Neo Agent <Warning> Revoking access will immediately stop all Neo Agent automations that rely on NinjaOne. Ensure you have alternative processes in place before disconnecting. </Warning> ## Troubleshooting <AccordionGroup> <Accordion title="OAuth Popup Blocked"> * Check your browser's popup blocker settings * Allow popups from `dashboard.neoagent.io` * Try using a different browser </Accordion> <Accordion title="Wrong Region Selected"> * Disconnect the integration in Neo Agent * Verify your region by checking your NinjaOne login URL * Reconnect with the correct region selected </Accordion> <Accordion title="Consent Flow Fails"> * Ensure you're logged into NinjaOne as an administrator * Check that third-party app access is not disabled in your NinjaOne settings * Contact NinjaOne support if organization policies restrict OAuth apps </Accordion> <Accordion title="Agent Says NinjaOne Is Not Fully Configured"> * Either the connection is missing its region, or its stored authorization has expired or been revoked — Neo cannot build a NinjaOne API call in either case * Disconnect NinjaOne on the [Integrations page](https://dashboard.neoagent.io/integrations) and reconnect it, selecting your region * See [When an agent reports the RMM is not fully configured](/integrations/rmm/intro#when-an-agent-reports-the-rmm-is-not-fully-configured) </Accordion> <Accordion title="Devices Not Appearing"> * Verify the OAuth authorization completed successfully * Check that your NinjaOne user has access to the relevant organizations * Ensure devices are active and checking into NinjaOne </Accordion> </AccordionGroup> ## External Resources <CardGroup> <Card title="NinjaOne API Documentation" icon="link" href="https://app.ninjarmm.com/apidocs/"> Official NinjaOne API reference and documentation. </Card> <Card title="NinjaOne Support" icon="headset" href="https://www.ninjaone.com/support/"> Contact NinjaOne support for platform-specific questions. </Card> </CardGroup> # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/rmm/screenconnect/connecting-to-neo Configure the connection between your ConnectWise ScreenConnect instance and Neo Agent Once you've [created an API secret](/integrations/rmm/screenconnect/creating-the-secret) in ScreenConnect, connect it to Neo Agent through the integrations dashboard. <Info> You'll need your instance URL and the RESTful API Manager authentication secret to complete this setup. </Info> ## Required Information <ParamField type="string"> Your ScreenConnect instance URL, e.g. `https://yourcompany.screenconnect.com`. Enter just the host — the API path is appended automatically. </ParamField> <ParamField type="string"> The **RESTful Authentication Secret** from the RESTful API Manager extension. </ParamField> <Info> ScreenConnect authenticates with a single secret — there is no separate client ID, so the Neo form only asks for the URL and the Client Secret. </Info> ## Configuring the Integration <Steps> <Step title="Access the Neo Agent Dashboard"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and log in. </Step> <Step title="Navigate to RMM Integrations"> From the dashboard: 1. Click **Integrations** in the left sidebar 2. Select the **RMM** category 3. Find and select **ConnectWise ScreenConnect** from the list of available RMM integrations <Frame> <img alt="Neo Agent Integrations page showing the RMM category with the ConnectWise ScreenConnect tile" /> </Frame> </Step> <Step title="Enter Your Credentials"> Complete the ConnectWise ScreenConnect integration setup form: 1. **RMM URL**: Enter your instance URL (e.g. `https://yourcompany.screenconnect.com`) 2. **RMM Client Secret**: Enter your RESTful Authentication Secret <Frame> <img alt="Neo Agent ConnectWise ScreenConnect setup form showing the RMM URL and RMM Client Secret fields" /> </Frame> <Warning> Double-check both values for accuracy. An incorrect URL or secret will prevent Neo Agent from connecting to your ScreenConnect instance. </Warning> </Step> <Step title="Submit Configuration"> Click **Submit**. Neo Agent validates the secret against your instance and establishes the connection. <Check> A successful connection confirms Neo Agent can reach your ScreenConnect instance with the provided secret. </Check> </Step> </Steps> ## Troubleshooting Connection Issues <AccordionGroup> <Accordion title="Authentication Errors (401 / 403)"> * Verify the authentication secret is correct and copied without extra spaces * Confirm the RESTful API Manager extension is installed and enabled * Check that the secret hasn't been rotated in the extension settings since you copied it * Confirm the instance URL is correct (just the host, e.g. `https://yourcompany.screenconnect.com`) </Accordion> <Accordion title="API Endpoint Not Found (404)"> A 404 means the request reached your ScreenConnect instance but never reached the RESTful API Manager, so the secret was never checked. There are two causes: * The **RESTful API Manager extension is not installed** (or is disabled) on the instance — see [Creating the Secret](/integrations/rmm/screenconnect/creating-the-secret) * The **instance URL is wrong** — enter only the host, e.g. `https://yourcompany.screenconnect.com`, with no path If this happens after the integration is already connected, Neo posts an **Action Required** message to your [Inbox](/product/inbox) and emails your admins, then retries on the next device sync. Once the extension is installed or the URL is corrected, the next sync succeeds and no new message is posted — mark the existing message as read in your Inbox to clear it. </Accordion> <Accordion title="Devices Not Appearing"> * Wait a few minutes for the initial sync to complete after connecting * Confirm the instance has installed (access) agents — Neo reads ScreenConnect **Access** sessions as devices </Accordion> </AccordionGroup> ## Configuring Permission Groups Once connected, open **Agent Settings → Permission Groups** to choose what the agent may do in ScreenConnect. Each group can be **Disabled**, **Read-only**, or **Read & Write**: | Group | Read | Write | | - | - | - | | **Sessions** | Find sessions, read session detail (OS, last-contact, custom properties) and command output | Create sessions, rename, update custom properties, add notes | | **Commands** | — | Send a shell/PowerShell command and read the output | | **Toolbox & Messaging** | — | Run a pre-staged Toolbox item, send a chat message to the end user | <Warning> ScreenConnect commands run as **SYSTEM** (Windows) or **root** (macOS/Linux). Enable **Require approval** on the Commands group to gate every command behind a technician before it runs. </Warning> ## What's Next? With ScreenConnect connected, Neo can: * **Device lookup** — pull session status, OS, and last-contact time while triaging tickets * **Company mapping** — associate sessions with the right PSA company by name * **Remote action** — run a command or Toolbox item and message the end user, where you've granted write access # Creating an API Secret Source: https://docs.neoagent.io/integrations/rmm/screenconnect/creating-the-secret Install the RESTful API Manager extension in ScreenConnect and set its authentication secret Neo Agent connects to ScreenConnect through the **RESTful API Manager** extension. Install it once, set an authentication secret, and copy that secret into Neo Agent. <Info> You need an administrator account on your ScreenConnect instance to install extensions and edit their settings. </Info> ## Installing the RESTful API Manager <Steps> <Step title="Open Extensions"> In your ScreenConnect instance, open **Administration** (the gear icon in the lower-left), then select **Extensions**. Click **Browse Extension Marketplace**. <Frame> <img alt="ScreenConnect Administration page with the Extensions section selected and the Browse Extension Marketplace button highlighted" /> </Frame> </Step> <Step title="Find and install RESTful API Manager"> In the marketplace, search for **RESTful API Manager** and install it. <Frame> <img alt="ScreenConnect Extension Marketplace showing the RESTful API Manager extension matching a search for Restful" /> </Frame> </Step> <Step title="Open the extension's settings"> Back on the **Extensions** page, find the installed **RESTful API Manager**, open its **...** menu, and choose **Edit Settings**. <Frame> <img alt="Installed RESTful API Manager extension with its context menu open showing Disable, Uninstall, and Edit Settings" /> </Frame> </Step> <Step title="Set the authentication secret"> Set **RESTfulAuthenticationSecret** to **Custom** and enter a randomly generated long string (a GUID works well). This is the value you enter in Neo Agent as the **Client Secret**. Click **Save Settings**. <Frame> <img alt="Edit Extension Settings dialog with RESTfulAuthenticationSecret set to a custom value" /> </Frame> <Warning> Treat the authentication secret like a password — anyone with it and your instance URL can call your ScreenConnect API. Generate a fresh one here if it is ever exposed. </Warning> </Step> </Steps> ## About the Other Settings The Edit Settings dialog also exposes two optional fields: * **RESTfulUserName** — the name shown next to events that API calls create. Leave it at the default (`RESTful API`) or set your own. * **RESTfulAllowedOrigin** — if set, every request's `Origin` must match this value. Neo sends your instance URL as the `Origin`, so you can either **leave this empty** (Origin validation off) or set it to your instance host (e.g. `yourcompany.screenconnect.com`). Both work with Neo. ## What You'll Need for Neo Agent | Value | Where to find it | | - | - | | **Instance URL** | The address you use to sign in, e.g. `https://yourcompany.screenconnect.com` | | **Authentication secret** | RESTful API Manager → Edit Settings → RESTfulAuthenticationSecret | <Check> With your instance URL and the authentication secret in hand, continue to [Connecting to Neo Agent](/integrations/rmm/screenconnect/connecting-to-neo). </Check> # Overview Source: https://docs.neoagent.io/integrations/rmm/screenconnect/overview Connect your ConnectWise ScreenConnect (Control) instance to Neo Agent for device context, remote command execution, and end-user messaging ## Setup Overview Setting up the ConnectWise ScreenConnect integration involves two main steps: <CardGroup> <Card title="Creating an API Secret" icon="key" href="/integrations/rmm/screenconnect/creating-the-secret"> Install the RESTful API Manager extension in ScreenConnect and copy its authentication secret. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/rmm/screenconnect/connecting-to-neo"> Configure the connection between your ScreenConnect instance and Neo Agent using your instance URL and the API secret. </Card> </CardGroup> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: An administrator account on your ScreenConnect instance with permission to install and configure extensions * **Your instance URL**: e.g. `https://yourcompany.screenconnect.com` <Info> ConnectWise ScreenConnect (also sold as **ConnectWise Control**) is a remote-support and access tool. Neo Agent talks to it through the **RESTful API Manager** extension — there is no separate REST API to enable, just the extension and its authentication secret. </Info> ## What Neo Can Do with ScreenConnect Neo Agent reads installed-agent (session) data and, where you allow it, runs commands and messages end users — gated by per-area permission groups you configure in Agent Settings. <Warning> **API actions only — not interactive remote control.** Neo works through the RESTful API Manager: it queries devices, runs commands and Toolbox items, and messages end users programmatically. Neo does **not** start an interactive remote-control session — no screen viewing or takeover, no manual keyboard/mouse control, and it never "logs in" to drive the desktop by hand. A technician still does that from the ScreenConnect client. </Warning> <AccordionGroup> <Accordion title="Sessions & Devices"> * **Session lookup** — find installed agents by name or filter, read session detail (operating system, last-contact time, online status, custom properties) * **Command output** — read the result of commands queued on a session * **Write** — create support sessions, rename sessions, update custom properties, add notes </Accordion> <Accordion title="Commands"> * **Execute** — send a shell or PowerShell command to a session and read back the output <Warning> ScreenConnect commands run with the agent's privileges — **SYSTEM** on Windows, **root** elsewhere. Enable **Require approval** on the Commands group to gate every command behind a technician. </Warning> </Accordion> <Accordion title="Toolbox & Messaging"> * **Toolbox** — run a pre-staged Toolbox item on the endpoint * **Messaging** — send a chat message to the logged-on end user </Accordion> </AccordionGroup> <Tip> Write access is opt-in per area. In Agent Settings → Permission Groups, set the relevant ScreenConnect groups to **Read & Write** to enable session writes, command execution, and messaging. </Tip> ## Available Actions | Category | Actions | Status | | - | - | - | | **Sessions** | Find sessions, read session detail and command output | Available (read) | | **Sessions** | Create sessions, rename, update custom properties, add notes | Available (read/write) | | **Commands** | Send a shell/PowerShell command and read the output | Available (read/write) | | **Toolbox & Messaging** | Run a pre-staged Toolbox item, send a chat message to the end user | Available (read/write) | <Info> Neo Agent uses the ScreenConnect RESTful API Manager. There is no script catalog — Neo sends the command text directly, so no scripts need to be pre-registered for command execution. </Info> # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/rmm/syncro/connecting-to-neo Syncro RMM connects automatically with the Syncro PSA — and how to connect it separately if you want a different token ## Most of the time, there is nothing to do Syncro is one product with two surfaces, so **connecting the Syncro PSA connects the RMM as well**. If your API token can read assets, the Syncro RMM card on the Integrations page will already say **Connected**, using the same credentials. <Info> Nothing to configure, and nothing to keep in sync: rotating your Syncro API token on the PSA updates the RMM at the same time. </Info> If the RMM card is **not** connected after you set up the PSA, the usual cause is the token's permissions — see [Creating an API Token](/integrations/psa/syncro/creating-api-token) and confirm **Assets** is included. Neo deliberately leaves the RMM disconnected rather than connecting one whose very first call would fail. ## Connecting with a different token Connect the RMM here only if you want it to use its own credentials — for example a token scoped more narrowly than the PSA's. <Steps> <Step title="Open the Integrations page"> In the Neo dashboard, go to **Integrations**, then find **Syncro RMM** under the RMM category. </Step> <Step title="Enter your Syncro details"> * **RMM URL** — your Syncro subdomain, e.g. `https://yourcompany.syncromsp.com` * **API key** — a Syncro API token whose permissions include **Assets** </Step> <Step title="Save"> Neo verifies the token by reading your assets before saving. A token that cannot read assets is rejected at this point rather than failing later. </Step> </Steps> <Note> **A token you enter here is yours.** Once you connect the RMM manually, re-saving the Syncro PSA will not overwrite it, and switching your PSA away from Syncro will not remove it. </Note> ## Disconnecting Disconnecting the Syncro RMM from its card is remembered: re-saving the PSA later will not silently turn it back on. To re-enable it, connect it from the card again. ## Verifying After connecting, devices appear on the next sync. To check sooner, open **Companies** and confirm devices are listed against the right customer — on a tenant running Syncro for both PSA and RMM, that mapping is exact rather than a name match. <Tip> Before assuming something is missing, check [what the Syncro API cannot do](/integrations/rmm/syncro/overview#what-the-syncro-api-cannot-do) — most notably, Neo cannot run or report on scripts through Syncro, and Windows patch data does not exist for Mac or Linux devices. </Tip> # Overview Source: https://docs.neoagent.io/integrations/rmm/syncro/overview Connect Syncro's RMM side to Neo Agent for device, software, patch and alert context — and what Syncro's API cannot do Syncro is one product with two surfaces: the PSA (tickets, customers, invoicing) and the RMM (managed devices, alerts). Neo treats them as **two integrations**, because an MSP can run Syncro RMM alongside a completely different PSA. <Info> **If you have already connected the Syncro PSA, the RMM is probably connected too.** Connecting the PSA with a token that can read assets connects the RMM for you — see [Connecting to Neo Agent](/integrations/rmm/syncro/connecting-to-neo). You only need that page if you want the RMM to use a different token. </Info> ## What Neo Can Do with Syncro RMM Neo reads device, software, patch and alert data, and — where you allow it — acts on alerts. Every area is gated by the permission groups you configure in Agent Settings. <AccordionGroup> <Accordion title="Devices"> * **Device lookup** — find managed devices, read their detail (operating system, serial, model, memory, last user, agent version) * **Company mapping** — each device is matched to the right customer automatically. On a tenant that runs Syncro for *both* PSA and RMM this is exact rather than a name match, because it is the same customer record on both sides * **Write** — create an asset, or update its name, customer, serial, type and properties (opt-in per the Devices permission group) </Accordion> <Accordion title="Software & Patches"> * **Installed applications** — the software inventory for a device, read on demand * **Patch status** — Windows patch state for a device <Note> Patch data is **Windows only**. A Mac or Linux device returns nothing here — that is Syncro's behaviour, not a gap in Neo. </Note> </Accordion> <Accordion title="Alerts"> * **Read** — query RMM alerts and the device that raised each one * **Write** — mute an alert, raise a new one, or resolve one <Warning> **Muting is permanent.** Syncro's API has no snooze — the only mute it accepts silences that monitor on that device indefinitely, for your technicians too, not just for Neo. So muting always asks for technician approval, even when the group is set to autonomous. </Warning> <Warning> Resolving an alert clears it from your technicians' console and Neo cannot undo it, so it sits behind its own **Resolve** toggle and always asks for technician approval — even when the rest of the group is set to autonomous. </Warning> Raising an alert is the one alert write that can run unattended: it is reversible, since resolving it puts things back. </Accordion> </AccordionGroup> ## What the Syncro API Cannot Do Read this section before comparing Syncro RMM against another RMM you use. These are limits of **Syncro's own API**, not features Neo has not built yet — Neo cannot work around them, and no setting will turn them on. ### Scripts: Neo cannot run or report on them **Syncro's API exposes no way to run a script that Neo can act on, and no way to query one.** * There is **no endpoint to list scripts**, so Neo cannot show you which scripts exist or let an agent choose one. * There is **no endpoint to read a script's result** — no output, no exit code, no run history. * Syncro does have a single "schedule a script" call, but it returns nothing beyond an acknowledgement: no run identifier, and no way to ask later what happened. Because Neo could never tell you whether a script succeeded, what it printed, or even that it finished, **script execution is not offered for Syncro at all**. Neo will say so plainly rather than start something it cannot report on. If a ticket needs a script, run it from the Syncro console. <Warning> This is the biggest difference from ConnectWise Automate, NinjaOne, Datto and the rest, where Neo can run a script and read its output. If your automations depend on that, Syncro RMM cannot replace them today. </Warning> Syncro lists script execution via the public API as shipping soon on their [public roadmap](https://syncrosecure.com/platform/roadmap/). Neo will support it once the API can report what a run did. ### Other limits * **No webhooks for RMM alerts.** Nothing pushes an alert to Neo — an agent reads them when it needs them, so a new alert does not on its own start a workflow. * **No recurring schedules** through the API. ## Available Actions | Category | Actions | Status | | - | - | - | | **Devices** | Find devices, read device detail, read installed applications and Windows patch status | Available (read) | | **Devices** | Create an asset; update name, customer, serial, type, properties | Available (read/write) | | **Alerts** | Read alerts and the device that raised them | Available (read) | | **Alerts** | Raise a new alert | Available (read/write) | | **Alerts** | Mute an alert (permanent — no snooze) | Available (read/write + approval) | | **Alerts** | Resolve an alert | Available (read/write + approval) | | **Scripts** | Run a script, read script output, list scripts | **Not available** — Syncro's API cannot report a result | <Tip> Write access is opt-in per area. In Agent Settings → Permission Groups, set the Syncro RMM **Alerts** group to **Read & Write** to allow raising and muting alerts (enable **Resolve** separately; muting and resolving both ask for approval), or the **Devices** group to allow asset writes. </Tip> ## Prerequisites * A Syncro account with the RMM in use and at least one agent installed * A Syncro API token whose permissions include **Assets** — the same token used for the [Syncro PSA integration](/integrations/psa/syncro/overview) is fine, and is what Neo uses by default # Connecting to Neo Agent Source: https://docs.neoagent.io/integrations/rmm/vsax/connecting-to-neo Configure the connection between your Kaseya VSA X tenant and Neo Agent Once you've [created a Third-Party Token](/integrations/rmm/vsax/creating-api-key) in VSA X, connect it to Neo Agent through the integrations dashboard. <Info> You'll need your tenant URL, Token ID, and Token Secret from VSA X to complete this setup. </Info> ## Required Information <ParamField type="string"> Your VSA X tenant URL, e.g. `https://yourtenant.vsax.net`. The `/api/v3` path is appended automatically — enter just the host. </ParamField> <ParamField type="string"> Your VSA X **Token ID**. </ParamField> <ParamField type="string"> Your VSA X **Token Secret**. </ParamField> <Info> VSA X calls these the **Token ID** and **Token Secret**; the Neo form labels them **Client Id** and **Client Secret** (the shared credential fields used across RMMs). They're the same values. </Info> ## Configuring the Integration <Steps> <Step title="Access the Neo Agent Dashboard"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and log in. </Step> <Step title="Navigate to RMM Integrations"> From the dashboard: 1. Click **Integrations** in the left sidebar 2. Select the **RMM** tab 3. Find and select **Kaseya VSA X** from the list of available RMM integrations <Frame> <img alt="Neo Agent dashboard Integrations page with RMM tab selected and Kaseya VSA X tile visible" /> </Frame> </Step> <Step title="Enter Your Credentials"> Complete the Kaseya VSA X integration setup form: 1. **RMM URL**: Enter your tenant URL (e.g. `https://yourtenant.vsax.net`) 2. **RMM Client Id**: Enter your VSA X **Token ID** 3. **RMM Client Secret**: Enter your VSA X **Token Secret** <Frame> <img alt="Neo Agent Kaseya VSA X Integration Setup form showing URL, Client Id, and Client Secret fields" /> </Frame> <Warning> Double-check all values for accuracy. Incorrect credentials will prevent Neo Agent from connecting to your VSA X tenant. </Warning> </Step> <Step title="Submit Configuration"> Click **Submit**. Neo Agent validates the token against your tenant and establishes the connection. <Check> A successful connection confirms Neo Agent can reach your VSA X tenant with the provided token. </Check> </Step> </Steps> ## Finding Your Tenant URL Your tenant URL is the address you use to log in to VSA X — `https://<yourtenant>.vsax.net`. You can confirm it under **Configuration → Account / Server details**. <Frame> <img alt="VSA X server details page showing the tenant URL and product version" /> </Frame> ## Troubleshooting Connection Issues <AccordionGroup> <Accordion title="Authentication Errors (401)"> * Verify the Token ID and Token Secret are correct and copied without extra spaces * Check that the token hasn't been revoked or expired in VSA X * Confirm the tenant URL is correct (just the host, e.g. `https://yourtenant.vsax.net`) </Accordion> <Accordion title="Permission Errors (403)"> * Review the permissions granted to the token in VSA X (Configuration → API Access → Third-Party Tokens → Authorization) * Ensure read access is granted to Devices, Device Assets, and Organizations at minimum * Confirm the token is scoped to the organizations you expect Neo to manage </Accordion> <Accordion title="Devices Not Appearing"> * Wait a few minutes for the initial sync to complete after connecting * Verify the token has Devices read access and is scoped to the right organizations </Accordion> </AccordionGroup> ## Configuring Permission Groups Once connected, open **Agent Settings → Permission Groups** to choose what the agent may do in VSA X. Each group can be **Disabled**, **Read-only**, or **Read & Write**: | Group | Read | Write | | - | - | - | | **Devices** | Devices, custom fields, applied policies, antivirus, notifications | Move device to group, update custom fields | | **Assets** | Hardware + installed-software inventory (60 req/hr) | — | | **Organizations** | Organizations, sites, groups, custom fields | Create/update/delete orgs, sites, groups | | **Automation** | Scripts, tasks, workflows + execution history | Run pre-registered scripts on devices | | **Patch Management** | Patch policies and global rules | — | | **Endpoint Protection** | Antivirus policies | — | | **Notifications** | Notifications and webhooks | Create notifications, manage webhooks | | **System** | Audit logs, environment, scopes, custom field definitions | — | ## What's Next? With VSA X connected, Neo can: * **Device lookup** — pull device status, OS, organization/site, and hardware/software inventory while triaging tickets * **Hierarchy mapping** — associate devices with the right PSA company * **Script suggestions** — surface relevant scripts from your automation catalog <Info> Neo Agent runs pre-registered VSA X scripts on a device when the **Automation** permission group has Read/Write access. Ad-hoc script source cannot be submitted — only scripts that already exist in your VSA X dashboard. </Info> # Creating an API Token Source: https://docs.neoagent.io/integrations/rmm/vsax/creating-api-key Create a Third-Party Token in Kaseya VSA X for the Neo Agent integration To enable Neo Agent to interact with your VSA X tenant, create a **Third-Party Token** (a Token ID + Token Secret pair) with the appropriate permissions. <Info> Token management lives under **Configuration → API Access → Third-Party Tokens**. If you don't see **API Access** under Configuration, your account's role lacks the API Access permission — ask a Super Admin to grant it or to create the token for you. </Info> ## Creating a Third-Party Token <Steps> <Step title="Navigate to Third-Party Tokens"> In your VSA X portal, go to **Configuration → API Access → Third-Party Tokens**, then click **Create Token** in the upper-right corner. <Frame> <img alt="VSA X Configuration → API Access → Third-Party Tokens page with the Create Token button" /> </Frame> </Step> <Step title="Configure the token details"> On the **Details** tab, give the token a recognizable name (e.g. `Neo Agent`) and an optional description. You can optionally set start/expiration dates and restrict the token to specific IP addresses. <Frame> <img alt="VSA X Create Token details form with name, description, expiry, and IP allowlist fields" /> </Frame> </Step> <Step title="Set the token authorization (scopes)"> On the **Authorization** tab, scope the token to the organizations Neo should manage, then grant the API endpoint permissions. Enable the exact set listed under [Permissions to grant](#permissions-to-grant) below — read access across every group, plus the **Automation** run permissions so Neo can execute scripts. <Warning> Missing permissions cause Neo to fail with `403 Forbidden` on the affected endpoints. At minimum, grant the **Device**, **Asset**, and **Organization** read permissions so device sync and PSA company mapping work. </Warning> </Step> <Step title="Create and save the token"> Click **Create**. VSA X displays the **Token ID** and **Token Secret** once. <Frame> <img alt="VSA X generated Third-Party Token showing Token ID and Token Secret" /> </Frame> <Warning> **Important**: Copy both the **Token ID** and **Token Secret** immediately and store them securely. The Token Secret is **not recoverable** after you navigate away — you would have to regenerate it. </Warning> <Check> Before closing, make sure you've saved: * The **Token ID** * The **Token Secret** * Your tenant URL (e.g. `https://yourtenant.vsax.net`) </Check> </Step> </Steps> ## Permissions to grant Enable the permissions below on the token's **Authorization** tab. The pattern is **read access across every group** plus the **Automation** run permissions so Neo can execute scripts — the create / update / delete write permissions are not needed. | Group | Enable these permissions | | - | - | | **Device** | Get a Specific Device · Get All Devices · Get Device Notifications · Get Antivirus Status · Get Device Custom Fields · Get Device Applied Policies | | **Asset** | Get Asset Information for a Specific Device · Get All Devices and Asset Information | | **Automation** | Run Task · Get a Specific Task · Get All Tasks · Get Task Execution · Get Task Execution Devices · Get Task Execution Scripts · Get Task Execution Script Output · Run Script · Get a Specific Script · Get All Scripts · Get Script Executions by Device · Get Script Execution Details · Run Workflow · Get a Specific Workflow · Get All Workflows · Get Workflow Executions · Get Workflow Execution Details · Cancel Workflow Executions | | **Custom Field** | Get a Specific Custom Field · Get All Custom Fields · Get Custom Field Usage | | **Organization** | Get a Specific Organization · Get All Organizations | | **Site** | Get a Specific Site · Get All Sites · Get Site Custom Fields | | **Group** | Get a Specific Group · Get All Groups · Get Group Custom Fields | | **Environment Information** | Get Environment Information | <Note> Leave the **create / update / delete** permissions — and **Publish a Device** — unchecked. The token needs only these read scopes to connect, plus the **Automation** run permissions (Run Task / Run Script / Run Workflow) used to execute scripts on devices, including the on-prem AD/Exchange PowerShell flow. What Neo may **write** back to VSA X is controlled per permission group in the Neo dashboard, where you can grant Read & Write per area. If you only want read-only device and asset visibility, you can omit the Automation run permissions too. </Note> <Info> A revoked token has a 30-day grace period during which you can regenerate its secret before it's permanently deleted. </Info> ## What's Next? Once you've created your token, you're ready to [connect it to Neo Agent](/integrations/rmm/vsax/connecting-to-neo) using the Token ID and Token Secret. # Overview Source: https://docs.neoagent.io/integrations/rmm/vsax/overview Connect your Kaseya VSA X (VSAX) RMM to Neo Agent for device, asset, and automation context ## Setup Overview Setting up the Kaseya VSA X integration involves two main steps: <CardGroup> <Card title="Creating an API Token" icon="key" href="/integrations/rmm/vsax/creating-api-key"> Create a Third-Party Token in your VSA X portal with the scopes Neo Agent needs. </Card> <Card title="Connecting to Neo Agent" icon="link" href="/integrations/rmm/vsax/connecting-to-neo"> Configure the connection between your VSA X tenant and Neo Agent using your Token ID and Token Secret. </Card> </CardGroup> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: An account in your VSA X tenant with the **API Access** permission (Super Admin, or a custom role that includes it) * **Your tenant URL**: e.g. `https://yourtenant.vsax.net` <Info> Kaseya VSA X (also written **VSAX**) is the modern, cloud-native Kaseya RMM built on the Pulseway engine — distinct from the classic VSA 9/10. Its REST API v3 lives at `https://<tenant>.vsax.net/api/v3`. </Info> ## What Neo Can Do with VSA X Neo Agent reads and (where you allow it) writes the VSA X REST API v3 surface, gated by per-area permission groups you configure in Agent Settings. <AccordionGroup> <Accordion title="Devices"> * **Device lookup** — find devices, status, OS type, organization/site/group, applied policies, antivirus status * **Custom fields & notifications** — read device custom fields and notifications * **Write** — move a device to another group, update device custom fields </Accordion> <Accordion title="Assets (hardware & software inventory)"> * **Hardware inventory** — BIOS, operating system, CPU, RAM, disks, network adapters * **Installed software** — name, publisher, version per device * **Last-seen** — the true `LastSeenOnline` timestamp <Info> The assets endpoint is rate-limited by Kaseya to 60 requests/hour, so Neo queries it sparingly. </Info> </Accordion> <Accordion title="Organizations, Sites, Groups"> * **Hierarchy** — read and (with write access) manage the organization → site → group structure and their custom fields </Accordion> <Accordion title="Automation"> * **Catalog** — list automation scripts, tasks, and workflows and inspect execution history * **Execute** — run pre-registered scripts on a device and read back the result (with write access to the Automation group) <Info> Script execution runs scripts that already exist in your VSA X dashboard — Neo never submits ad-hoc source. To let Neo run on-prem PowerShell (AD / Exchange) through VSA X, register the Neo wrapper script — see [On-prem AD & Exchange setup](/integrations/m365/on-prem#2-upload-the-neo-script-to-your-rmm). </Info> </Accordion> <Accordion title="Patch, Protection, Notifications, System"> * **Patch management** — read patch policies and global rules * **Endpoint protection** — read antivirus policies * **Notifications** — read notifications; create notifications and manage webhooks (with write access) * **System** — read audit logs, environment info, RBAC scopes, custom field definitions </Accordion> </AccordionGroup> <Tip> Write access is opt-in per area. In Agent Settings → Permission Groups, set the relevant VSA X groups to **Read & Write** to enable creates, updates, and deletes. </Tip> ## Available Actions | Category | Actions | Status | | - | - | - | | **Devices** | List/read devices, custom fields, applied policies, antivirus, notifications; move device; update custom fields | Available (read/write) | | **Assets** | Read hardware + installed-software inventory (60 req/hr) | Available (read) | | **Organizations / Sites / Groups** | Read and manage the tenant hierarchy | Available (read/write) | | **Automation** | Browse scripts, tasks, workflows and execution history | Available (read) | | **Automation** | Execute pre-registered scripts on devices and read results | Available (read/write) | | **Patch Management** | Read patch policies and global rules | Available (read) | | **Endpoint Protection** | Read antivirus policies | Available (read) | | **Notifications** | Read notifications; create notifications and manage webhooks | Available (read/write) | | **System** | Read audit logs, environment, scopes, custom field definitions | Available (read) | <Info> Neo Agent uses the VSA X REST API v3. Make sure your Third-Party Token has the necessary permissions for the areas you want Neo to act in — see the [API token guide](/integrations/rmm/vsax/creating-api-key). </Info> # Connecting RoboShadow to Neo Source: https://docs.neoagent.io/integrations/roboshadow/connecting-to-neo Copy a RoboShadow refresh token and save it in Neo You connect RoboShadow once at the MSP level. Neo reaches every organisation the RoboShadow user behind the token can see, so connect it with a user who sees all the customers you want Neo to read. ## 1. Copy the refresh token <Steps> <Step title="Open the API Token page"> Sign in to the RoboShadow portal and open **Reports**, then **API Token**. </Step> <Step title="Copy the Refresh Token"> The page shows an Organisation ID, a Bearer Token and a Refresh Token. Copy the **Refresh Token**. Neo uses it to get a new bearer token whenever the last one expires, so you never paste the short-lived bearer token. </Step> </Steps> <Warning> Neo reads only what the RoboShadow user behind the token can see. If that user loses access to an organisation, restore it in RoboShadow, or save a refresh token from another user who has it. </Warning> ## 2. Add the token in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the RoboShadow card, under Security. </Step> <Step title="Save the token"> Paste the refresh token and click **Save**. Neo checks it against RoboShadow before saving, so a wrong token is rejected straight away. </Step> </Steps> ## 3. Turn RoboShadow on per agent Open the agent, go to the Integrations section, and configure the RoboShadow block. The **Read Only** profile turns on every area. To leave an area out, set it to Disabled: | Area | Access levels you can pick | Notes | | - | - | - | | **Organisations, Devices and Inventory** | Disabled, Read Only | Organisations, devices, applications, services, disks and hardware. | | **Vulnerabilities and Updates** | Disabled, Read Only | CVEs, fixes, missing updates and remediation attempts. Needed to patch from the CVE report. | | **Antivirus and Firewall** | Disabled, Read Only | Antivirus, threats, Windows Defender and firewall status. | | **Users and MFA** | Disabled, Read Only | User accounts and profiles on each device, and the Microsoft MFA report. Device lists in the other areas still name the logged-on user. | | **External Scans** | Disabled, Read Only | External vulnerability scans of your customers' internet-facing addresses. | To let the agent patch what it finds, also give it your RMM's tools. See [RoboShadow API](/agents/tools/security/roboshadow-api) for what the agent can read. # RoboShadow Source: https://docs.neoagent.io/integrations/roboshadow/overview Let Neo agents read your RoboShadow vulnerabilities, missing patches and endpoint security RoboShadow scans your customers' Windows devices for vulnerabilities, missing updates and weak security settings, and scans their internet-facing addresses. Connect it, and Neo agents can read those findings while they work a ticket, plan patching or prepare a security review. Neo reads RoboShadow and changes nothing there. ## What Neo can do with RoboShadow * Find a client's critical CVEs, rank them by known exploitation, CVSS and EPSS, and read the fixed version for each one * Check what RoboShadow's own remediation already tried, and which attempts failed * List devices with no working antivirus, a disabled firewall, a detected threat or a missing critical update * Find Microsoft 365 users with no MFA * Summarise a client's vulnerabilities, endpoint security and MFA for a QBR See [RoboShadow API](/agents/tools/security/roboshadow-api) for the permission groups. ## Your organisations are mapped to companies Neo matches your RoboShadow organisations to the companies in your PSA and keeps the mapping on the RoboShadow card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Matching uses the organisation name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **A name match, or one you confirm, is handed straight to your agents.** An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect RoboShadow" icon="plug" href="/integrations/roboshadow/connecting-to-neo"> Copy your refresh token and save it in Neo. </Card> # Connecting SaaS Alerts to Neo Source: https://docs.neoagent.io/integrations/saas-alerts/connecting-to-neo Copy your SaaS Alerts partner API key and save it in Neo You connect SaaS Alerts once at the MSP level. One partner API key covers every client in your SaaS Alerts account. ## 1. Copy the API key <Steps> <Step title="Open the API settings"> Sign in to SaaS Alerts as a partner admin and open **Settings** > **API**. </Step> <Step title="Copy the key"> Under **Manage API**, click **Show key** and copy the key. Copy it before you leave the page. </Step> </Steps> <Warning> Do not reset the key in SaaS Alerts after you connect it. A reset replaces the key, and Neo loses access until you save the new key here. </Warning> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **SaaS Alerts**](https://dashboard.neoagent.io/integrations?open=saas_alerts), under Security. </Step> <Step title="Save the key"> Paste the API key and click **Save settings**. Neo checks it against SaaS Alerts before saving, so a wrong key is rejected straight away. </Step> </Steps> ## 3. Turn SaaS Alerts on per agent Open the agent, go to the Integrations section, and configure the SaaS Alerts block. Pick a profile, or set each area: | Area | Access levels you can pick | Notes | | - | - | - | | **Events and Alerts** | Disabled, Read Only | The event behind an alert ticket and the user's other events. This is the area an alert-triage agent needs. | | **Customers and Users** | Disabled, Read Only, Read / Write | SaaS Alerts customers and their users. | | **Approved Locations** | Disabled, Read Only, Read / Write | Approved countries, IP ranges and ASNs. Reading the current lists needs Customers and Users read access. | | **Suppressions** | Disabled, Read Only, Read / Write | Suppression rules. | | **Respond Rules** | Disabled, Read Only, Read / Write | Respond rules and IOC rules. | | **Respond Triggers and Actions** | Disabled, Read Only, Read / Write | Rule triggers and actions on Microsoft 365 accounts. | | **Connections and Devices** | Disabled, Read Only, Read / Write | Respond connections and Unify devices. | | **PSA Mapping** | Disabled, Read Only, Read / Write | Which PSA company gets each client's alert tickets. | | **Reports** | Disabled, Read Only, Read / Write | Scheduled reports and report emails. | | Profile | Writes | | - | - | | **Read Only** | Not allowed | | **Helpdesk** | Every write asks a technician | | **IT Admin** | Ignoring a rule trigger and customer, connection, device and report changes run on their own; suppressions, approved locations, Respond rules and PSA mapping ask a technician | | **Full Automation** | Run on their own | Under every profile, a Respond action on an account, approving, rejecting or manually remediating a rule trigger, deleting a customer or an application connection, and turning Respond off ask a technician. ## Example: investigate alert tickets Give the agent that triages your SaaS Alerts tickets the **Read Only** profile and an instruction like this: > When a ticket is a SaaS Alerts alert, look up the event and the user's recent activity in SaaS Alerts, judge whether it needs action, and write what you found in an internal note. See [SaaS Alerts API](/agents/tools/security/saas-alerts-api) for what the agent can read and change. # Overview Source: https://docs.neoagent.io/integrations/saas-alerts/overview What the SaaS Alerts integration brings to your Neo Agent setup SaaS Alerts (by Kaseya) monitors your clients' Microsoft 365, Google Workspace and other SaaS accounts and raises security alerts. Connect your SaaS Alerts partner API key to Neo once, at the MSP level. ## What Neo can do with SaaS Alerts <CardGroup> <Card title="Alert tickets" icon="bell"> Find the event behind a SaaS Alerts ticket from its Event ID, with its severity, IP, location and operation. </Card> <Card title="User activity" icon="list"> Read the user's other events around the alert and how often the event type fires for the client. </Card> <Card title="Accounts and clients" icon="user-shield"> Check whether the account is enabled and holds an admin role, and read the client's approved locations. </Card> <Card title="Suppressions and Respond" icon="shield-halved"> Suppress a recurring event for one client, and run Respond actions on Microsoft 365 accounts when you allow it. </Card> </CardGroup> Every Respond action on an account, and every rule-trigger approve, reject or manual remediation, always asks a technician first. ## Your SaaS Alerts customers are mapped to clients Neo matches each SaaS Alerts customer to a client in your PSA and keeps the mapping on the SaaS Alerts card's **Organization Mapping** tab, refreshed on each PSA metadata sync. With the mapping, an agent reads the alerts of the right client by its SaaS Alerts customer id. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Then comes the domain of the customer's contact email, against the website on a PSA company. Neo skips a free-mail domain, a domain that two customers share, and your own domain. Last comes an AI match for the long tail. A name match, or one you confirm, is handed straight to your agents. A domain match or an AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right client by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect SaaS Alerts" icon="plug" href="/integrations/saas-alerts/connecting-to-neo"> Copy your partner API key from SaaS Alerts and save it in Neo. </Card> # Connecting ScalePad to Neo Source: https://docs.neoagent.io/integrations/scalepad/connecting-to-neo Generate a ScalePad API key, save it in Neo, and decide what each agent can do You connect ScalePad once at the MSP level, then turn it on per agent. Setup takes a few minutes. <Info> ScalePad uses a single API key per MSP. There is no separate URL per end client. Save the key once and every agent that has ScalePad permissions can use it. </Info> ## 1. Generate an API key in ScalePad <Steps> <Step title="Open API Keys in ScalePad"> Sign in to ScalePad and go to **Settings**, then **API Keys**. </Step> <Step title="Create a new key"> Generate a new key with scopes covering the modules you want Neo to use (Core, Lifecycle Manager, ControlMap, Quoter, Backup Radar). <Tip> Grant the scopes broadly in ScalePad. You can always tighten per agent access in Neo afterwards, without reissuing the key. </Tip> </Step> <Step title="Copy the key"> ScalePad shows the key once. Copy it somewhere safe before leaving the page. </Step> </Steps> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the ScalePad card. </Step> <Step title="Paste the key and pick your data region"> Paste the key. Then leave **Data region** on United States unless ScalePad created your account for European, Canadian, or Australian data residency. <Warning> Your ScalePad data lives in one region only. A call to the wrong region comes back empty rather than failing, so an agent would report that a client has no assets when it does. If you are not sure, ask ScalePad support which region your account is in. </Warning> </Step> <Step title="Save"> Click **Save**. The form saves both fields together and closes, so set the region before you save. To change it later, open the ScalePad card again and save again. </Step> </Steps> ## 3. Turn ScalePad on per agent Each agent decides whether it uses ScalePad and which modules it can touch. Open the agent, go to the Integrations section, and configure the ScalePad block. ### Pick an access profile Quick start profiles set every module at once. <CardGroup> <Card title="Read Only" icon="magnifying-glass"> All five modules set to read only. The agent can look up anything your subscription and region cover, and it never makes changes. Best for reporting agents, QBR agents, and any agent that should never write. </Card> <Card title="Operations Manager" icon="briefcase"> Lifecycle Manager and Quoter set to read and write. Core, ControlMap, and Backup Radar stay read only. Best for vCIO and Client Success agents that draft initiatives, notes, deliverables, and quotes on their own. </Card> <Card title="Full Access" icon="bolt"> Lifecycle Manager, ControlMap, Quoter, and Backup Radar all read and write, with delete enabled where the module supports it. Core stays read only because the ScalePad API itself does not accept writes there. ControlMap and Backup Radar writes still wait on technician approval. </Card> </CardGroup> ### Or set each module by hand If a profile is not quite right, configure each module on its own. | Module | Access levels you can pick | Notes | | - | - | - | | **Core** | Disabled, Read Only | Clients and hardware assets. Read only by ScalePad API design. | | **Lifecycle Manager** | Disabled, Read Only, Read and Write | Notes, meetings, goals, initiatives, action items, assessments, deliverables. Optional Allow Delete toggle. | | **ControlMap** | Disabled, Read Only, Read and Write | Compliance health, evidences, risks, reports. Writes always wait on technician approval. Optional Allow Delete toggle. | | **Quoter** | Disabled, Read Only, Read and Write | Quotes, templates, line items, product catalog. Optional Allow Delete toggle. | | **Backup Radar** | Disabled, Read Only, Read and Write | Backup compliance per client, backup devices and their SLA history. Read and Write adds one action, sending backup results in, and it always waits on technician approval. No delete toggle, because the module has no delete. | ## Safety controls A few defaults stay in place no matter how you configure the agent. * **Core is always read only.** The ScalePad API itself does not expose write endpoints in Core, so Neo never tries to write there. * **ControlMap and Backup Radar writes wait on a technician.** Compliance evidence, risk changes, and backup result batches always pause for a technician to approve, even when the rest of the agent runs fully on its own. A backup batch carries up to 10,000 results and feeds your SLA reporting, so a wrong one is not undone by sending a right one afterwards. * **Delete is opt in.** A writable module whose ScalePad API has delete endpoints carries a separate **Allow Delete** toggle, and Read and Write does not grant delete on its own. Backup Radar shows no toggle, because that module has nothing to delete. * **Path safety.** Suspicious URL paths (anything containing `..`, for example) are rejected before they reach ScalePad. The agent cannot route around its own permission settings. * **Region-aware refusals.** ScalePad does not run every module in every region. Core, Lifecycle Manager, and Quoter are United States only, and Backup Radar runs in the United States and Europe. When an agent asks for a module your region does not serve, Neo says so by name instead of passing on an empty answer. ## Disconnecting ScalePad <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the ScalePad card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault. </Step> </Steps> Agents that use ScalePad stop working until you connect it again. Nothing else is deleted, so reconnecting later picks up where you left off. ## Security * The API key lives in Azure Key Vault. It is never stored in plaintext. * All traffic to ScalePad goes over HTTPS to the regional host you picked: `api.scalepad.com`, `eu.api.scalepad.com`, `ca.api.scalepad.com`, or `au.api.scalepad.com`. * Write access to ScalePad is opt in per module, per agent. * ControlMap and Backup Radar writes always involve a technician approval step. Once your key is saved and an agent has permissions, the ScalePad tool is added to that agent automatically. Browse the [Use cases](/integrations/scalepad/use-cases) page for ideas on what to build first. # Overview Source: https://docs.neoagent.io/integrations/scalepad/overview What the ScalePad integration brings to your Neo Agent setup ScalePad is the platform many MSPs use for hardware lifecycle management, vCIO planning, compliance, quoting, and backup monitoring. When you connect ScalePad to Neo, your agents can read this data and act on it inside the workflows you already build. Work you normally do by clicking around in ScalePad can now happen on its own or alongside ticket work, with your team reviewing instead of typing. <Info> ScalePad uses a single API key per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with ScalePad Neo reaches into five ScalePad modules. You decide which ones each agent can touch. <CardGroup> <Card title="Core" icon="server"> Look up clients, workstations, servers, network devices, and mobile assets that ScalePad syncs from your PSA. Any agent that needs to know what hardware a client has can use this data. </Card> <Card title="Lifecycle Manager" icon="route"> Read and write goals, initiatives, action items, assessments, meetings, notes, and deliverables. This is where most vCIO and Client Success workflows live. </Card> <Card title="ControlMap" icon="shield-check"> Read compliance health, evidences, risks, and reports. Write new evidence and risk updates when the agent gets explicit approval from a technician. </Card> <Card title="Quoter" icon="file-invoice-dollar"> Read and write quotes, quote templates, line items, and the product catalog. Lets agents draft quotes inside the same flow that triggered the request. </Card> <Card title="Backup Radar" icon="database"> Read backup compliance per client and per device, including the days a device missed its SLA and the days no result arrived at all. Agents can also send backup results in from another system, with technician approval. </Card> </CardGroup> ## Why connect ScalePad Four new abilities open up with ScalePad connected. Which of them you get depends on your ScalePad subscription and on the region your account sits in, because ScalePad does not run every module everywhere — the [setup page](/integrations/scalepad/connecting-to-neo) has the matrix. 1. **Live hardware and lifecycle data inside every workflow.** Any ticket, report, or planning agent works with the current asset reality instead of a stale spreadsheet, because the lookup happens against ScalePad at runtime. 2. **Draft roadmap initiatives, meeting notes, assessments, and deliverables on a schedule.** vCIO prep work that used to take hours becomes a review of a ready draft, sitting in ScalePad before you sit down. 3. **Write back compliance evidence and draft quotes.** Agents can capture ControlMap evidence and stage Quoter drafts, always behind the permission gates you set per agent. 4. **Answer backup questions from the ticket.** An agent handling a backup alert can check what Backup Radar knows about that device and client before it replies, instead of asking a technician to open another tab. ## How agents reach ScalePad When you enable any ScalePad permission group on an agent, Neo automatically adds the ScalePad tool to that agent's toolbox. There is nothing extra to install and no toolbox tweaking needed. The agent uses the API key you saved in the dashboard, and every call stays inside the modules and access levels you allowed. ## Where to go next <CardGroup> <Card title="Use cases" icon="lightbulb" href="/integrations/scalepad/use-cases"> Concrete workflows MSPs run today, including warranty coverage proposals, at risk customer scans, and quarterly business reviews. </Card> <Card title="Connecting ScalePad to Neo" icon="plug" href="/integrations/scalepad/connecting-to-neo"> Setup steps for the API key, per agent access levels, and the safety controls that stay in place. </Card> </CardGroup> # Use cases Source: https://docs.neoagent.io/integrations/scalepad/use-cases Concrete things MSPs run today with ScalePad and Neo These are the workflows MSPs run most often once ScalePad is connected. Several start as a Neo template you can spawn, point at a client, and adjust to your operating model; the rest are patterns to build from, and the Neo Support Agent will set one up with you. Which modules you can reach depends on your ScalePad subscription and the region your account sits in — the [setup page](/integrations/scalepad/connecting-to-neo) has the detail. ## Monthly workstation warranty coverage proposals A recurring agent that scans a client's fleet on the first of every month, finds workstations whose hardware warranty has already expired, and drafts a ScalePad Lifecycle Manager initiative ready for the vCIO to review. <Steps> <Step title="Pulls expired workstations"> Reads the client's hardware lifecycles from ScalePad Core and filters down to workstations whose warranty expiry date has passed. </Step> <Step title="Skips duplicates"> Lists open roadmap initiatives for the client. If a related initiative is already in flight (a workstation warranty refresh already proposed or in progress), the agent stops and reports the existing one instead of creating a second. </Step> <Step title="Creates the initiative from your template"> Posts a new initiative using your ScalePad Workstation Warranty Coverage template, attaches every expired workstation, and lands it in the Not Scheduled roadmap bucket. </Step> <Step title="Adds budget when you provide one"> If you configured a per workstation budget on the agent, the agent fills in the matching budget line item. If you did not, the budget is left empty for your vCIO to set during review. </Step> </Steps> The result is a ready to review draft that lives in ScalePad already, with the right workstations attached. Your team reviews and approves rather than starting from a blank page. ## At risk end customer scan A monthly portfolio wide scan that flags any end customer who looks at risk, with evidence and a recommended next step for each one. The agent checks three signals per customer. 1. **Business distress in the news.** A web search across the last 60 days for layoffs, restructuring, bankruptcy filings, mergers under stress, or major office closures. 2. **Ticket volume going silent.** A drop of more than 50 percent in the last 30 days against the prior 30 days, plus a comparison against the same calendar month last year. 3. **Stagnant fleet in ScalePad.** More than 20 percent of hardware assets sitting past end of life, with no engagement on refresh recommendations in the last 90 days. The output is a single markdown report with a ranked leaderboard, the evidence behind each flag (with source links and device counts), and a recommended ScalePad Lifecycle Manager initiative your team can spin up to engage the customer. Account managers walk into the month already knowing who to call first. ## Quarterly business reviews on demand An agent that pulls hardware lifecycle data from ScalePad, device names and assigned users from your RMM, and the full quarter of tickets from your PSA, then writes a concise QBR report you can hand straight to the client. The QBR includes: * A short executive summary that calls out the two or three things that matter this quarter. * A hardware health section that lists only the devices that need attention, with the assigned user, age, issue, and recommended action. * A business outcomes section that surfaces the top recurring ticket themes for the quarter using ticket clustering, plus any major incidents. * A prioritised list of recommended actions that traces back to the findings above. Reports stay under a few hundred words by design. Your vCIO walks into the QBR meeting with talking points already drafted, sourced from ScalePad and your PSA in one pass. ## Drafting roadmap initiatives from ticket trends Lifecycle Manager is where MSPs plan and track work with each client. With ScalePad connected, Neo can turn recurring ticket pain into a draft initiative inside the right client's ScalePad roadmap, instead of leaving it on a board. Common variations: * **Self service password reset.** When the agent sees a cluster of manual password reset tickets over 90 days, it can draft a Self Service Password Reset initiative under the right client's operational maturity goal, with an executive summary that quotes the ticket numbers. * **Recurring incident remediation.** A run of repeat outages on the same hardware can become a Hardware Replacement initiative with the offending assets already attached. * **Onboarding gaps.** A spike in new joiner tickets can become an Improve Onboarding initiative with action items and budget lines tied to your standard onboarding process. Because the agent reads existing initiatives first, it never piles up duplicate roadmap entries. ## Capturing compliance evidence in ControlMap ControlMap stores the evidence and risks that back your compliance posture. Neo can read the live picture and, with technician approval, push new evidence in. Examples: * When a security focused workflow finishes (such as resetting a high privilege account, or revoking access for a leaver), the agent can draft an evidence record in the matching control, with a technician approving before it commits. * On a regular cadence, the agent can summarise the past month of compliance evidence and surface gaps before the audit cycle, so nothing is missed when the auditor arrives. Writes to ControlMap always wait on technician approval, even when other parts of the agent are fully autonomous. This is the right default for compliance work. ## Drafting quotes in Quoter When the agent identifies that a client needs new hardware, a license bundle, or a project scope, it can draft a quote in Quoter using your existing templates and line items. Examples: * A warranty proposal agent can draft both the ScalePad initiative and a matching Quoter quote covering the proposed workstations. * A renewal workflow can draft a quote off a Quoter template every time a service is about to expire, populated with the right product categories from your catalog. You keep full control. Quotes land in Quoter as drafts ready for your team to review, adjust, and send. ## Answering a backup alert with Backup Radar Backup Radar knows whether a device is meeting its SLA and, more importantly, whether any result arrived at all. An agent handling a backup ticket can read that before it answers. Examples: * A backup alert lands on the board. Before the agent replies, it reads the device's last result and its SLA status for the past fortnight, so the note says "failed three nights running" rather than "a backup alert was received". * A weekly agent lists every client whose backups fell out of compliance, separating the true failures from the devices that reported nothing at all, and drafts the follow-up per client. * A vCIO agent pulls a client's backup compliance into the quarterly review pack beside the hardware and warranty picture. A device whose Backup Radar company is not mapped to a ScalePad client comes back with no client name. Neo reports those separately instead of filing them under the wrong customer. ## Bring your own use case These templates are starting points. The ScalePad tool reaches every module your subscription and region give you, so any combination of those is possible. If you run a vCIO practice, a hardware refresh program, a compliance practice, or a managed services renewal cycle, the integration gives you the data and the write actions to automate the parts your team does manually today. When you are ready to wire one up, the [Connecting ScalePad to Neo](/integrations/scalepad/connecting-to-neo) page covers the access levels and safety controls you set per agent. # Connecting SentinelOne to Neo Source: https://docs.neoagent.io/integrations/sentinelone/connecting-to-neo Create a SentinelOne service user, save its token in Neo, and decide what each agent can do You connect SentinelOne once at the MSP level, then turn it on per agent. ## 1. Create a service user in SentinelOne A service user is an API-only account. It cannot sign in to the console, and its token does not depend on a person's account. <Steps> <Step title="Open Service Users"> In the SentinelOne management console, go to **Settings > Users > Service Users** and create a new service user. </Step> <Step title="Pick the scope"> Pick **Account** scope to cover every client in that account, or **Site** scope for one client. Neo maps each site to a PSA company, so Account scope is usually right for an MSP. </Step> <Step title="Pick the role"> Each API operation needs its own permission (for example `Threats.updateAnalystVerdict` to set a verdict), and a role grants a set of them. Other MSP tools ask for **Viewer** to read, and for **SOC** or **IR Team** to set verdicts and respond to threats. Whatever you allow in Neo, the role decides what SentinelOne accepts. </Step> <Step title="Set the expiry and copy the token"> SentinelOne requires an expiry date for the token. Pick the longest your policy allows, and note the date: when the token expires, agents stop reaching SentinelOne until you save a new one. Copy the token when it is shown. </Step> </Steps> <Warning> Do not use the token from **My User > API Token Operations**. It belongs to your own console account and expires after 30 days by default. </Warning> ## 2. Add the token in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the SentinelOne card, under Security. </Step> <Step title="Enter the console URL and token"> **Console URL** is the address of your management console, as the browser shows it, for example `https://usea1-yourcompany.sentinelone.net`. Paste the service user's token into **API Token** and click **Save**. Neo checks both before it saves them. It confirms that the token authenticates and that it can list your sites. A wrong URL, an expired token or a role that cannot view sites is rejected immediately. </Step> </Steps> <Note> Neo accepts SentinelOne cloud consoles (`*.sentinelone.net`) and US government consoles (`*.s1gov.net`). On-premises consoles are not supported. </Note> ## 3. Turn SentinelOne on per agent Each agent decides whether it uses SentinelOne and which areas it can touch. Open the agent, go to the Integrations section, and configure the SentinelOne block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area read only. The agent investigates threats and endpoints and reports, but never changes anything. </Card> <Card title="Helpdesk" icon="headset"> Threats & Alerts and Endpoints read and write, everything else read only. The agent triages, mitigates and closes threats on its own. Endpoint actions, such as a scan, isolation or a reboot, wait on a technician. </Card> <Card title="IT Admin" icon="user-gear"> Every writable area read and write. The agent mitigates, isolates, reboots, runs scripts and manages sites and groups on its own. Exclusion and blocklist changes wait on a technician. </Card> <Card title="Full Automation" icon="bolt"> Every supported write runs with no approval. Only uninstalling, decommissioning or disabling the SentinelOne agent, and changes to unified alerts, wait on a technician. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Threats & Alerts** | Disabled, Read Only, Read and Write | Verdicts, incident status, notes, the ticket number and mitigation follow your approval setting. Changes to unified alerts always wait on a technician. | | **Endpoints** | Disabled, Read Only, Read and Write | Scans, log and file collection, tags, isolation, reboot and moving an endpoint follow your approval setting. Uninstalling, decommissioning or disabling the agent always waits on a technician. | | **Exclusions & Blocklist** | Disabled, Read Only, Read and Write | Follows your approval setting, and so does adding a threat to the blocklist or exclusions. An exclusion stops SentinelOne from seeing a file or path. | | **Deep Visibility & Activities** | Disabled, Read Only | Event searches, the activity log and hash verdicts. | | **Remote Scripts** | Disabled, Read Only, Read and Write | Script runs follow your approval setting. | | **Accounts, Sites & Groups** | Disabled, Read Only, Read and Write | Groups, sites and moving endpoints between groups follow your approval setting. | | **Users & Roles** | Disabled, Read Only | Who has console access, with which role. | ## Safety controls * **You set the approvals.** Each area has its own approval setting, so an agent can isolate an endpoint or quarantine a threat on its own, or ask a technician first. * **Removing protection always waits on a technician.** Uninstalling, decommissioning or disabling the SentinelOne agent, and changes to unified alerts, need approval whatever the agent's automation level. This is not a setting you can turn off. * **Threat, alert and endpoint actions name their targets.** SentinelOne applies such an action with an empty filter to every endpoint or threat the token can see. Neo refuses one that does not list the exact threat, alert or endpoint ids. * **Only the writes Neo needs are allowed.** Neo refuses policy changes, site deletion, user and token management, remote shell and other console administration, whatever the agent is set to. * **Secrets stay in SentinelOne.** Neo never reads site registration tokens, agent passphrases or the uninstall password. It also removes registration tokens from every site and group record before an agent sees it. * **Path safety.** Neo rejects suspicious URL paths (anything that contains `..`, for example) before they reach SentinelOne. ## If SentinelOne refuses Neo's requests | What comes back | Cause | Fix | | - | - | - | | `401` | The token expired or was revoked | Generate a new token for the service user in SentinelOne and save it in Neo. | | `403` | The service user's role or scope does not allow the operation | Give the service user a role with the permission that operation needs, or widen its scope. | | A failed **SentinelOne Company Mapping** row with HTTP 401 | The token expired or was revoked | Save a new token. The mapping rebuilds on the next PSA sync. | | A failed **SentinelOne Company Mapping** row with HTTP 403 | The role cannot view sites | Give the service user a role with site view access. | | `429` | Too many requests | Wait, then try again. If it repeats, check what else uses the same token. | Until a `401` or `403` is fixed, agents that use SentinelOne report the failure on the ticket they were working. The rest of Neo keeps running. ## Disconnecting SentinelOne <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the SentinelOne card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault. </Step> </Steps> Neo keeps your Organization Mapping, including any mapping you set by hand, so a later reconnect continues from the same state. Agents that use SentinelOne stop working until you connect it again. ## Security * The token is stored in Azure Key Vault, never in plaintext. * All traffic to SentinelOne goes over HTTPS, to your own console address only. * Write access is opt-in per agent. # Overview Source: https://docs.neoagent.io/integrations/sentinelone/overview What the SentinelOne integration brings to your Neo Agent setup SentinelOne Singularity is an EDR and XDR platform: it detects threats on your clients' endpoints, and it can kill, quarantine or roll back what it finds. Connect SentinelOne to Neo, and your agents can read the threat behind a ticket and check the endpoint it hit. They can then record the verdict and close the threat in SentinelOne. A technician does not need to open the SentinelOne console. <Info> SentinelOne uses one service-user API token per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with SentinelOne <CardGroup> <Card title="Threats & Alerts" icon="shield-virus"> Read threats, STAR alerts and unified alerts with their detection details and timeline. Set the analyst verdict and incident status, add notes, and write the PSA ticket number on the threat. Kill, quarantine, remediate or roll back a threat. </Card> <Card title="Endpoints" icon="desktop"> Find an endpoint by name, user or IP. Read its status, threats and installed software. Run a scan, collect logs or files, isolate the endpoint from the network, or reboot it. Uninstalling or disabling the SentinelOne agent always waits on a technician. </Card> <Card title="Exclusions & Blocklist" icon="ban"> Read and change exclusions and blocked hashes. An exclusion stops SentinelOne from seeing a file, so you may want a technician to approve these. </Card> <Card title="Deep Visibility & Activities" icon="magnifying-glass"> Search endpoint events with Deep Visibility or PowerQuery, read the console activity log, and check a hash's verdict. Read only. </Card> <Card title="Remote Scripts" icon="terminal"> Run a script from your library on named endpoints, and read its results. </Card> <Card title="Accounts, Sites & Groups" icon="building"> Your SentinelOne client hierarchy, used to scope every other lookup to the right client. </Card> </CardGroup> Users & Roles is also available, read only, for access reviews. ## Your clients are mapped automatically Neo matches your SentinelOne **sites** to the companies in your PSA. The mapping is on the SentinelOne card's **Organization Mapping** tab. Neo refreshes it on each PSA metadata sync and when you save the token. Matching is by name. Neo tries an exact match first, then a match after it removes a legal-form suffix (Ltd, Inc, LLC). The last step is an AI match for names the first two steps miss. Neo matches on the site name alone. A site has an `externalId` field that SentinelOne describes as an external CRM id, and Neo does not use it until a live console shows what MSPs store there. **Your agents get an exact or suffix match, or a match you confirm, directly.** They then scope every lookup to the ticket's client without searching for it. A match from the AI step is only a suggestion. It stays on the Organization Mapping tab until someone confirms it. You can set a mapping by hand on the same tab, and it survives every later sync. ## Why connect SentinelOne * **Threat tickets arrive with the detail already gathered.** An agent reads the threat and its timeline. It then checks whether the endpoint is online and whether SentinelOne already mitigated the threat. The technician gets a summary, and does not need to open the console. * **The console and the PSA agree.** When a ticket is resolved, the agent sets the verdict and incident status on the threat and writes the ticket number on it. The next run finds the same threat by that number and does not open a duplicate ticket. * **You decide how far agents go on their own.** Each area has its own approval setting, from read only to full response with no technician in the loop. Only uninstalling, decommissioning or disabling the SentinelOne agent, and changes to unified alerts, always wait on a technician. The [SentinelOne API tool](/agents/tools/security/sentinelone-api#safety-controls) reference lists the controls. ## How agents reach SentinelOne When you enable any SentinelOne permission group on an agent, Neo adds the SentinelOne tool to that agent's toolbox. There is nothing to install. The agent uses the token you saved in the dashboard, and every call stays inside the areas and access levels you allowed. ## Where to go next <Card title="Connecting SentinelOne to Neo" icon="plug" href="/integrations/sentinelone/connecting-to-neo"> Setup steps for the service user and token, per-agent access levels, and the safety controls that stay in place. </Card> # Deploy your end-user Slack bot Source: https://docs.neoagent.io/integrations/slack/end-user-bot The full procedure: from a tested chat agent to your branded Slack app answering a client's employees in their own Slack workspace Every Slack channel in Neo gets its own Slack app, with your display name, description and icon on it. Neo builds the app for you. Each client's Slack admin installs it with one link, and from then on anyone in that workspace can message it: your [chat agent](/chat-agents/overview) answers, scoped to that one client company, and usage bills to you. This page is the deployment procedure, top to bottom, for each client you roll out to. For what channels are, see [Channels](/chat-agents/channels). For clients on Microsoft Teams, see [Deploy your end-user Teams bot](/integrations/teams/end-user-bot). ## Before you start * A [chat agent](/chat-agents/building-a-chat-agent) with the **End-user** audience, tested in the dashboard with [Test as end-client](/chat-agents/channels#testing-as-an-end-client). * The client company in [**Companies**](https://dashboard.neoagent.io/end-companies). Slack needs no tenant ID or domain on the record: the install link carries the company. * An icon: a square PNG or JPEG, at least 512 × 512 px and at most 2 MB. Slack refuses smaller icons. * Someone at the client who can install apps in their Slack workspace, usually a Workspace Owner or Admin. ## Deploy <Steps> <Step title="Create the channel"> Open [**Chat** → **Channels**](https://dashboard.neoagent.io/chat?tab=channels) → **New Channel**. Pick the **Slack** transport and the **End-user** audience, name the channel, pick your chat agent, and click **Create channel**. The channel starts **Active**. Slack is offered only for End-user channels, and only when you create a channel: a saved channel can't switch between Teams and Slack. Then set the branding on the channel's **Slack app** tab, and the welcome message on its **Chat** tab: | Field | Limit | Where end users see it | | - | - | - | | **Display name** | Required, at most 35 characters | The app's name in Slack | | **Description** | At most 140 characters. A new channel starts with a default text you can replace | The app's details in Slack, the side panel, the welcome message and `/help` | | **Welcome message** | Optional | The first message a person gets from the app | **Upload** the **Icon** on the **Slack app** tab too. </Step> <Step title="Request the Slack app"> On the **Slack app** tab, click **Request Slack app**. The tab shows where the app is: | Status | Meaning | | - | - | | **Creating** | Neo is creating the app in Slack. | | **Awaiting setup** | The app exists. Slack allows its last setup steps only in its web interface, so Neo does them for you. This usually takes up to one business day, and you have nothing to do. | | **Ready** | The app is finished, and the install link controls appear on the **Installs** tab. | | **Failed** | Slack did not create the app, and the reason is shown. Fix what it names and click **Request Slack app** again. If the request was cut off, the app may exist in Slack already: the page says "Neo support must check this request before it can run again" and offers no retry, so contact Neo support. | <Frame> <img alt="The Slack app tab of a Slack channel: display name, description and icon, and the Slack app status Ready" /> </Frame> </Step> <Step title="Generate the install link"> On the channel's **Installs** tab, under **Install link for a client company**, pick the company and click **Generate install link**, then **Copy**. The link works for **2 days** and only for that company. Make a link for each client company. </Step> <Step title="Send it to the client's Slack admin"> The admin opens the link, signs in to their Slack workspace and clicks **Allow**. Slack then returns them to a Neo page that says **The app is installed**, with an **Open in Slack** button. At that moment the workspace is linked to the company you generated the link for. Every conversation from that workspace is scoped to that company, with no name or domain matching involved. If the workspace makes members ask before they install an app, a non-admin who opens the link sends Slack's approval request to the workspace admins instead, so send the link to an admin directly. </Step> <Step title="Verify"> The workspace appears under **Connected Slack workspaces** on the channel's **Installs** tab, with its company and install time. Then, as a person in that workspace: * Find the app under **Agents & apps** in the Slack sidebar and open its **Messages** tab. Your welcome message appears. * Ask a question. Your agent answers in a thread under it. * Reply in that thread. The agent keeps the context of the conversation. </Step> </Steps> ### Test in your own workspace first [Test as end-client](/chat-agents/channels#testing-as-an-end-client) checks the agent's answers without any install. To check the Slack side too (your branding, the welcome message, buttons and forms, relayed technician replies), install the app into your own Slack workspace: generate an install link for a company in **Companies** that stands for your own business, and install it yourself. The bot treats you like any client's employee, scoped to that company. A workspace stays linked to the company it was installed for while the app is installed there. To link it to a different company later, disconnect it first; see [Offboarding a client](#offboarding-a-client). ## What end users see **Where they talk to it.** Every conversation is a thread: * **Direct messages**: the app's **Messages** tab, found under **Agents & apps** in the sidebar. Each message a person sends there starts its own conversation, and the answer comes in a thread under it. Replies in that thread continue the conversation, across days. * **Channels**: add the app to a channel, and people **@mention** it. It answers in a thread under the message, and later mentions in that thread continue the same conversation. It never reads or answers a channel message that doesn't mention it. <Frame> <img alt="An end user's direct messages with the branded Slack app: the welcome message, two messages that each started their own conversation, and the thread of one of them open on the right, where the agent asks three multiple-choice questions about a VPN problem" /> </Frame> **The welcome message** arrives the first time someone opens the app's Messages tab. Without a welcome message set, it reads "Hi! I'm" and your display name. Your **Description** follows it, and the message always ends with a line saying that each new message starts a new conversation continued in its thread, a pointer to `/help`, and a line saying that replies are generated by AI and can be wrong. The app posts nothing when it is installed. **Replies.** The reply appears in the thread as the agent writes it. While the agent works, Slack shows that it is working, with a stop button. **Stop** stops the agent's work in that thread, including any question you sent there that is still waiting for its answer, and the app confirms in the thread. The conversation stays, so the next message in the thread carries on from there. Wait until Slack no longer shows that the agent is working before you send it, and send any dropped question again then: a message sent while the stop is still in progress is dropped with the stopped work. With **Show progress updates** on in the channel's **Chat** tab, a small card lists what the agent is doing with plain labels such as "Checking your tickets", and a **Show steps** button opens the list. End users never see tool names or what a tool returned. **Buttons and forms.** When the agent asks a question with a few likely answers, the options come as buttons (up to six), or as tick boxes with a **Something else** box when several answers can apply. Several questions at once come as one form with **Submit**. [Intent forms](/chat-agents/intent-forms) show in the conversation with a **Submit** button; a form with a long-text field opens in a Slack form window from an **Open form** button. After a long pause, a **Start fresh** / **Continue previous chat** card lets the person choose; see [starting fresh after a pause](/chat-agents/channels#starting-fresh-after-a-pause). **Commands.** `/help` shows your **Description** and how to use the app, visible only to the person who ran it. To start fresh, a person sends a new message: in direct messages each one starts its own conversation, and in a channel a new message that mentions the app does the same. `/new` says so. Typing "start a new chat" in a thread starts that thread over. **Files.** People can attach up to six files per message: screenshots, which the agent reads, and documents, which it can attach to their ticket. The accepted types are on [end-user tools](/agents/tools/end-user/overview#sharing-screenshots-and-files). Files over 20 MB, and other types, are skipped. The app never sends files back. **Technician replies.** A client-facing reply on the person's ticket arrives in the same conversation, the way [live ticket updates](/integrations/teams/end-user-bot#live-ticket-updates-in-the-chat) work in Teams. It shows who replied (the technician's name and picture, or your own name) and one footer line with the ticket number, title and status. The channel's **Relayed technician messages**, **Show the ticket title** and **Show the ticket status** settings apply as they do for Teams, and **Don't label them** sends the note as plain text with no footer. Which PSA entries relay, and the Autotask client portal address for ticket links, are set once for Teams and Slack together, on the **Microsoft Teams — End-user Chat Bot** card under [**Integrations**](https://dashboard.neoagent.io/integrations). The person's replies land on the ticket as [the ticket records](/integrations/teams/end-user-bot#what-the-ticket-records) describes. <Frame> <img alt="A Slack thread with the branded app: the end user reports that email won't send, answers the agent's questions, the agent files and escalates ticket #2020, and a technician's reply from the PSA appears in the same thread under the technician's name with a footer line showing the ticket number, title and status" /> </Frame> ## The Tickets tab **Show the Tickets tab** on the channel's **Slack app** tab gives the Slack app a **Home** tab with each person's tickets. A new Slack channel starts with it on, so its Slack app is built with the Home tab. When you switch it, Neo sends the change to Slack, and people see the tab the next time they open the app; nobody installs the app again. If Slack did not take the change, the **Slack app** section says so, and **Request Slack app** sends it again. The Home tab lists the person's **open** tickets, most recently updated first, and the tickets **closed in the last 30 days**, the same list as the [Teams Tickets tab](/integrations/teams/end-user-bot#the-tickets-tab): every ticket filed under their PSA contact, not only the ones the bot created. Each row has the ticket title, number, status and date; where your PSA has a client-portal link, the number opens the ticket there. The status follows **Show the ticket status** on the channel's **Chat** tab. If no contact has the email on the person's Slack profile, the tab says so and asks them to contact you. * **New ticket** opens the app's **Messages** tab and starts a new conversation there, which begins with "What would you like to raise a ticket about?". The person answers in that thread. The bot then follows your [ticket policy](/integrations/teams/end-user-bot#choose-when-the-bot-opens-a-ticket), as in Teams. * **Chat about this**, on each open ticket, starts a new conversation about that ticket, which begins with "We are now on ticket" and the ticket's number and title. What the person writes in that thread is recorded on that ticket, and a technician's client-facing reply on it arrives in the same thread. * **Refresh** reads the list again. When the list cannot be read for a moment, such as when your PSA is slow or after too many refreshes, the tab keeps the list it is showing, with a line saying it may be out of date. When the tab was turned off or the workspace is no longer connected, the tab says so instead. **Links on the Tickets tab** puts up to five of your links at the top of the Home tab, such as your emergency line or your IT Glue portal. A web link is a button; a phone number or email address shows as text beside its label, and Slack's apps let people tap it to call or write. The Home tab is in English. Links need no update to the app: they show the next time the tab is opened or refreshed, also while the workspace is not yet linked to a company. Slack decides which tab the app opens on, so Slack has no **Open the app on** setting. Point people to the **Home** tab at the top of the app. ## Who the bot serves * **The company** is the one the workspace's install link was generated for. One workspace is linked to exactly one company. * **The person** is matched by the email on their Slack profile against that company's active contacts in your PSA. With a match, they can see and reply to their own tickets. Without one, the bot can still file a ticket, noting the email it came from, but it can't show them tickets until you add them as a contact. * **What the agent can reach** is the same end-user tool set as in Teams, locked to that one person and company: see [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access) and [how end-user bots work](/chat-agents/how-end-user-bots-work). The bot serves the people of the workspace that installed it, guests of that workspace included. A person from another organization, such as someone in a Slack Connect channel, gets a short refusal that sends them to their own IT support team, and nothing they write reaches your agent. When Slack can't confirm who is writing, the bot asks the person to try again in a moment and sends nothing on. ## What the app can access in the workspace A client's Slack admin sees these permissions on the **Allow** screen. The app can: * Read direct messages sent to it, and channel messages that mention it. It has no access to other channel messages. * Send messages, and show that it is working on an answer. * Read people's names and email addresses, to match each person to a PSA contact. * Read files people send to it. * Run its `/new` and `/help` commands. * Read the workspace's name. The app never reads Slack's message history. It keeps the context of each conversation on Neo's side. ## How it differs from Teams | | Teams | Slack | | - | - | - | | The app | One Teams app package with your branding | Its own Slack app per channel, built by Neo | | Ready to install | At once | After **Awaiting setup**, usually up to one business day | | Who installs | A Teams or Global administrator of the client's Microsoft 365 tenant, through the Neo Installer consent, then **Install for everyone** in the Teams admin center | The client's Slack admin clicks **Allow** on the install link. Everyone in the workspace can then find the app under **Agents & apps**, with no rollout step | | How the company is known | The Microsoft 365 tenant ID on the company record; one tenant can cover several companies | The company the install link was made for; each workspace belongs to one company, and a company can have several workspaces | | Group conversations | Mention-only in group chats and channels | Mention-only in channels, answered in a thread | | Replies written live | In 1:1 chats | In every conversation, since each one is a thread | | Branding changes reach clients | After you publish from the channel's page, Teams shows it after a few hours ([how](/chat-agents/channels#publishing-an-update)) | The app's name and details with **Request Slack app**; the welcome message within 10 minutes. See [Updating the app](#updating-the-app) | **Enterprise Grid.** Install the app into one workspace at a time. An install for a whole Enterprise Grid organization is refused. ## Updating the app | Change | Takes effect | | - | - | | Assigned agent, agent instructions and tools | Immediately. A conversation already open moves to a newly assigned agent by itself | | Welcome message, and the description in the welcome message and `/help` | Within 10 minutes | | Display name, and the description in the app's details | After you click **Request Slack app** again, which sends them to Slack | | **Show the Tickets tab** | When you switch it; Neo sends it to Slack. It also sends a display name or description you saved since the last request | | **Links on the Tickets tab** | The next time the Home tab is opened or refreshed | | Icon | After Neo applies the new upload in Slack, which Neo does for you | Installed workspaces keep the app through every update, and nobody needs to install it again. ## Offboarding a client Click **Disconnect** on the workspace under **Connected Slack workspaces**, then **Disconnect it**. Neo stops answering there and asks Slack to remove the app. If the app still shows in the workspace, a Slack admin there can remove it. If the client removes the app in Slack first, Neo drops the workspace from the list by itself. Disconnecting also removes the workspace's company link, once no other Slack channel of yours is installed in that workspace. The same happens when the client removes the app in Slack. The workspace is then free: an install link for any company connects it again. While another of your channels is still installed there, the workspace keeps its company, and an install link for a different company is refused. ## Billing The Slack bot is billed like the Teams bot: a flat monthly price per client company where someone used it, with the same free trial, which starts with your first install on either transport. See [end-user bot pricing](/chat-agents/sessions-and-billing#end-user-teams-bot-pricing). ## Over the API The same steps are in the [public API](/developers/introduction): * `POST /public-api/channels/{id}/slack-app` requests the app, retries a failed request, or sends changed branding. * `GET /public-api/channels/{id}/slack-app` returns its status. * `POST /public-api/channels/{id}/slack-app/icon` uploads the icon. * `POST /public-api/channels/{id}/slack-install-link` with a `psa_company_id` makes an install link. * `GET /public-api/channels/{id}/slack-installs` lists the connected workspaces, and `DELETE /public-api/channels/{id}/slack-installs/{install_id}` disconnects one. ## Troubleshooting <AccordionGroup> <Accordion title="The app request failed"> The **Slack app** tab shows the reason. The usual causes are a missing display name, a display name over 35 characters or a description over 140. Fix the field, and click **Request Slack app** again. When the tab says Neo support must check the request, the call to Slack was cut off and the app may already exist there; contact Neo support, who clear it for a new request. </Accordion> <Accordion title="The icon upload was refused"> Slack needs a square image of at least 512 × 512 px, and Neo accepts up to 2 MB. Export a larger or smaller file, and upload it again. </Accordion> <Accordion title="The admin sees 'This link has expired'"> An install link works for 2 days. Generate a new one for the same company and send it again. </Accordion> <Accordion title="The admin sees 'The install was cancelled'"> The admin left Slack's screen without clicking **Allow**. They open the same link again, while it is still valid. </Accordion> <Accordion title="The admin sees 'This Slack workspace is already connected to another company'"> The workspace is still installed with a link for a different company, and a workspace keeps its company while any of your Slack channels is installed there. Slack's install is undone, and nothing changes. Check which company the workspace belongs to. To move it, click **Disconnect** on the workspace in every Slack channel that lists it, then send the new install link again. </Accordion> <Accordion title="The admin sees that an Enterprise Grid organization is not supported"> The admin chose to install the app for the whole organization. Have them open the link again and install it into one workspace. </Accordion> <Accordion title="The bot says the app isn't connected for this workspace yet"> The message tells the person to contact their IT support team, and the fix is yours. Either the workspace has no live install of this channel's app, or the channel is **Disconnected**. Set the channel to **Active**, and check that the workspace shows under **Connected Slack workspaces**. If it doesn't, generate an install link and have the workspace's Slack admin install the app. </Accordion> <Accordion title="The bot says the app isn't fully set up for the organization yet"> The message tells the person to contact their IT support team. The app is installed, but the workspace isn't linked to a company; its row under **Connected Slack workspaces** shows **Company not linked**. Generate the install link for the right company and have the Slack admin install the app again with it. This also shows when you removed the workspace's company from **Companies**; the workspace keeps that link, so disconnect it first, then send the new install link. </Accordion> <Accordion title="A user can't see their tickets"> The bot tells them their account isn't linked to a contact record. The email on their Slack profile matches no active contact at the company in your PSA. Add them as a contact, or correct the email on the contact; the next message picks it up. </Accordion> <Accordion title="The bot ignores a channel"> In a channel it answers only when someone **@mentions** it, and only in channels it was added to. Add it to the channel, and mention it. </Accordion> <Accordion title="The bot says it can't reach the service, or couldn't finish"> Have the user send the question again as a new message, which starts a fresh conversation. If the same message comes back there, contact Neo support. </Accordion> <Accordion title="A person from another organization is refused"> They see "Sorry, I can only help people in this organization's own workspace. For help, please contact your own IT support team." That is expected: they belong to a different Slack organization, usually through a Slack Connect channel, and the bot serves only the workspace that installed it. Guests of the installing workspace are served. </Accordion> <Accordion title="The bot says the assistant isn't active for the organization right now"> The end-user bot is paused for your end users: its free trial ended with no payment method on file, or you cancelled the add-on on the Billing page. On the [Billing page](https://dashboard.neoagent.io/billing), click **Subscribe** (it asks for a payment method when none is on file, then click **Subscribe** again), or **Turn back on** if you cancelled; see [Free trial](/chat-agents/sessions-and-billing#free-trial). </Accordion> <Accordion title="The bot says the assistant isn't active any more"> Your Neo account is switched off, so every branded bot you installed stops answering. The apps stay installed. When your account is active again, the next message gets an answer. </Accordion> </AccordionGroup> <Tip> This app is for your **clients' employees**. Your own technicians chat with Neo in the dashboard or in Microsoft Teams; see [chat surfaces](/chat-agents/overview#the-chat-surfaces). </Tip> # Slack Source: https://docs.neoagent.io/integrations/slack/intro Receive workflow notifications in your Slack channels, and let your clients chat with an agent in their Slack <Info> Notifications and end-user chat use separate Slack apps: one Neo app that you set up on this page, and a branded app per Slack channel that Neo builds for you. * **Notifications** — Neo posts into your Slack channels. Workflows use the <a href="/building-automations/actions/notify/notify-internal-team">Notify Internal Team</a> action, and agents use the <a href="/agents/tools/communication/send-slack-message">Send Slack Message</a> tool. Both post through the Neo Slack app this page sets up. * **End-user chat** — your clients' employees chat with one of your chat agents in their own Slack workspace, through that channel's branded app; see <a href="/integrations/slack/end-user-bot">Deploy your end-user Slack bot</a>. To chat with Neo yourself, use the Neo AI Agent in Microsoft Teams. </Info> ## Create the Slack app <Steps> <Step title="Open Slack API and create the app"> Go to <a href="https://api.slack.com/">Slack API</a> → Your Apps → Create New App → Create from scratch. Name it "Neo Agent" and select your workspace. <Frame> <img alt="Create a new Slack app" /> </Frame> <Frame> <img alt="Create app from scratch in Slack" /> </Frame> <Frame> <img alt="Name the app and select workspace" /> </Frame> </Step> <Step title="Add the bot token scope"> On OAuth & Permissions, add the `chat:write` bot token scope so Neo can post messages to your channels. <Frame> <img alt="Add the chat:write bot token scope" /> </Frame> </Step> <Step title="Install to workspace"> On OAuth & Permissions, click Install to workspace. The app appears under Apps in Slack. <Frame> <img alt="Neo Agent app installed in Slack" /> </Frame> </Step> <Step title="Share credentials with Neo admin"> Provide your Bot User OAuth Token and App ID to your Neo administrator to complete configuration. </Step> </Steps> ## Add Neo to channels <Step title="Add to a channel"> Open the Neo Agent app in Slack and add it to the channel where you want to receive notifications. <Frame> <img alt="Add Neo Agent to a Slack channel" /> </Frame> </Step> ## Configure channel notifications Use the channel ID in the <a href="/building-automations/actions/notify/notify-internal-team">Notify Internal Team</a> action, then run a workflow that notifies that channel to confirm delivery. <Tip> Copy a channel link in Slack and use the last segment as the channel ID (for example: C1234567890). </Tip> # Connecting Sophos to Neo Source: https://docs.neoagent.io/integrations/sophos/connecting-to-neo Create a Sophos Central API credential and save it in Neo You connect Sophos once at the MSP level, with the client ID and client secret of a Sophos Central API credential. ## 1. Create an API credential in Sophos Central <Steps> <Step title="Open your partner account"> Sign in to [Sophos Central Partner](https://central.sophos.com/manage/partner) as an administrator. Use your partner account, not a customer's tenant. </Step> <Step title="Add a credential"> Click **Settings & Policies**, then **API Credentials**. Give the credential a name, such as `Neo`, and a description, then click **Add**. </Step> <Step title="Copy the client ID and secret"> Copy the **client ID**. Click to show the **client secret** and copy it too. Sophos shows the secret only now, so keep it until you save it in Neo. </Step> </Steps> <Note> An organization or a single tenant can also connect: create the credential under **Settings & Policies** (organization) or **Global Settings** (tenant) at [central.sophos.com/manage](https://central.sophos.com/manage). Neo then reaches only that organization's tenants, or that one tenant. </Note> <Warning> Do not delete the credential in Sophos Central after you connect. Neo loses access until you save a new client ID and secret here. </Warning> ## 2. Add the credential in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Sophos**](https://dashboard.neoagent.io/integrations?open=sophos), under Security. </Step> <Step title="Save the credential"> Paste the client ID and the client secret, and click **Save settings**. Neo checks them against Sophos Central before saving, so a wrong value is rejected straight away. </Step> </Steps> # Overview Source: https://docs.neoagent.io/integrations/sophos/overview What the Sophos integration brings to your Neo Agent setup Sophos Central manages your clients' Sophos endpoint protection, firewalls and email security. Connect Sophos to Neo once, at the MSP level, with an API credential from your Sophos Central Partner account. A partner credential reaches every Sophos Central tenant you manage, in every data region. An organization credential reaches the tenants of that organization, and a tenant credential reaches that one tenant. Neo finds each tenant's own regional API host for you, so you do not enter a region. ## What Neo can do with Sophos * Check a device in Sophos when your RMM says it is offline: whether Sophos sees it online, when it was last seen, and its health * Read a Sophos alert and its device, then acknowledge, clean or clear it * Isolate or scan an endpoint, and allow or block an item * Read Sophos Firewalls, search and release held email, and act on mobile devices * Read your tenants, licences and usage Allow rules, exclusions, removing a block, lifting an isolation, deleting endpoints, turning Adaptive Attack Protection or Tamper Protection off, authorizing a potentially unwanted application, wiping a phone, and admin, role and billing changes always ask a technician. See [Sophos API](/agents/tools/security/sophos-api) for the permission groups and access profiles. ## Your Sophos tenants are mapped to clients Neo matches each Sophos Central tenant you manage to a client in your PSA and keeps the mapping on the Sophos card's **Organization Mapping** tab, refreshed on each PSA metadata sync. With the mapping, an agent works in the right client's tenant without looking it up. A suspended or canceled tenant, or one that has not allowed you to manage it, is listed but not mapped automatically. A tenant-level credential lists its own tenant without a name: set its client by hand. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. A name match, or one you confirm, is handed straight to your agents. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right client by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Sophos" icon="plug" href="/integrations/sophos/connecting-to-neo"> Create an API credential in Sophos Central and save it in Neo. </Card> # Deploy your end-user Teams bot Source: https://docs.neoagent.io/integrations/teams/end-user-bot The full procedure: from a tested chat agent to your branded bot answering a client's employees in their Microsoft Teams Put your own support bot — your name, your icon — into a client's Microsoft Teams. Their employees message it; your [chat agent](/chat-agents/overview) answers; everything runs on your Neo configuration and bills to you. This page is the canonical deployment procedure, written to be followed top to bottom for each client you roll out to. For what channels *are*, see [Channels](/chat-agents/channels). ## Before you start * A [chat agent](/chat-agents/building-a-chat-agent) you've tested in the dashboard. * The client's **Microsoft 365 tenant ID**, set on their company record under [**Companies**](https://dashboard.neoagent.io/end-companies). * A Microsoft 365 admin in the client tenant to approve the one-time install — their admin, or you if you have delegated (GDAP) admin into their tenant. The tenant must allow custom Teams apps either way. ## Test in your own tenant first Two ways to try a bot before a client ever sees it, covering different things: * **Behavior** — does the agent answer the way you want for a given client? Use the dashboard [Test as end-client](/chat-agents/channels#testing-as-an-end-client) picker — no install, instant. * **The Teams experience** — branding, the welcome message, adaptive and approval cards, proactive messages, the install greeting? Install your branded app into **your own** Microsoft 365 tenant and message it as an employee would. To test the Teams experience: 1. On the channel's **Installs** tab, click **Test in your own Teams**. It is the first step on a new channel, and at the top of the tab after a client has installed. 2. Click **Open install page**, sign in as a **Global admin** of your Microsoft 365, and approve. Not an admin? Copy the link from the same window and send it to one. 3. Back in the dashboard, the window changes to **Open the chat in Teams**. The page you land on after the approval has the same button. Teams does not list a bot you have never messaged, so use that button to find the chat. After the install, the **Test in your own Teams** button reads **Open in your own Teams** and opens the chat again, also when an older chat carries the wrong name (see the note below). Your tenant needs no company record, and you skip the **Install for everyone** step that clients do. The test bot answers as an end-user bot, with the same company scoping a client gets. One install in your own tenant tests the whole Teams experience. <Note> If your tenant has an internal bot created before internal bots got their own identities, the self-install reports that the identity is taken. **Move the internal bot onto its own identity first, and finish that move before you install here**; [custom internal bots](/integrations/teams/internal-bot) has the steps. Removing the internal channel's registration is only the first step of the move — its Teams app stays in your catalog on the shared identity until an administrator opens the new install link and approves it, and installing the end-user bot before that leaves your technicians with a chat that shows a stranger's name and cannot send. Neo refuses the install until you have generated that link. The refusal lifts then, before the approval, so wait for the approval yourself. Once it is approved, install the end-user bot. It takes over the chat your technicians had with the internal bot, and its first message there says which bot it now is and where the internal one went. That chat can keep the internal bot's old name in the Teams sidebar for a while, so it is easy to miss: open the end-user bot from the **Open in your own Teams** button instead of hunting for its name. </Note> ## Deploy The fastest path is a **magic install link**: you generate it, the client's admin clicks it once and approves, and Neo publishes your branded app into their tenant automatically — no zip to upload. (No admin access? See [Install the package manually](#install-the-package-manually) below.) <Steps> <Step title="Create and activate the channel"> Open [**Chat** → **Channels**](https://dashboard.neoagent.io/chat?tab=channels) → **New Channel**. Pick the **Teams** transport and the **End-user** audience, name the channel, assign your chat agent, and click **Create channel**. The channel starts **Active** and opens on its **Installs** tab. <Frame> <img alt="The New channel form: Teams transport, End-user audience, the channel name, the chat agent picker and the Create channel button" /> </Frame> Branding is optional: any field you leave blank uses the Neo default. To make the bot yours, set at least the **Display name** (the bot's name in Teams) on the **Teams app** tab and the **Welcome message** (the first thing users see) on the **Chat** tab. Where every setting lives: [the channel page](/chat-agents/channels#the-channel-page). </Step> <Step title="Generate the install link"> On the channel's **Installs** tab, **White-label installs** is a table of every [**Companies**](https://dashboard.neoagent.io/end-companies) entry with a Microsoft 365 tenant ID — one row per tenant (companies sharing a tenant are covered by a single install) — with each row's status: **Not enabled**, **Link sent** (with its expiry), **Link expired**, **Registered**, **Installed**, or **Live for everyone**. Once a tenant is bound, rows still **Not enabled** fold behind the **Not enabled** button above the table; a search looks through every row. Click **Install link** on a row — or tick several rows and **Generate install links** in bulk — then copy each link from the dialog. A link is tied to its one channel and tenant and expires in **2 days**; the row shows **Link sent** until the client's admin approves, so you can see at a glance who still needs a nudge. Generating a new link for a tenant **replaces** the previous one (an already-sent copy stops working), and removing the row revokes an outstanding link entirely. **One branded bot per client** — a tenant already installed on another channel is refused when you generate its link. </Step> <Step title="Send it to the client's Teams administrator"> Send the link to a **Global Administrator** of the client's Microsoft 365 tenant. They open it, sign in, and approve the permission prompt for their whole organization; Neo then publishes your branded app into their catalog on their behalf and registers routing — all in one sign-in. They land on a "You're all set" confirmation. The organization-wide approval is what lets every employee open the [Tickets tab](#the-tickets-tab) without a prompt. A **Teams Administrator** can still finish the install, because publishing to the catalog is a Teams admin action, but cannot approve for the organization: the confirmation page then says so, and the Tickets tab asks for an administrator's approval until a Global Administrator opens the link again or approves the request (see [Troubleshooting](#troubleshooting)). <Info> The sign-in authorizes the dedicated **Neo Installer** app to publish apps to the catalog *as that admin*, and lets it confirm who is looking at the Tickets tab — nothing more. The bot itself is still messaging-only and has **no** standing Microsoft Graph access in the client tenant; its manifest permissions are just `identity` and `messageTeamMembers`. If you have GDAP admin into the tenant, you can open the link and sign in yourself. That sign-in leaves a **Neo Installer** app in the tenant's **Enterprise applications** — leave it in place. If a sign-in errors, have the admin **re-open the link** rather than deleting it to retry: deleting the app soft-deletes its service principal and blocks the next sign-in with `AADSTS650051` (see [Troubleshooting](#troubleshooting)). </Info> Once they've approved, routing is live: messages from that tenant to your bot route to this channel's agent. There's no separate confirmation step and no ordering to get right — the publish and the routing registration happen together. </Step> <Step title="Make it reach their users"> Publishing puts the app in the org catalog, but users still have to get it. In the client's [Teams admin center](https://admin.teams.microsoft.com/policies/manage-apps) → **Teams apps** → **Manage apps**, open your app, go to the **Users and groups** tab → **Installs** → **Install app** (or **Edit installs**), set it to **Everyone**, and **Apply**. This installs the bot for everyone — **including people who join later** — so new hires get it automatically. On the same tab, check **Availability** too. It must include the people who use the app and the admin who opened the install link: click **Edit availability** and choose **Everyone** (the simplest, and it includes guests) or a group that contains them. Many tenants default custom apps to **No one**. Microsoft treats an app available to no one as blocked for its users and hides it from the admin's view of the catalogue, which can make **Publish update** fail (see [Troubleshooting](#troubleshooting)). This last step is a **manual admin action and can't be automated** — Microsoft gates the "Install for everyone" assignment to the admin center (and the Teams admin PowerShell), with no API a third-party app can call. Neo reminds you of it after an install and lets you tick the company's row under **White-label installs** once it's done: the **Everyone** column, or **For everyone** in the status cell on a narrow screen. The row then reads **Live for everyone**. Changes can take up to 24 hours to reach all users. <Frame> <img alt="Teams admin center — Manage apps, an app's Users and groups tab, Installs set to Installed for everyone, with the Edit installs button" /> </Frame> **Optional — pin it.** Installing puts the app in the user's Teams; *pinning* keeps it on the sidebar instead of under **More apps (…)**. Pinning is separate (it isn't read-only under app-centric management) and lives in **Teams apps** → **Setup policies** → **Global (Org-wide default)** → **Pinned apps** → **Add apps** → your app → **Save**. A pin only shows for users who already have the app, so do the **Install for everyone** step first. <Note> This is **app-centric management** (the "moved to unified app management" experience most tenants are now on). On a tenant **not yet** migrated, use **Teams apps** → **Setup policies** → **Global (Org-wide default)** → **Add apps** instead — once a tenant moves to app-centric management, setup-policy installs become read-only and the **Install for everyone** step above is the way. </Note> </Step> <Step title="Verify"> From a user account in the client tenant, open the bot in Teams: * First contact shows your **welcome message** (or "Hi! I'm *your display name*" if you left it blank). * A 1:1 question gets an answer from your agent. * **"start a new chat"** acknowledges and starts a fresh conversation. It's in the bot's command menu, and typing it works anywhere. The user's company is recognized from the Microsoft 365 tenant the message arrives from, via the tenant ID on the [Company](https://dashboard.neoagent.io/end-companies) record — no per-user setup (see [Sessions & billing](/chat-agents/sessions-and-billing#identity-on-sessions)). </Step> </Steps> ### Install the package manually If the tenant blocks the consent flow, or the app is already installed and you only need to bind routing, use the zip instead of the link: <Steps> <Step title="Download the Teams app package"> On the channel's page, open the **⋮** menu → **Download Teams app package**. You get a `.zip` containing the manifest and your icons — upload it exactly as downloaded; re-download it whenever you change branding rather than reusing an old copy. </Step> <Step title="Upload it in the client's Teams admin center"> Open the [Teams admin center](https://admin.teams.microsoft.com/policies/manage-apps) → **Teams apps** → **Manage apps** → **Actions** → **Upload new app**, and upload the `.zip`. </Step> <Step title="Register routing on the channel"> Back under **White-label installs**, open the company row's **⋮** menu → **App already installed? Register directly** to bind routing. Do this **before** users start messaging — the bot greets on install, and an unregistered tenant gets a neutral "finishing setup" note instead of your welcome message (routing still self-heals on the next message once registered). </Step> </Steps> With the [Tickets tab](#the-tickets-tab) on, the package still signs users in to the tab through the **Neo Installer** app, which a manual upload never approves. The first employee to open the tab is asked to approve it. In a tenant where users can't approve apps, that becomes a request an administrator approves once in the Microsoft Entra admin center under **Enterprise applications** → **Admin consent requests**; after that nobody is asked again. ## What end users can access Every conversation through this bot is **scoped to the end user's company**, resolved from the Microsoft 365 tenant the message arrives from. That scope is enforced by Neo, not by the agent's configuration (the architecture behind it: [how end-user bots work](/chat-agents/how-end-user-bots-work)): * The bot runs a purpose-built [set of end-user tools](/agents/tools/end-user/overview): it answers from your knowledge base (for a common how-to your knowledge base doesn't cover, it gives brief general steps and says they are general guidance, never your company's details), looks up the user's **own** tickets, and (if you enable it) files new tickets and posts replies as the user — all scoped to that one person and their company. * Tools that operate across your whole client base — MSP-wide ticket search, company listings, configuration/contact search, generic PSA or Microsoft Graph API access, sandbox scripting — **never run in end-user conversations**, even if they're enabled on the agent's toolbox. * If the inbound tenant isn't linked to any of your [Companies](https://dashboard.neoagent.io/end-companies), the bot refuses the conversation and tells the user to contact their IT support team — it never answers unscoped. * One Microsoft 365 tenant **can be linked to several companies** (branch offices sharing a tenant). Neo scopes each conversation to the company whose PSA contacts hold the speaker's verified email; if the email isn't found there (or appears in more than one), Neo picks deterministically — the parent company (Autotask), then the lowest company ID. * If the speaker's email matches more than one contact record within the resolved company (some MSPs keep a duplicate contact per site), the bot treats tickets filed under **any** of those contacts as the user's own — they can view, reply to, and resolve every one of them. New tickets and replies are still authored under one consistent contact for stable attribution. * This applies to **your own tenant too**: a self-install of an *end-user* channel is company-scoped like any client install. For cross-company technician work, use the [Neo AI Agent app](/integrations/teams/intro) and Neo Support — or build a [custom internal bot](/integrations/teams/internal-bot) from an Internal channel, which runs with your full MSP toolbox. ## Ticket links in the chat Whenever the bot mentions a ticket, it shows the human ticket number — and, where your PSA has a client-facing portal link, that number is a clickable link the end user can actually open. For **Autotask**, set this up once: copy your Client Portal address from Autotask (**Admin → Client Portal Global Settings → "Generic Client Portal Login"**, e.g. `https://yourcompany.itclientportal.com`) and paste it under **Integrations → Microsoft Teams — End-user Chat Bot → Ticket links in the chat**. Autotask's API doesn't expose that address, so Neo can't fill it in for you. Until it's set, the bot shows plain ticket numbers — never an internal Autotask link an end user can't open. Note the portal only admits contacts you've granted Client Portal access in Autotask; if only some of your users have it, you can [gate the link per contact from the agent's instructions](/agents/tools/end-user/overview#using-a-custom-field-to-drive-behaviour). ## The Tickets tab **Show the Tickets tab** on the channel's **Teams app** tab gives the app a **Tickets** tab beside the chat. A new end-user channel starts with it on. It lists the signed-in employee's **open** tickets, most recently updated first, and the tickets **closed in the last 30 days** — every ticket filed under their PSA contact, not only the ones the bot created, so a ticket they emailed or phoned in shows up too. Each row has the ticket number, title, status and dates; where your PSA has a client-portal link (see [Ticket links in the chat](#ticket-links-in-the-chat)), the number opens the ticket there. **New ticket** at the top of the tab opens the chat, and the bot asks what the ticket is about, in the end user's Teams language where Neo has a translation and in English otherwise. The bot is told the user asked for a ticket, so it files one for what they describe next, also under the **Troubleshoot first** [ticket policy](#choose-when-the-bot-opens-a-ticket), and that message is not recorded on a ticket the chat was already on (see [What the ticket records](#what-the-ticket-records)). The request lasts an hour, or until the bot files or links a ticket. A ticket the bot files runs your workflows like any other. In Outlook and the Microsoft 365 app, which show the tab but not the chat, the button opens Teams on the chat. **Chat about this** on an open ticket moves the chat onto that ticket. The bot says which ticket the conversation is now on, with its title and status unless you hide them under **Relayed technician messages**, and asks what the user would like to know or add, in the same languages as New ticket. From the user's next reply, the conversation is recorded on that ticket, and your technicians' client-facing updates on it reach this chat. It also works for a user who has not chatted with the bot yet: their first message continues the ticket when they send it within 20 minutes of the tap. The tab follows the end user's Teams theme, including dark and high contrast, and fits a phone screen. It is written in the user's Teams language when that is English, French, German, Spanish, Dutch, Italian or Portuguese, and in English otherwise; dates follow their regional format. Ticket titles and status names come from your PSA as they are. Your link labels can follow the language too: see below. A Slack channel shows the same list as the Slack app's Home tab: see [the Slack Tickets tab](/integrations/slack/end-user-bot#the-tickets-tab). **Open the app on** picks the tab people see first. A new end-user channel opens on **Tickets**, with the chat next to it; a channel created before this default opens on **Chat** until you change it. Nobody signs in: Teams tells Neo who is looking, through the **Neo Installer** app the client's admin approved with the [install link](#deploy), and the list is scoped exactly like the bot's own "my tickets" answer — the user's company, resolved from their Microsoft 365 tenant, and the PSA contacts that hold their email address. If no contact has their address, the tab says so and suggests contacting you. Under **Links on the Tickets tab**, add up to five links for the top of the page, such as your emergency line or your IT Glue portal. A link is a web address (https only), a phone number or an email address, with a label of up to 40 characters. A phone number can end in an extension, such as `514-555-0199 x6`, `ext. 6` or `poste 6`. Under **Label in other languages**, a link can carry its label in any of the tab's languages; each person sees the one for their Teams language, and the main label when you left theirs blank. The tab shows a phone number or email address as text beside its label; a tap calls the number, dialling the extension once the call connects, or opens an email, where the device can. Links need no publish: they show the next time the tab loads, or when the user clicks **Refresh** on it. They also show while the client's tenant is not yet linked to one of your companies, when the tab cannot list tickets. Three things to know: * The tab and **Open the app on** are part of the installed Teams app, so they reach a client only after you [publish an update](/chat-agents/channels#publishing-an-update). Adding or removing the tab is a change Microsoft makes each user approve: users who added the app themselves click **Update** in Teams once, while **Install for everyone** tenants update without a prompt. A change to **Open the app on** alone needs no approval. * Turning the tab off also sets **Open the app on** back to **Chat**. * The status column follows **Show the ticket status** below: turn that off and the tab shows no status names either. ## Live ticket updates in the chat Intake is only half of it. When work on a ticket the user raised here produces a **client-facing update**, that update is delivered into the *same* Teams conversation — and the user's reply goes straight back onto the ticket. The Teams thread and the ticket's client-facing notes become two views of one exchange, so a user follows their ticket without leaving Teams or digging through email. <Steps> <Step title="The user raises a ticket"> Through the bot — a new ticket, or a reply on one they already have. </Step> <Step title="A technician (or a Neo workflow) responds"> Someone posts a **client-facing** note on that ticket — the normal way you'd update a customer. </Step> <Step title="It lands in the chat"> Neo relays that update into the same Teams conversation as the bot's next message, usually within seconds of the update. It arrives as a **card showing who replied** — by default the technician's own name and avatar, taken from the note's author in your PSA — with their message and the ticket's title, number and current status below it, so the employee can tell a person replied, not the AI — and which of their tickets it is about. That avatar is a coloured disc of the technician's initials unless you have connected [Microsoft Teams — Technician Mapping](/integrations/teams/workforce-availability#technician-photos-on-relayed-replies), in which case a mapped technician's card carries their real Microsoft 365 profile photo. It is one setup for your whole client base, with nothing to enable per channel, and anyone Neo can't match keeps the initials. You choose per channel what that card shows, under **Relayed technician messages** on the channel's **Chat** tab: * **Show the technician's name** (the default) — the individual who wrote the note, with their profile photo where Neo can find one and coloured initials otherwise. If your PSA doesn't tell us who wrote it, the card falls back to the label you set. * **Show your own name instead** — every relayed message carries your label and your channel's icon, and never an individual's name. Pick this if your technicians rotate, or you'd rather present one brand to end-clients. * **Don't label them** — the note is relayed as plain text with no attribution, as it arrived before labelling existed. The label itself has ready-made wordings in several languages, or write your own. Two switches control the footer under the message, and the **ticket number is always shown** whatever you do with them. **Show the ticket title** (on by default) puts the ticket's own title on its own line above the number. That is what tells one of a contact's open tickets from another — somebody holding six of them thinks in "the password one", not in numbers. A long title is shortened to fit the card. Turn it off if your ticket titles are internal shorthand rather than the words the end-user raised the ticket in. **Show the ticket status** (on by default) puts the current status beside the number. The status is the status name straight from your PSA, in whatever language your PSA is configured in — Neo passes it through and can't translate it on this card, even if your agent is otherwise answering in the end-user's language. Turn it off when that language isn't one this channel's end-users read; it also hides the status column on the [Tickets tab](#the-tickets-tab). </Step> <Step title="The user replies in Teams"> Their reply is recorded on the ticket as a **customer reply**, so the technician sees it on the ticket they're already working — no inbox round-trip. </Step> </Steps> ### What the ticket records Once a conversation is linked to a ticket — the bot created it, or the user replied about an existing one — **every message from both sides lands on that ticket automatically**, turn by turn, while the conversation stays active. Nothing depends on the bot deciding to log something, and nothing in your instructions is needed to make it happen. After more than a day of quiet, the next message starts a fresh conversation: the bot links a ticket again or files a new one before anything more is recorded. One chat covers many problems over its life, so **each message is recorded on the ticket it is actually about**. A follow-up, a correction, an answer to the bot's question, a "thanks, that worked" hours later — all of that continues the ticket the conversation is on. A message that raises a *different* problem does not: it is held back rather than filed as a customer reply on a ticket nobody mentioned, which would have started your customer-replied rules on the wrong ticket. Once the new problem has a ticket of its own, everything said from then on is recorded on it as usual. The messages before that ticket existed are not moved onto it — if the bot asked two questions before filing, those two exchanges are in the ticket's own description rather than as replies. That judgement is made per message, and it can fail: if your PSA won't return the ticket Neo is comparing against, or the check itself errors, the message falls back to the older rule and is recorded on the ticket the conversation was already on. Neo would rather keep the record than lose it, so a rare wrong-ticket reply is possible when the check can't run. * **The user's messages** are recorded as **customer replies** in your PSA's own shape — authored by their contact on Autotask, ConnectWise and Halo (the shape your customer-reply rules react to; on ConnectWise it also sets the ticket's customer-updated flag), and as a visible comment carrying their name on ServiceNow and Syncro. * **The bot's replies** are recorded as **internal notes**, so they never email the customer or fire customer-facing rules — the user already has the reply in Teams. Technicians and Neo's own ticket summaries still see the full exchange, in order. They're written as plain text: PSA note fields don't render the formatting Teams shows, so headings, bold and links are converted rather than left as `**` and `###` characters. * **A closed ticket never receives a customer reply.** A customer reply on a completed ticket is what most "customer replied" rules re-open it on, so once a ticket is resolved the follow-up ("thanks, that worked") is still recorded on it, but as internal notes on both sides — the audit trail is complete and nothing re-opens by accident. If the user comes back with the same problem, the bot files a new ticket, and the conversation follows that decision. If a message ever fails to reach the PSA, Neo keeps it and retries on the next turn — and, when the conversation has ended, within about an hour of the last message, so the final exchange is retried without waiting for a message that never comes. In one rare case — the note landed but Neo could not record that it had — the retry posts the same message a second time; a duplicate note is preferred to a lost one. **A ticket deleted in your PSA stops the retries on ConnectWise, Autotask and Syncro.** Those three report the deletion precisely when the note is rejected, and there is nothing left to write to, so the messages held for that ticket are released instead of being tried again every turn. HaloPSA and ServiceNow reject the note without saying the ticket is gone, so those messages keep retrying until they age out after seven days. Either way, anything the conversation says afterwards is recorded on whichever ticket it is about next. <Warning> **Don't instruct the bot to log the conversation.** "Add the whole conversation as one note at the end", "log every reply to the ticket", "post the transcript when we're done" — the ticket already carries it, and the bot has no tool that posts a note you dictate, so the instruction only gives it a job it cannot do. That is a separate question from *when* a ticket gets opened, which **is** yours to set — see [Choose when the bot opens a ticket](#choose-when-the-bot-opens-a-ticket) below. An instruction like "wait until the conversation is finished, then log it" answers both at once: keep the timing half, drop the logging half. </Warning> **Only client-facing communications relay** — exactly what the user already sees under [their own tickets](#what-end-users-can-access). Internal, technician-only notes never reach the chat; the user's own replies don't echo back to them; and Neo's own bookkeeping notes are filtered out. **The conversation runs through the ticket, entry by entry.** Your technicians never type in the end user's Teams conversation — there is no technician seat in it, and the only two speakers are the end user and the bot. A technician replies the way they already do, by saving a client-facing entry on the ticket, and Neo carries that entry across. The end user's answer comes back on the same ticket, where the technician reads it, in the shape [What the ticket records](#what-the-ticket-records) sets out above. Messages travel both ways, but each one is a ticket entry rather than a live conversation between two people, and which entries cross is the setting below. ### Choose when the bot opens a ticket Two questions decide what your PSA ends up with, and only the first is yours to answer: * **When does a ticket get opened?** The bot's decision, and you set the policy in its custom instructions — there is no hidden setting. That is this section. * **How does the conversation get onto that ticket?** Neo's job, always, from the moment a ticket is linked. Nothing you write changes it — see [What the ticket records](#what-the-ticket-records) above. The policy covers new problems only. A message about one of the user's open tickets ("any news on my email ticket?") or a question about the bot itself ("can I reply to my ticket here?") is not a new problem, so it never opens a ticket, whichever shape you pick. Your instructions don't need to say so. The bot reads the user's open tickets from your PSA when a conversation starts (a new chat, or one reset by `/new` or the idle timer), so it can tell an existing problem from a new one without being asked. "My email ticket" matches the open ticket about email; "Outlook still isn't getting mail" as the opening message matches the open Outlook ticket instead of opening a second one. When the read fails or your PSA is slow to answer, the bot is told the list is missing and looks the tickets up with **Get My Tickets** before it acts on a possible follow-up or files a ticket. The list carries the time it was read: in a conversation that runs past two hours, the bot rechecks with **Get My Tickets** before filing, in case a ticket reached you another way meanwhile. Three shapes cover every bot in production today. **Creating an end-user agent asks you which one** — the cards under **Audience** on the agent's Overview tab — and the choice writes the matching block into the starter instructions for you. Nothing is stored behind it: from then on the instruction text is the only source of truth, so you change the policy by editing that text (or asking Neo Support to). To move an existing agent to another shape, replace its **When to create a ticket** block with one of these: | Shape | When to use it | What lands on the ticket | | - | - | - | | **Ticket first** | Every request must be traceable from the first message — dispatch, SLA clocks, audit. | The user's first message in the body, word for word; every later message about that request as a customer reply, every bot reply as an internal note. | | **Troubleshoot first** (default) | Most questions are how-tos the bot can answer; a ticket only when a technician is needed. | The conversation so far in the body; from then on, every message about that request as above. | | **Record at the end** | Every conversation should leave a record, but technicians should not be paged for chat that resolved itself. | The whole conversation in the body; a resolved ticket when the bot fixed it, an open one when it could not. | <Tabs> <Tab title="Ticket first"> ```text theme={null} When to create a ticket - For every new problem or request, create a ticket immediately, before troubleshooting or answering, with the user's exact words as the description. Do not ask the user to confirm first. - If the user has not described a problem yet ("hi", "new issue"), ask what is going on, then create the ticket as soon as they describe it. - After creating the ticket, continue helping in the same reply: one safe check or one diagnostic question. ``` </Tab> <Tab title="Troubleshoot first"> ```text theme={null} When to create a ticket - If a couple of safe steps don't resolve it, or the issue needs a technician, create a support ticket. Clearly summarise the problem and list the steps already tried and their results, so the technician has full context. - Tell the user the ticket has been logged and that a technician will follow up. ``` </Tab> <Tab title="Record at the end"> ```text theme={null} When to create a ticket - No ticket exists when the chat starts. Create it once you know the outcome. - If you resolved the issue yourself, log it as an already-resolved ticket so the IT team has a record. - If a technician is needed, create an open ticket with the full diagnosis and everything you collected — the user has left the chat, so the ticket must be self-contained. ``` </Tab> </Tabs> **What reaches the ticket, and how, under each shape.** Once the ticket exists, every later message is written to it automatically. What happened *before* it existed is carried by the ticket the bot files — so under **Ticket first** that is one message, and under **Record at the end** it is the whole exchange, under the bot's summary. Either way you write nothing about logging; the difference is only how much of the conversation the new ticket has to carry. Neo rebuilds that exchange from the stored conversation, so the wording and the speaker on each turn are the real ones. Where it can't — a conversation older than the last 200 messages of a long-running session is the usual reason — the bot's own rendering of the exchange is used instead, which can paraphrase a turn or attribute it to the wrong speaker. Everything from the ticket onward is unaffected: those messages are written from the stored conversation. A long exchange doesn't fit a PSA description field, so it isn't kept there. The body then ends with *"Transcript too long for this field — the full chat transcript is in an internal note on this ticket"*, and the transcript follows as one or more internal notes titled **Chat transcript**, split into parts if it needs them. A technician reading a body that stops mid-sentence is told where the rest is. That note is written on a best-effort basis, so the ticket is never held up by it. If your PSA rejects it, the ticket keeps the truncated body and its pointer, the message the user had just sent still reaches the ticket as a customer reply, and the earlier part of the exchange that the body could not hold is not on the ticket. If the problem a closed ticket was about comes back, the bot files a new ticket and names the closed one in its description. <Note> **Record at the end has one limit.** A conversation the bot never opens a ticket for leaves nothing in your PSA. The conversation itself is still in **Chat → History** under the End-user lens; what's missing is the ticket. If every conversation must produce one regardless of outcome, use **Ticket first**. </Note> ### What counts as a client-facing update, per PSA Each PSA models customer communication differently, so Neo keys off that PSA's own signal for "the customer is meant to see this". | PSA | Relayed by default | | - | - | | **ConnectWise** | Every public (Discussion) note | | **Autotask** | Notes published to **All / Customer** | | **HaloPSA** | Actions whose **outcome** emails the user (e.g. *Email User*) | | **ServiceNow** | Customer-visible **Additional comments** | In ConnectWise, a note marked **Internal Analysis** never relays, whatever the settings. So your technicians reply the way they already do: **save a Discussion note on the ticket and the employee sees it in their chat.** Ticking *Email Resource/Contact* is optional — it sends your PSA's usual email as well. If your technicians instead use Discussion notes to document their work, that documentation would reach the employee. Turn off **All public Discussion notes** in the relay settings and Neo falls back to notes ConnectWise actually emailed to the ticket's contact. <Note> If you connected ConnectWise before this default changed, your account keeps the settings you had saved. Open the relay settings and check **All public Discussion notes** to pick up the new behaviour. </Note> These defaults work out of the box. To tune exactly what relays for your PSA — for example narrow ConnectWise back to emailed notes, include customer-visible time entries, or pin the specific HaloPSA outcomes you use — open **Integrations → Microsoft Teams — End-user Chat Bot** and adjust the relay settings. The change applies to your whole client base. #### Autotask: narrow to a Work Type or Note Type If your technicians log *all* their work on the ticket and only some of it is meant for the customer, the toggles above are too coarse — turning on time entries relays every one of them. Autotask lets you narrow further: * **Limit to specific Work Types** — relay a time entry only when its Autotask **Work Type** is one you pick. The common setup is a dedicated *Communication* work type (often applied by a speedcode) that technicians use whenever they contact the customer: pick it here and ordinary work time on the same ticket stays out of the chat. * **Leave out specific Work Types** — relay every time entry except those of the work types you pick. Use it when most time entries are fine for the customer and only one or two work types are noise, such as an internal tech-assist speedcode. A work type you add to Autotask later still relays, with nothing to update here. * **Limit to specific Note Types** — relay a published note only when its **Note Type** is one you pick. Each picker sits under the toggle it narrows and is only active while that toggle is on. **Leaving a picker empty means "don't narrow"** — every entry of that kind relays, which is the behaviour you have today. Clearing a picker restores that, so you can't accidentally mute your relay by emptying it; to stop a kind relaying altogether, turn its toggle off instead. You can set both Work Type pickers. A time entry then relays only when its work type is in the limit and not in the list to leave out; a work type in both stays out of the chat. If Neo can't read a time entry's work type, the limit keeps it out, and the list to leave out lets it through. **Why a time entry needs the Work Type, when a note doesn't.** An Autotask ticket note carries a **Publish** setting, so a technician decides per note whether the customer sees it, and Neo relays only the notes published to *All Autotask Users*. A time entry has no equivalent setting: Autotask requires **Summary Notes** on a ticket time entry and treats that field as the customer-facing description of the work, while **Internal Notes** is the internal field and Neo never relays it. A technician can't mark one time entry as internal, so with time entries switched on, every summary reaches the chat — a bare "Reviewed ticket" and a technical description of the fix alike. The Work Type is the per-entry intent signal Autotask does give you: log customer contact under the work type you allowlisted (or log internal work under a work type you leave out), and keep technical detail on any other work type or in Internal Notes. Gating on the ticket's **status** instead doesn't hold up, which is why there's no setting for it: the status describes the ticket, not the entry. Once a ticket sits in *Waiting Client*, every time entry added while it waits would relay, and a genuine customer update written while the ticket is still *In Progress* would be held back. #### Autotask: time entries need one more webhook field Autotask sends Neo no webhook when a technician saves a time entry and changes nothing else on the ticket. So when time entries relay, Neo also subscribes your Autotask ticket webhook to the **Last Activity Date** field. That field changes on every save to a ticket, so Autotask sends Neo more webhooks than before. Neo adds the field at the next scheduled PSA sync, which runs about once a day. Until then, a time entry reaches the chat only when the same save also changes the ticket's status or queue. The relay is **on by default**. The same panel has a master **Relay ticket updates into the chat** switch at the top — turn it off to stop relaying entirely (your PSA's own customer email still goes out as usual), and the integration card shows **Connected** whenever it's on. **Which tickets relay.** By default, only tickets your bot **raised** relay updates — a ticket created directly in your PSA or by email stays out of the chat, even if a user later asks about it through the bot. If you'd rather follow updates on *every* ticket a user picks up through the bot, turn off **Only tickets the bot raised** in the same panel. <Note> Two things worth knowing today: * The relay is delivered **in addition to** your PSA's own customer email, so a user who is actively chatting with the bot may receive both a Teams message and an email for the same update. * A user receives chat updates only once they've messaged the bot at least once (so there's a live conversation to deliver into). Before that, updates reach them through your PSA's email as usual. (ServiceNow note: only **Additional comments** relay — a message sent from ServiceNow's separate Email tab doesn't appear in the chat.) </Note> The user simply **replies** in the conversation — "yes, it's my laptop", "still happening" — and it lands on the right ticket as a customer reply (see [What the ticket records](#what-the-ticket-records)). They can also ask the bot for the status of any of their tickets at any time (see [What end users can access](#what-end-users-can-access)). ## Consent and security Two separate Microsoft identities are involved. It's worth being precise about what each can do — for your own assurance and to answer a client admin's questions. **The bot** (the app published into the client tenant) is **messaging-only**. Its manifest requests just `identity` and `messageTeamMembers` — receive and send Teams messages, nothing else. It has **no** Microsoft Graph access in the client tenant: it can't read mail, files, directory, or anything else there. Everything the agent *does* runs on **your** integrations under **your** permissions, and every end-user conversation is company-scoped (see [What end users can access](#what-end-users-can-access)). **The Neo Installer** is the app a client admin signs into when they open a magic install link. They grant it, for their whole organization, **delegated** `AppCatalog.ReadWrite.All` (the one permission needed to publish your app to their tenant's catalog *as that admin*), plus `offline_access`, so Neo can re-publish your branding later with **Publish update** instead of asking for consent again, and the sign-in permissions `openid`, `profile` and `email`, which the Tickets tab uses to confirm which employee is looking. A delegated permission never exceeds what the signed-in person can do, and only the consenting admin's sign-in is ever used to publish. It is **not** the bot, and it grants no standing access to the client's data. If you'd rather not have it in a tenant at all, use the [manual zip](#install-the-package-manually) path with the Tickets tab off; with the tab on, the tab still signs users in through the Neo Installer. If you approve the Neo Installer with CIPP or another tenant management tool, give it all five delegated Microsoft Graph permissions the install link grants: `openid`, `profile`, `email`, `offline_access` and `AppCatalog.ReadWrite.All`. These tools set the approval to exactly the list you give, so leaving out `AppCatalog.ReadWrite.All` removes Neo's permission to publish your app in every tenant the tool runs on. If the tool applies the approval as a standard or template, give it the same five, or its next run removes them again. A tenant installed from the [manual zip](#install-the-package-manually) may leave out `AppCatalog.ReadWrite.All`, because Neo never publishes there. **Routing is authorized server-side, not by the app package.** The Teams package carries your branding and the shared bot id — it carries **no authority**. When a message arrives, Neo trusts only Microsoft's signed account of it: the message is authenticated by Microsoft's Bot Framework, and the tenant it came from is the tenant ID Microsoft stamps on it — never anything in the manifest. Neo resolves which channel (and which of your agents) handles it from the **install record** for that `(bot, tenant)`, and the company scope from that tenant's [Company](https://dashboard.neoagent.io/end-companies). So a copied or edited package can't make the bot answer as a different MSP's channel, reach a tenant it wasn't installed in, or widen a conversation beyond the end user's company. **A registration is a claim until it's proven.** When you register a tenant under **White-label installs**, the binding is *unverified* until a tenant admin completes a magic-link consent, or the bot first receives a Microsoft-verified message from that tenant — then it's **verified** and locked to your channel. An unverified claim can be replaced (register the wrong tenant ID, or two providers race on the same one, and a real install wins); a verified install can't be taken over — to move it, remove the holding channel's registration first. Installs into your own tenant are verified automatically. ## Updating the bot after rollout Settings on the channel's **Chat** tab (the welcome message and the assigned agent among them) apply at once. Settings on the **Teams app** tab (display name, description, icons, the Tickets tab) reach a client only after you publish them from the bar pinned to the bottom of the channel's page, which needs no re-consent and no admin-center step. How it works and what users see: [Publishing an update](/chat-agents/channels#publishing-an-update). If a user's Teams then says *You cannot send messages to this bot*, see [Troubleshooting](#troubleshooting). <Info> A publish lists any tenants it couldn't reach under **Some tenants didn't update** — usually because the admin's sign-in has expired or been revoked, or the tenant now blocks custom apps. Send each of them a new link for an admin to re-authorize: the row's **⋮** menu → **Send re-consent link**. A publish doesn't cover tenants you installed via the manual zip; re-upload there with **New version** → **Upload file** in the admin center. </Info> ## Automating with GDAP (CIPP-style) If you run delegated admin (GDAP) across your clients, you don't need to wait on each client's admin — open the install link yourself for any tenant you administer (you'll sign in with your delegated admin rights). For full automation, the same publish is a Microsoft Graph call against the client tenant with a **delegated** admin token holding `AppCatalog.ReadWrite.All` — `POST /appCatalogs/teamsApps` with the package from **Download Teams app package** (then `POST .../appDefinitions` to update) — which slots into a CIPP-style runbook. (Graph's Teams-catalog publish is delegated-only; there is no app-only equivalent.) ## Offboarding a client Remove the company's row under **White-label installs** — routing stops immediately and the bot no longer responds in that tenant. Then have the client's admin remove the app from their Teams admin center so users don't message a dead bot. ## Troubleshooting <AccordionGroup> <Accordion title="The admin approved the link but got an error"> The consent has to be approved **in the client's own tenant**. If the admin was signed into a different tenant (e.g. your MSP tenant) when they clicked, Microsoft consents there and Neo rejects the mismatch. Have them sign out, sign in to the client tenant, and open the link again. A link also dies when its **2-day** window lapses or when a **newer link was generated for the same tenant since** (each new link replaces the last) — the row's status shows which; generate a fresh one. </Accordion> <Accordion title="Publishing failed — the tenant blocks custom apps"> The link removes the upload step, not the tenant's policy. The client tenant must allow custom (line-of-business) Teams apps. Have their admin enable custom app uploads in the Teams admin center, then re-open the link. </Accordion> <Accordion title="The install fails with AADSTS650051 — 'service principal name is already present'"> This almost always follows someone **deleting the Neo Installer app** from the tenant's **Enterprise applications** to retry a failed install. Deleting it only **soft-deletes** the service principal — Microsoft keeps it in a recoverable state for up to 30 days and **keeps its app ID reserved** — so the next sign-in can't re-create it and fails with `AADSTS650051`. The catch: a soft-deleted service principal is **not** listed on the Entra portal's **Deleted applications** page — that page shows deleted *App registrations*, not deleted *Enterprise apps*. Find and purge it with Microsoft Graph (Graph Explorer works), then re-open the link: 1. `GET https://graph.microsoft.com/v1.0/directory/deletedItems/microsoft.graph.servicePrincipal?$filter=appId eq 'a77de2a9-75e6-4627-b50c-82c19e5d28b4'` — the Neo Installer's app ID is the same in every tenant. 2. `DELETE https://graph.microsoft.com/v1.0/directory/deletedItems/{id}`, using the `id` from step 1, to permanently remove it. Then open the install link again. (Waiting up to 30 days for Microsoft to purge the object on its own also clears it — the Graph purge is just the immediate fix.) To avoid this entirely, never delete the Neo Installer app to retry — just re-open the link. </Accordion> <Accordion title="Publish update says some tenants didn't update"> The **Installs** tab shows, under each tenant, what stops Neo publishing there: why a publish failed, or a sign-in that the daily check found broken. It stays until a later publish there succeeds or the sign-in works again: * **Update pending**: Microsoft Teams was busy or still hid the app. Neo's daily run sends it again when it can (above); publishing once more also works. * **Needs a new install link**: the sign-in Neo stored for the tenant no longer works. Use the row's **⋮** menu → **Send re-consent link**. * **Needs a Teams admin**: the person who approved the link is not a Teams or Global administrator, or the tenant blocks custom apps. * **Check the app availability**: the app is in the tenant but hidden from the admin who approved it. See the last item below. * **Last update failed**: anything else. The detail under the line says what Microsoft, or Neo, reported. The same per-tenant reasons are in `GET /public-api/channels/{id}/teams-installs`, which the Neo Support Agent also reads. When the reason is **status 429**, **status 502**, or **Value cannot be null**, Microsoft Teams was busy, or was still hiding the app from the admin's view after an install or an update. **Value cannot be null** often means Microsoft applied the update and then answered with an error. Once a day, Neo tries again: it sends the app you last published to each tenant that doesn't have it yet and still holds its admin's sign-in, as long as the publish reached at least one tenant, you haven't changed the app since, and its icons are uploaded images rather than web links (Neo can't tell whether the image behind a link changed). A tenant still behind a day later needs one of the fixes below. If you want it sooner, publish once more ([who a publish reaches](/chat-agents/channels#publishing-an-update)). Otherwise, that tenant either removed the Neo Installer app (revoking publish rights) or now blocks custom apps. Send its admin a fresh install link to re-consent; the next publish then succeeds. Variants worth telling apart from the error text: * **"Consent expired or was revoked"**: the admin's sign-in that Neo stored for that tenant can no longer publish to its Teams app catalog. Either it expired or was revoked, or a later change to the Neo Installer's permissions in that tenant removed the catalog permission, as a CIPP approval without `AppCatalog.ReadWrite.All` does ([Consent and security](#consent-and-security)). A fresh install link, approved by a Teams or Global administrator, restores it. Neo also checks every tenant's sign-in once a day, marks a tenant that needs a new link on the **Installs** tab, and sends a notice to your Neo Inbox naming it. When the sign-in works again, both clear by themselves. * **"TenantAppDefinitionManifestVersionAlreadyExists"**: the tenant already holds an app version with the number in the error, so Neo did not count this publish as done. Publish once more: each publish sends a higher version number. The admin's role is not the cause. * **"valid Office365 license"** — the person who originally consented has since lost their Microsoft 365 licence, so Microsoft won't let them manage the app catalogue any more. A fresh install link, consented by a licensed admin, fixes it. * **"does not show it to the admin who signed in"** — the app is in the tenant, but Microsoft's catalogue hides it from the admin who opened the install link, so Neo can't find it to update it. Keep the app installed: its users still have it. The usual cause is the app's **Availability**. In the [Teams admin center](https://admin.teams.microsoft.com/policies/manage-apps) → **Teams apps** → **Manage apps**, open your app, click **Edit availability**, include that admin (**Everyone** is simplest) and **Apply**, then publish again. Microsoft can take a day or more to apply the change. Right after an install or an update, Teams can also hide the app for a short time, so if the error shows once, publish again later first. Only if **Manage apps** doesn't list your app was it added another way, such as a hand upload: then remove it and install again from a fresh link. </Accordion> <Accordion title="The Tickets tab asks for approval, or says the app needs approval"> The client's tenant has not approved the **Neo Installer** app for everyone, and its users can't approve apps themselves, so Microsoft sends each employee's request to an administrator (the prompt reads *Approval required*). This happens where the install link was approved by a Teams Administrator, or without the organization-wide approval, and on tenants installed with the [manual zip](#install-the-package-manually). One approval in the client's tenant fixes it for everyone. The simplest way: * A Global Administrator opens a fresh install link: the row's **⋮** menu → **Send re-consent link**. It also publishes the app again. * Or a Global Administrator or Cloud Application Administrator approves the pending request in the [Microsoft Entra admin center](https://entra.microsoft.com) under **Enterprise applications** → **Admin consent requests** → **Neo Installer**. The request is there, not in the Teams admin center. * Or, with CIPP or a similar tool, approve the Neo Installer for the whole organization with the five permissions listed under [Consent and security](#consent-and-security). </Accordion> <Accordion title="Users don't see the change, or the Tickets tab, after Publish update"> Check that the channel's page no longer shows the **Not published** bar, and that the tenant reads **Up to date** under **White-label installs**. Teams can take a few hours to show the update. A user who added the app themselves, where the tenant has no **Install for everyone**, must click **Update** in Teams once when the Tickets tab was added or removed; an admin cannot do it for them. See [Publishing an update](/chat-agents/channels#publishing-an-update). </Accordion> <Accordion title="After Publish update, Teams says 'You cannot send messages to this bot'"> Teams desktop can keep the previous version of the app in a window that was open during the update. That window locks the message box, while the same chat in a new window still works. Have the user quit Teams fully (**Quit** from the system tray on Windows, or **Cmd+Q** on a Mac) and open it again. The bot and Neo are not affected. </Accordion> <Accordion title="Users got a 'finishing setup' greeting instead of my welcome message"> The app was installed before the channel was **Active** or before routing was registered — most common on the manual-zip path. The greeting is one-time, and routing self-heals: activate the channel and confirm the company is registered, and the next message a user sends reaches your agent normally. </Accordion> <Accordion title="In a channel thread it can't see the post I'm replying to"> The agent reads the post that started the thread (see [In a Teams channel thread](/chat-agents/building-a-chat-agent#in-a-teams-channel-thread)), but only once the installed app carries the permission to read channel messages. An app installed before that shipped keeps its old manifest: publish an update from the channel's page, then have a **team owner** re-add or re-consent the app in that team — the consent prompt is per team, not per tenant. Until then the agent answers using only your reply, so paste the details in or quote the post. </Accordion> <Accordion title="My technicians' internal-bot chat now answers as the end-user bot"> Teams attaches a chat to the bot identity. Your internal bot moved onto its own identity, and the end-user bot you then installed in your own tenant took the identity that chat is attached to. So the chat still named after the internal bot now runs the end-user bot. The internal bot is in its new app, linked in the message Neo posted into the old chat. Ask technicians to open it from that link (or from **Apps**) and hide the old chat. For a fresh start in the old chat, type **start a new chat** there. The same link is on the channel itself, so you can send it again without finding the Teams message: **Open the chat in Teams** on the internal channel's **Installs** tab, and **Open in your own Teams** on the end-user channel's **Installs** tab. </Accordion> <Accordion title="A technician's old chat shows a name we don't recognise and says 'Failed to send'"> That chat is on a bot identity no app in your tenant carries any more, so Teams falls back to the raw bot registration name and blocks the message. It happens when the end-user bot was installed in your own tenant before the internal bot had finished moving onto its own identity. Typing **start a new chat** cannot fix it — sending is exactly what is blocked. The technician gets out of it in **Apps**: open the app by name (the end-user bot's **Display name**, or the internal bot's) and message it from there, which starts a chat on the right identity. The old chat can be hidden. If the app does not appear, have them remove and re-add it from **Apps → Manage your apps**. Neo now refuses an end-user self-install while an internal channel is still on the shared identity. Once its new link is generated, have an administrator approve it before you install the end-user bot. </Accordion> <Accordion title="The bot doesn't respond at all"> Check in order: the channel is **Active** (a **Disconnected** channel stays installed but doesn't route); the client company shows under **White-label installs** with the correct tenant ID; and the user messaged 1:1 or @mentioned the bot in a group chat. </Accordion> <Accordion title="The bot says it couldn't reach the service, or couldn't finish"> Ask the user to type **/new** or **"start a new chat"**. Either one starts a fresh conversation, which clears a chat stuck on an old session. If the same message comes back in the fresh conversation, contact Neo support. </Accordion> <Accordion title="A user can't chat, gets no reply, or their chat box is greyed out"> The branded app is **blocked in the client's tenant**. Microsoft rejects messages and notifications with *"(BotDisabledByAdmin) The tenant admin disabled this bot"*, and Teams greys out the compose box — it's per-user, so some of the client's users may work while others are blocked. The **client's** Teams admin allows it in the [Teams admin center](https://admin.teams.microsoft.com): **Manage apps →** the branded Neo app → **Allowed**, and the **app permission policy** assigned to those users must permit it; then have them re-open the app. When Neo sees Microsoft refuse the install welcome this way, the client's row on the channel's **Installs** tab says *Blocked by the tenant's Teams admin* (`blocked_by_admin_at` in `GET /public-api/channels/{id}/teams-installs`). A row without the warning proves nothing: a block Neo did not see leaves no trace, and a new chat or a new install from any user of that tenant clears it. (This is distinct from the tenant blocking custom app *uploads* — that's the publishing-failed accordion above.) </Accordion> <Accordion title="It answers 1:1 but ignores group chats"> That's expected: the agent is **mention-only** in group chats and channels — it answers when @mentioned and stays quiet otherwise, so it never talks over a busy channel. **"start a new chat"** works in groups even without a mention. See [mention mode](/chat-agents/building-a-chat-agent#settings-that-work-differently-in-chat). </Accordion> <Accordion title="The bot says the app isn't fully set up and to contact the IT support team"> The user's Microsoft 365 tenant reached your bot but isn't linked to any company, so Neo refuses to answer rather than run unscoped: the tenant ID was removed from (or never set on) the company under [**Companies**](https://dashboard.neoagent.io/end-companies). Set it, and the fix takes effect on the user's next message; nothing needs reinstalling. (Several companies sharing one tenant ID is fine — Neo scopes each conversation by the speaker's email; see [What end users can access](#what-end-users-can-access).) </Accordion> <Accordion title="The bot says the assistant isn't active any more"> Your Neo account is switched off, so every branded bot you installed stops answering. Your clients' users see *"This assistant isn't active any more. Please contact your IT provider."* — the message points them to you and never names Neo. The bots stay installed in your clients' tenants. When your account is active again, the next message a user sends gets an answer. Nothing needs reinstalling. </Accordion> <Accordion title="Autotask: users' replies land under your API user, not under the customer"> When a user replies in the chat, Neo records it on the ticket as a **customer reply** authored by that person's Autotask contact — which is what flips the ticket to *Customer Note Added* and fires your customer-note workflow rules. If the note shows your Neo API user as the author instead (and no workflow rules fire), the API user's security level is missing **Contact Impersonation**. Autotask fails this **silently**: it accepts the note, drops the contact, and returns success. Nothing errors, so the only symptom is the author name on the note. Fix it on the security level assigned to your Neo API user — **Admin → Organization Settings & Users → Resources/Users (HR) → Security Levels →** your Neo API user's level **→ Web Services API → Contact Impersonation** — and check **Add** for **Tickets** and **Ticket Notes** (or click **Full Permission** on the whole Web Services API section, as the [security level guide](/integrations/psa/autotask/creating-security-level) shows). Save, and the next reply a user sends is authored by their contact. Nothing needs reinstalling and existing notes are not rewritten. If another API user in the same Autotask instance already writes notes attributed to contacts, that confirms the instance supports it and only this security level is missing the grant — compare the two levels side by side. This is separate from **Resource Impersonation** on the same page, which is what makes records a *technician* asks Neo for in Teams carry the technician's name. </Accordion> <Accordion title="I can't add the company to White-label installs"> Two causes: the company has no Microsoft 365 tenant ID (set it on [**Companies**](https://dashboard.neoagent.io/end-companies) — it must be the tenant GUID), or that tenant is already bound to another of your channels — one branded bot per client. </Accordion> </AccordionGroup> <Tip> This bot is for your **clients' end users**. For your own technicians, use the [Neo AI Agent app](/integrations/teams/intro) (notifications, approvals, Neo Support) or a [custom internal bot](/integrations/teams/internal-bot) you build. </Tip> # Custom internal bot for your technicians Source: https://docs.neoagent.io/integrations/teams/internal-bot Put a chat agent you build — your prompt, your tools, your branding — in your own technicians' Microsoft Teams, as a bot separate from the Neo AI Agent app You can put a chat agent **you build** — your instructions, your tools, your branding — in front of **your own technicians** in Microsoft Teams. It installs into your own Microsoft 365 tenant as its own bot, separate from the Neo AI Agent app, and runs with the full MSP toolbox you give it. This is the technician-facing counterpart to the [branded end-user bot](/teams-bot): same channel machinery, but pointed at your own tenant and your own team instead of a client's. ## Neo Support Agent vs. your own internal agent Two different things can answer your technicians in Teams — and it's easy to conflate them. Pick by what you need: | | Neo Support Agent | Your own internal agent | | - | - | - | | **Built by** | Neo — managed, you can't edit it | You — your instructions, your toolbox | | **Brand** | Neo | Yours, per channel | | **In Teams via** | the **Neo AI Agent** app (from AppSource) | a **channel** → **Install in your tenant** — a separate branded bot | | **How many** | one per tenant | as many as you build | | **What it does** | answers Neo setup questions, searches your docs and tickets (read-only) | whatever you configure — your full MSP toolbox | | **Notifications & approval cards** | **yes**, through the app | **no** — those still arrive through the Neo AI Agent app | | **Cost** | support tooling is free | billed like any chat agent | Reach for the [Neo Support Agent](/chat-agents/neo-support-agent) for "how does my Neo setup work?" or "find me a similar past ticket." Build your **own** internal agent when you want a purpose-built assistant with your prompt and your tools — see the [five common internal patterns](/chat-agents/building-a-chat-agent#what-technicians-use-internal-chat-agents-for), from a research copilot and on-demand reporting to a [self-serve ticket dispatcher](/recipes/technician-self-serve-dispatch). You don't have to start from scratch: [copy the Neo Support Agent](/chat-agents/neo-support-agent#copy-it-for-a-head-start) into your own editable agent and build from there. <Note> The two **coexist**: a technician can have both the **Neo AI Agent** app and your custom bot in their Teams, side by side. Workflow notifications and [Technician-in-the-Loop](/core/technician-in-the-loop) approval cards always arrive through the **Neo AI Agent** app — never through a custom internal bot. Your custom internal bots coexist too: you can run **several internal bots at once** — say one for dispatch and one for documentation — because each new internal channel gets its own bot identity. And an [End-user bot](/integrations/teams/end-user-bot) can be installed in your **own** tenant alongside them, if you want to see exactly what your clients' employees see. Internal channels created before this capability share one bot identity; if a new install reports the identity is taken, the fix is self-serve: open the older internal channel, remove its registration under **Install in your tenant** on its **Installs** tab, and generate a new install link — the channel moves onto its own bot identity automatically. Finish the whole move before you install anything else on the shared identity. Removing the registration does not take the old app out of your Teams catalog, and neither does generating the link — the app is replaced when an administrator opens that link and approves it. An end-user bot installed in between would land on an identity the old app still holds, and your technicians' existing chats would stop sending. Neo refuses that install until you have generated the new link. The refusal lifts then, before the approval, so wait for the approval yourself. Install from the new link, then retry the install that was blocked. Neo updates the app in your Teams catalog in place, so there is no old app to remove. Each technician's existing chat with the bot stays behind, because Teams attaches a chat to the bot identity. Neo posts a message into that chat with a link to the new one; technicians can hide the old chat. The same link is on the channel itself as **Open the chat in Teams**, so you can re-send it to anyone who lost the message. If you then install an end-user bot in your own tenant, it takes over that old chat, and its first message says so. </Note> ## Deploy your internal bot <Info> **Before you start:** an [Internal chat agent](/chat-agents/building-a-chat-agent) you've tested, an admin sign-in to the dashboard, and the ability to install custom Teams apps in your own Microsoft 365 tenant. </Info> <Steps> <Step title="Build an Internal chat agent"> Create a [chat agent](/chat-agents/building-a-chat-agent) and set its **Audience** to **Internal**. An Internal agent carries the MSP toolbox you give it — PSA, RMM, Microsoft 365, documentation, cross-company lookups — unlike an [End-user agent](/chat-agents/how-end-user-bots-work), which is locked to one company. For a head start, [copy the Neo Support Agent](/chat-agents/neo-support-agent#copy-it-for-a-head-start) and customize the copy instead of starting blank. Test it from [**Chat** → **Agents**](https://dashboard.neoagent.io/chat?tab=agents) → **Chat**. </Step> <Step title="Create an Internal channel"> Open [**Chat** → **Channels**](https://dashboard.neoagent.io/chat?tab=channels) → **New Channel**. Pick the **Teams** transport, set **Audience** to **Internal**, name the channel, assign your internal agent (the picker only shows agents whose audience matches), and click **Create channel**. The channel starts **Active**. Branding is optional; blanks use a Neo default. Set the name and icon your technicians see on the **Teams app** tab, and the welcome message on the **Chat** tab. </Step> <Step title="Install it in your tenant"> On the channel's **Installs** tab, under **Install in your tenant**, click **Generate install link** and open it yourself as a **Teams or Global administrator** of your tenant. One sign-in publishes the bot into your own Microsoft 365 and switches routing on. <Warning> That sign-in adds a **Neo Installer** app to your tenant's **Enterprise applications** — this is expected and safe: it only publishes your bot to the catalog and gets no standing access to your data. If a sign-in ever errors, **open the link again — don't delete the Neo Installer app to "start fresh."** Deleting it soft-deletes the underlying service principal and keeps its app ID reserved, so the next sign-in fails with `AADSTS650051: …service principal name is already present`, and the deleted object **isn't shown** on the portal's *Deleted applications* page. If you've already hit this, see [recovering from a failed install](/integrations/teams/end-user-bot#troubleshooting). </Warning> Prefer a manual upload? The **⋮** menu → **Download Teams app package** gives you the `.zip` to sideload in your Teams admin center; then use **Already installed it manually? Register directly** to bind routing. </Step> <Step title="Make it reach your team"> Publishing puts the app in your org catalog — to give it to everyone, open your [Teams admin center](https://admin.teams.microsoft.com/policies/manage-apps) → **Manage apps**, find your app, then **Users and groups** → **Installs** → **Install app** → **Install to: Everyone** → **Apply**. New technicians then get it automatically. </Step> <Step title="Verify"> Click **Open the chat in Teams** on the **Installs** tab and ask the bot something. It answers as your MSP with the toolbox you configured — it can work across all your companies, exactly as the same agent does in the dashboard. Typing **"start a new chat"** starts a fresh conversation. Use that link rather than searching Teams. A bot nobody has messaged yet is in no chat list and no search result, and a chat left over from an earlier bot identity carries the old name. The link always opens the right one, and it is the link to pass to a technician who cannot find the bot. </Step> </Steps> ## Who can message it Who may message an internal bot is set under [**Roles & Access** → **Chat Agent Access**](/product/rbac#chat-agent-access) (Everyone, Admins only, or Specific people), exactly as for any [internal chat agent](/chat-agents/building-a-chat-agent#who-can-chat-with-the-agent). A technician who isn't permitted gets *"You don't have access to this assistant"* in Teams. Under **Admins only** or **Specific people**, a technician needs a membership in [Roles & Access](/product/rbac) to be admitted at all. Add the ones who only use Teams through [Add technicians](/product/rbac#adding-technicians-in-bulk), with the **Chat only** role. Messaging the bot and reading your company's data through it are separate settings. A technician in Teams with no dashboard account may still be allowed to message it, and what it may read for them comes from [AI chat data access](/product/rbac#ai-chat-data-access) — their own grants, or the workspace default for people without an account. ## Why it installs only in your own tenant An Internal channel can be installed **only** in your own Microsoft 365 tenant. Because it runs with your full, cross-company MSP toolbox, Neo refuses to install it into a client tenant — that would hand a client's employees an agent that can see your whole client base. The dashboard offers an end-client-company picker only for **End-user** channels, and the server enforces the same rule regardless of how the request is made. To serve a **client's** employees instead, build an [End-user bot](/integrations/teams/end-user-bot): those are scoped to one company by construction and safe to install in a client's tenant. ## Using it in a chat with a client You can add an internal bot to a group chat that includes people outside your tenant — a client in a federated (external) chat, for example — and your technicians can use it there. A tech can pull a ticket up, check a device, or look something up without leaving the client's chat. **Only your own people can ask it anything, or approve what it wants to do.** It never answers, takes an action, or runs a command for anyone outside your tenant — a federated client, or a guest account in your directory. When one of them asks it something or taps one of its cards, it replies *"I can only answer questions from people inside the organisation I work for"*. Your technicians keep using it normally in the same chat. This holds in **every** conversation, a one-to-one chat with the bot included. A guest account lives in your own directory, so a guest can open a one-to-one chat with the bot — and the bot declines it there too. <Warning> The **answer** is posted into the chat, so everyone in it can read it. The bot works with your full cross-company toolbox, so treat asking it something in a client's chat exactly like typing the answer in yourself: it is your technician's call what to surface there. </Warning> If you want a bot a client can talk to directly, that is an [End-user bot](/integrations/teams/end-user-bot) — scoped to one company by construction. <Note> If the bot answers *"I couldn't confirm who you are just now"*, Microsoft did not return the sender's profile in time. Send the message again. </Note> ## Branding updates The welcome message, the other settings on the **Chat** tab and the assigned agent apply at once. The display name, description and icons on the **Teams app** tab are part of the installed Teams app: after a change, click **Publish to your tenant** in the bar pinned to the bottom of the channel's page. For a manual-zip install, re-upload the package in the admin center instead. How the update reaches technicians: [Publishing an update](/chat-agents/channels#publishing-an-update). If a technician's Teams then says *You cannot send messages to this bot*, have them quit and reopen Teams ([details](/integrations/teams/end-user-bot#troubleshooting)). ## Troubleshooting <AccordionGroup> <Accordion title="The bot is installed but answers nothing"> First send it a message in a one-to-one chat. In a group chat or a channel, a bot that answers only when mentioned stays silent until you @mention it. If the one-to-one chat is silent too, your Teams admin settings can **block the app**, for some technicians or for all of them. Microsoft then delivers no message from a blocked technician to the bot, so the chat stays silent while the install still shows as installed. When Neo sees the block, the channel's **Installs** tab says *Blocked by the tenant's Teams admin*. Neo sees it when Microsoft refuses the install welcome with *"(BotDisabledByAdmin)"*. A Teams Administrator or Global Administrator of your tenant fixes it in the [Teams admin center](https://admin.teams.microsoft.com): 1. Open **Teams apps → Manage apps**, find your bot's app and set it to **Allowed**. 2. Check that the **app permission policy** and the app's **availability** include the technicians who use it. Microsoft can take a few hours to apply the change. Each technician then opens the chat again. The warning clears when a new chat or a new install from any technician in your tenant reaches Neo. Technicians the block still covers can stay blocked after it clears, so check the policies for each technician who gets no reply. </Accordion> </AccordionGroup> # Microsoft Teams Source: https://docs.neoagent.io/integrations/teams/intro The Teams apps Neo offers — the Neo AI Agent app, your branded end-user bot, and a custom internal bot — how to tell them apart, and which one to set up Neo shows up in Microsoft Teams as **several separate apps** — easy to mix up, partly because more than one appears in a chat simply as "**Neo**." Two questions pin down which you mean: **who messages it** (your technicians or your clients' employees) and **who answers** (Neo's managed assistant or an agent you built). <Note> **"Bot" vs "chat" are different things.** A **bot** is the installable Teams app — the vehicle that carries notifications, cards, and messages into someone's Teams. The **chat** is the agent that answers inside it. The three apps below are bots; what answers inside each is a chat agent (Neo Support, your end-user agent, or your internal agent). Pick both. </Note> ## The three apps at a glance | | Neo AI Agent | Your branded end-user bot | Your custom internal bot | | - | - | - | - | | **Who messages it** | Your technicians | Your clients' employees | Your technicians | | **App name** | **Neo AI Agent** (on Microsoft AppSource) | Yours | Yours | | **Shows in chat as** | **Neo** | your bot's name | your bot's name | | **Brand** | Neo | Yours | Yours | | **Installed in** | Your own tenant | Each client's tenant | Your own tenant | | **Installed from** | [Microsoft AppSource](https://marketplace.microsoft.com/en-us/product/WA200009699?tab=Overview) | A magic install link (or package) | A self-install link (or package) | | **Who answers / what it does** | Workflow notifications, approval cards, and [Neo Support](/chat-agents/neo-support-agent) chat — all Neo-managed | Your [chat agent](/chat-agents/overview) answering end users | A [chat agent you build](/integrations/teams/internal-bot) answering technicians | A technician can run more than one side by side. Quick routing: * **Your clients' employees** → the [branded end-user bot](/teams-bot) ([deployment guide](/integrations/teams/end-user-bot)). Most teams start here. * **Your technicians, a Neo-managed assistant** → the **Neo AI Agent** app (this page). * **Your technicians, an agent you build** → a [custom internal bot](/integrations/teams/internal-bot). <Info> An older end-user bot, **Neo Pulse** (you may see it under a per-client name like "Acme IT Pulse"), predates the branded end-user bot — treat it as legacy; new rollouts use the [branded end-user bot](/teams-bot). </Info> Separately, [Technician Mapping & Availability](/integrations/teams/workforce-availability) maps technicians to their Microsoft accounts (so a chat agent can act as whoever is asking — "assign to me", and PSA records under their own name) and optionally feeds their presence and shifts to Ticket Dispatch — it's an integration, not an app. ## Which "Neo" do I have? Both the current **Neo AI Agent** and an older, now-retired Neo technician app appear in a 1:1 chat as **"Neo"** — you can't tell them apart from the chat alone, yet notifications and approval cards only reach the **current** app. If a technician's Teams notifications and approvals have **stopped arriving** (or just to be sure), (re)install the current app — installing is idempotent, harmless if they already have it. Identify it by its **listing**, not the chat name: **Neo AI Agent** on [Microsoft AppSource](https://marketplace.microsoft.com/en-us/product/WA200009699?tab=Overview), published by *Neo Agent LTD* — install it [below](#install-the-app). **The rest of this page covers the Neo AI Agent app.** ## What your technicians get * **Notifications** from workflows — ticket alerts, escalations, daily digests — as 1:1 Teams messages. * **Approval cards** for [Technician-in-the-Loop](/core/technician-in-the-loop) sign-off — approve or reject right in Teams. * **Neo Support** — message the bot anything you'd ask the [Neo Support Agent](/chat-agents/neo-support-agent). Answers from the **Neo AI Agent** app carry Teams' **AI generated** label beside the bot's name. Hover it and Teams shows its own note: *AI-generated content may be incorrect.* It marks chat answers only — approval cards and error notices don't carry it, and neither do workflow notifications, whose wording a model may still have written. Your own [branded bots](/chat-agents/channels) are unlabelled: the label meets a Microsoft Store requirement that applies to the Neo app, and what your bots show is your call. If a reply is inaccurate, harmful or objectionable, send it to [support@neoagent.io](mailto:support@neoagent.io). ## Install the app Installing **is** the registration: the moment the app lands in a technician's Teams, Neo captures the delivery route and they become reachable for notifications and approvals — there's no separate sign-up. ### Roll it out across your team (recommended) A Teams admin does this once for everyone in the [Teams admin center](https://admin.teams.microsoft.com): **install** it, then **pin** it to the sidebar. <Steps> <Step title="Install for everyone"> **Teams apps → Manage apps** → search **Neo AI Agent** → open it → **Users and groups** → **Installs** → **Install app** → **Install to: Everyone** (or a specific group/team) → **Apply**. </Step> <Step title="Pin it to the Teams sidebar"> **Teams apps → Setup policies** → open **Global (Org-wide default)** (or a custom policy assigned to your techs) → **Pinned apps** → **+ Add apps** → search **Neo AI Agent** → **Add** → order it → **Save**. Neo then sits in the left app bar so technicians can open Neo Support anytime, not only when a notification arrives. Policy changes can take a few hours to reach clients. </Step> </Steps> ### Install individually Each technician adds it from the Microsoft AppSource listing — <a href="https://marketplace.microsoft.com/en-us/product/WA200009699?tab=Overview">open the Neo AI Agent listing</a> → **Get it now**, then right-click it in the sidebar → **Pin** to keep it handy. ## Notify technicians from workflows Technicians with the app installed appear in the recipient pickers of the Notify actions: * [Notify Internal Team](/building-automations/actions/notify/notify-internal-team) * [Notify Ticket Owner](/building-automations/actions/notify/notify-ticket-owner) * [Notify Ticket Contact](/building-automations/actions/notify/notify-ticket-contact) <Warning> A technician **without** the app can't receive Teams messages: the send fails for that person, the failure is reported in the action's run output, and the workflow continues. There is no automatic fallback to email — configure Email as the notification channel explicitly where you want it. </Warning> ## See who has Neo in Teams The [**Technicians**](https://dashboard.neoagent.io/profiles) page marks every technician whose Microsoft account has the Neo AI Agent app with **Teams installed**, and its **Teams app** filter shows the technicians whose app is installed, not installed, or who have no Microsoft account linked. Neo links a technician to their Microsoft account by name after each technician sync, or you link one by hand in the technician's **Microsoft** pane. When you select **Add Technician**, a PSA technician whose name matches, one to one, a Microsoft account that has the Neo AI Agent app and no technician yet is listed first, marked **Uses Teams**. People who use Neo in Teams but are not in your PSA, such as owners and service managers, are not on that page. They still receive the notifications and approval cards you send them. ## Remove someone from Neo in Teams Neo keeps one entry per Microsoft account that has used a Neo app, not one per human. If someone has more than one account that has used the app — an old account kept after a rename or migration, plus a separate admin account — each one is a separate entry with its own **Entra ID**. To remove one, ask the [Neo Support Agent](https://dashboard.neoagent.io/support), for example *"Remove Dana Patel's old account from Neo in Teams"*. It finds the account, shows you which one it means, and removes it once you confirm. Removing an entry: * takes it out of every Notify recipient picker * stops notifications and approval cards going to that account * leaves that person's ability to chat with Neo untouched — they can still message the app and get replies Removal sticks on its own. If the account messages the bot again it does **not** come back — that's deliberate, so a removal you meant isn't undone the next time that person says hello to Neo. To undo a removal, ask the Neo Support Agent to restore that person. A restored account is notifiable again straight away. There's nothing for the person to reinstall and no need to wait for them to message Neo first — Neo kept their chat open the whole time, it just stopped treating them as a notification recipient. <Warning> Tell the Neo Support Agent which account by its **Entra ID** when one person has two. Removing the one they actually use stops their notifications — so check the Entra ID against the account in your Microsoft 365 admin center first. If the wrong one goes, ask it to restore that account. </Warning> ## Post to a Teams channel or chat Neo posts to a Teams **channel** or **group chat** **through the Neo app itself** — the same app that sends technician DMs and approval cards. The message arrives as a proper post from Neo, supports the same rich formatting, and doesn't depend on any email plumbing. <Steps> <Step title="Add Neo to the channel or chat"> **To a channel:** a Team owner adds the **Neo AI Agent** app to the Team once — in the Team, open `···` → **Manage team** → **Apps** → **More apps** → find **Neo AI Agent** → **Add**. Every channel in that Team then becomes available to Neo; you don't add it per channel. **To a group chat:** open the chat's participants menu (top-right) and choose **Add agents**, then pick **Neo AI Agent** and click **Add**. Neo joins and posts a short hello — it's ready to receive notifications. <Frame> <img alt="Add agents to a Microsoft Teams chat" /> </Frame> <Frame> <img alt="Add the Neo AI Agent app to the chat" /> </Frame> <Frame> <img alt="Neo AI Agent added to the chat, posting its greeting" /> </Frame> </Step> <Step title="Pick it as a notification destination"> * In a **workflow**, open the [Notify Internal Team](/building-automations/actions/notify/notify-internal-team) action, set the channel to **Teams**, and choose from the **Teams channels & chats** picker (channels show as *Team / Channel*; group chats show their name). You can mix channels, chats, and individual technicians in one action. * In an **agent**, the [Send Teams Message](/agents/tools/communication/send-teams-message) tool posts to a channel or chat — set its **Channels & chats** scope to *Any* or *Only specific* to allow it. * To let an **agent read** a channel, for example a channel where your team posts client travel, turn on the [Read Teams Channel Messages](/agents/tools/communication/read-teams-channel-messages) tool and pick the channel. * For **approvals**, pick the channel or chat on the [Request Technician Approval](/agents/tools/approvals/request-technician-approval) tool or on [Ticket Dispatch](/building-automations/actions/ai/ticket-dispatch-suggest-technician#human-in-the-loop-approvals). Neo posts the approval card there, and anyone in the channel or chat can answer it. See [Approvals in a Teams channel or chat](/core/technician-in-the-loop#approvals-in-a-teams-channel-or-chat). </Step> </Steps> <Note> **Where Neo can post.** **Standard** channels and **group chats** work as soon as the app is added. **Shared** channels (Teams Connect) are supported once your admin allows the app in shared channels. </Note> <Note> **Made a new channel?** It joins the picker on its own — reopen the picker to see it. **Private** channels are the exception: Microsoft leaves them out of the Team's channel list, and adding the app to a private channel does not put it in the picker. Mention `@Neo AI Agent` in the channel once, then reopen the picker. If Neo cannot read the channel's name, the channel shows as *Team / Unnamed channel*. Picking it still allows only that one channel. </Note> <Note> **Renamed a Team or channel?** The picker follows the new name after the next message anywhere in that Team. </Note> <Warning> **Already using the email-address workaround? Switch it over.** Older setups posted to a channel by emailing its connector address (`…@amer.teams.ms`). That path is fragile — it can show the wrong sender and occasionally double-posts (a Microsoft-side email quirk we can't dedupe). Re-point each such Notify action to the native **Teams channels & chats** picker above and remove the channel email from the recipients. Native posting is the recommended way. </Warning> <Accordion title="Legacy: post via the channel email address"> Only needed for a Team you can't add the Neo app into. <Steps> <Step title="Get the channel email"> Open the channel → click `...` → select `Get email address`. <Frame> <img alt="Get channel email address in Microsoft Teams" /> </Frame> </Step> <Step title="Allow external senders"> Open `Advanced settings` and enable `Anyone can send emails to this address`. Copy the email and save. <Frame> <img alt="Enable external senders for the channel email" /> </Frame> </Step> <Step title="Use it in a Notify action"> Paste the channel email into the [Notify Internal Team](/building-automations/actions/notify/notify-internal-team) action as an email recipient. <Frame> <img alt="Use channel email in the Notify Internal Team action" /> </Frame> </Step> </Steps> </Accordion> ## Troubleshooting <AccordionGroup> <Accordion title="The same technician has two Microsoft accounts in Teams"> They have two Microsoft accounts that have both used the Neo app — commonly an account kept after a rename or tenant migration, plus its replacement, or a personal and an admin account. The two entries carry different Entra IDs and are different Teams users to Microsoft, so Neo lists both. Notifications go to whichever of the two most recently messaged the bot. To make it unambiguous, remove the account they no longer use — see [Remove someone from Neo in Teams](#remove-someone-from-neo-in-teams). </Accordion> <Accordion title="A technician can't chat with Neo, gets no reply, or the chat box is greyed out"> Their Microsoft 365 tenant has the **Neo AI Agent** app blocked. Microsoft then rejects every message and notification to that person with *"(BotDisabledByAdmin) The tenant admin disabled this bot"*, and Teams greys out the compose box. This is set in **your own Teams admin**, not in Neo — and it's per-user, so some technicians can be working while others are blocked. Fix it in the [Teams admin center](https://admin.teams.microsoft.com): **Teams apps → Manage apps → Neo AI Agent** must be **Allowed**, and the **app permission policy** assigned to the affected technicians must permit it. Then have them re-open the app. Policy changes can take a few hours to apply. </Accordion> <Accordion title="Posts to a channel or chat stopped arriving"> The run shows the post as failed with *"the Neo AI Agent app is not a member of this team or chat"* (Teams error *BotNotInConversationRoster*). Someone removed the **Neo AI Agent** app from that Team or chat, so Teams refuses every post from Neo there. Add the app back — see [Post to a Teams channel or chat](#post-to-a-teams-channel-or-chat). For a Team, this brings back every channel in it. </Accordion> <Accordion title="Notifications or approval cards still arrive on the old 'Neo' app, not the new one"> Two causes. Most often the technician is **still only on the retired app** — (re)install the current **Neo AI Agent** (idempotent; see [Which "Neo" do I have?](#which-neo-do-i-have)). If they already have the new app but it's **blocked by your tenant admin** (above), Neo can't deliver to it — clear the app block and have them re-open the app. </Accordion> </AccordionGroup> # Microsoft Teams — Technician Mapping Source: https://docs.neoagent.io/integrations/teams/workforce-availability Map your technicians to their Microsoft accounts (for chat dispatch) and, optionally, feed live availability into Ticket Dispatch The **Microsoft Teams — Technician Mapping** integration connects Neo to your **own** Microsoft 365 tenant (not your clients' tenants) and does three things: * **Maps each technician to their Microsoft account** — the foundation. This identity link is what lets a chat agent recognise *whoever is asking*, so it can assign a ticket to them ("assign this to me") and [record what it creates in your PSA under their name](/chat-agents/building-a-chat-agent#psa-records-carry-the-technicians-name) rather than Neo's — their time entries land on their own timesheet. It works in a [custom internal bot](/integrations/teams/internal-bot) and in the dashboard chat, and it's the prerequisite for everything below. * **Puts real faces on relayed ticket replies** — automatic. When a technician answers on a ticket, that reply is [relayed into your end-user Teams bot](/integrations/teams/end-user-bot#live-ticket-updates-in-the-chat) as a card. A mapped technician's card carries their own Microsoft profile photo instead of coloured initials. There is nothing to switch on: once the integration is connected, map the technician and their photo appears. * **Feeds live availability into Ticket Dispatch** — optional. With **Teams availability** turned on for a dispatch workflow, Neo won't assign work starting now to someone who is Away, Offline, or out of office, prefers technicians whose Teams Shifts rota covers the time the work would start, reads each shift's label (an on-site client name, or an absence marker like *Annual Leave*), and excludes anyone whose Shifts **time off** overlaps the work for an absence reason. <Tip> Connecting the integration only performs the **mapping** — it does not change dispatch on its own. Availability is opt-in **per dispatch workflow** (and Shifts is a further opt-in), so you can connect this purely for chat dispatch without affecting how tickets are routed. </Tip> <Info> This integration reads your **service desk's own** Microsoft tenant. It is separate from the [Microsoft 365 integration](/integrations/m365/intro) that lets agents act on your end-clients' tenants. </Info> ## Set it up You'll need an administrator of your own Microsoft 365 tenant for step 2 — someone who can grant admin consent (typically a Global Administrator). <Steps> <Step title="Open the integration"> Go to [**Integrations** → **Directory** → **Identity & Workspace**](https://dashboard.neoagent.io/integrations?tab=directory\&category=Identity%20%26%20Workspace) and click **Microsoft Teams — Technician Mapping**. The connect panel shows consent, technician mapping, and optional Shifts settings. </Step> <Step title="Grant admin consent"> Click **Open consent page**. Microsoft's consent screen opens in a new tab and lists what Neo asks for — sign-in basics plus four **read-only** application permissions: | Permission on the consent screen | Why Neo needs it | | - | - | | Read presence information for all users | Live Teams presence (Away/Offline/out-of-office) at dispatch time | | Read all schedule items | Your Teams **Shifts** rota, if you use one | | Read all group memberships | Listing your Teams and their members for the technician auto-map | | Read all users' full profiles | The members' email/sign-in name — the key the auto-map matches technicians on | Neo never writes anything in your tenant, and these permissions do not cover chats, files, or mail. After you accept, you land back in the Neo dashboard — click **Continue setup** to return to the integration. </Step> <Step title="Add technician profiles"> Auto-map works on the technicians listed on the [**Technicians**](https://dashboard.neoagent.io/profiles) page. Add at least one technician there before you run it. Neo does not create profiles for every PSA account automatically. </Step> <Step title="Auto-map technicians"> Click **Run auto-map**. Neo scans every Team in your tenant, then matches each technician profile by comparing its PSA email against each Microsoft member's email or sign-in name (UPN). The review shows **Matched** and **Unmatched** technicians. Map any unmatched technicians manually — see [Mapping technicians](#mapping-technicians). </Step> <Step title="Configure Shifts (optional)"> If your rota lives in the Teams **Shifts** app, turn on **Read shift rota from Microsoft Teams Shifts**, select the Team(s) that hold the rota, and click **Save shift settings**. This Team picker affects Shifts only; auto-map always scans every Team. </Step> <Step title="Turn it on per workflow"> Enable the **Teams availability** toggle on a [Ticket Dispatch action](/building-automations/actions/ai/ticket-dispatch-suggest-technician#teams-availability-presence-shifts). A workflow can also override the saved rota Teams in the toggle's settings. </Step> </Steps> ## Mapping technicians The integration runs on one piece of state: a link from each PSA technician to their Microsoft account. Dispatch only sees presence and shifts for **mapped** technicians. * **Neo links by name after each technician sync.** The sync runs every day and when you add technicians. A technician with no link gets one when exactly one technician and exactly one Microsoft account share the name. The accounts are the people who use Neo in Teams and your dashboard members. A name that two technicians or two accounts share stays for you to map. A name link needs no admin consent, so on its own it brings no presence, shifts or photo: those read Microsoft 365, which needs the integration's consent. * **Auto-map matches on email.** The technician's email address in your PSA must equal the Microsoft account's email or sign-in name (UPN). Technicians whose PSA record uses a different address — an alias, a shared address, a personal email — come back as **Unmatched**. An email match replaces a name link. * **Manual mapping.** Open [**Technicians**](https://dashboard.neoagent.io/profiles), open the technician's **Microsoft** pane, and pick their **Microsoft account** from the list, or type the Entra object ID. A badge shows how the mapping was set: **Auto-mapped**, **Matched by name** or **Manual**. One Microsoft account belongs to one technician, so an account another technician holds is refused. * **Re-running auto-map never touches manual work.** Auto-map always scans every Team. It never overwrites or clears manual mappings, but it clears an auto-derived mapping when that technician no longer matches any Team member. * **To remove a mapping by hand**, clear both fields in the technician's Microsoft Teams Mapping section and save. The technician then stays unlinked: neither the name match nor auto-map links them again until you set a mapping by hand. * **Find the gaps.** Open a technician on the [Technicians](https://dashboard.neoagent.io/profiles) page and select **Microsoft** to see their mapping and how it was set. A technician whose name matches no account, or matches more than one, stays unmapped until auto-map finds their email or you map them by hand. * **An unmapped technician cannot be recognised in chat.** An internal Chat Agent is told it cannot place the speaker, so it declines a request that needs their PSA technician record, such as showing the tickets assigned to them, assigning or dispatching a ticket to them, or logging their time, and tells them to have their account mapped. It never picks a technician on their behalf. Requests that need no PSA technician still work: the Neo Support Agent opens a support ticket with the Neo team under the person's verified Teams account. The integration card shows **Connected** once at least one technician is mapped by auto-map or by hand. Name links do not count, because they need no consent. ## Technician photos on relayed replies Your end-user Teams bot relays a technician's client-facing ticket note into the employee's chat as a card showing who replied. Where that card would otherwise show coloured initials, a **mapped** technician gets their own Microsoft 365 profile photo. * **No setup and no switch.** This follows the mapping. Once a technician is mapped and the integration is connected, their photo appears on their next relayed reply. * **A technician who is not on the Technicians page can still get a photo.** Neo falls back to matching the note author's PSA email address against your Microsoft directory, so your whole service desk benefits from the integration, not only the profiles you added. * **Initials whenever there is no photo to show** — an unmapped technician, someone whose PSA email matches nobody, or an account with no photo set in Microsoft 365. Nothing is ever left blank. * **Only your own tenant is read.** The photo is embedded in the card that Neo sends, so your client's Microsoft tenant never reaches into yours to fetch it. * **Photos follow the channel's attribution setting.** A channel set to **Show your own name instead** or **Don't label them** shows no technician photo, because it names no individual — see [Relayed technician messages](/integrations/teams/end-user-bot#live-ticket-updates-in-the-chat). <Note> A newly set photo, or a technician mapped after their first relayed reply, appears within a few hours — Neo caches what it finds so a busy ticket doesn't re-check on every note. </Note> ## What dispatch does with it **Live presence.** A technician whose presence is **Away**, **Offline**, or who has out-of-office set is treated as on a break and is skipped for work starting now. **Busy**, **In a call**, **Presenting**, **Do not disturb**, and **Be right back** all still count as working — being occupied is what workload balancing is for; the presence check only asks "are they at their desk and on the clock?". Presence is a right-now signal, so it is **time-scoped**: when the workflow books a schedule entry further in the future, a technician on a break right now can still get that slot — only slots starting within the next \~2 hours are blocked by live presence. **Shifts.** If you configure the rota team(s) in the dispatch action's Teams availability settings, Neo reads each mapped technician's upcoming shifts and prefers technicians whose shift covers the proposed assignment time. A mapped technician with no shift in the planning window is deprioritized as likely off-rota (custom instructions can override). Shifts influence AI dispatch only; Round Robin uses the on-break presence check. Neo reads each shift and time-off entry on the same clock as the technician's calendar, or in your company's timezone when it reads no calendar for them, so write shift times in your custom instructions on that clock too. By default Neo reads shifts from the current time onward, so a shift that ended earlier today is not in the window. If your instructions make a technician unavailable once their last shift of the day has ended, turn on **Should Neo see today's earlier calendar entries?** in the dispatch action (on a dispatch agent, its technician context needs both `include_teams_availability` and `include_earlier_today`). Neo then also reads today's ended shifts and marks each one as ended. An ended shift does not by itself count as a time clash with a new slot. Neo also reads each **shift's label** (the name you give a shift in the Shifts app). Labels carry meaning, so Neo weighs them rather than treating every shift as plain availability: a shift named for a client or site is read as an on-site commitment (pair it with a custom instruction like *"Don't assign to someone who is on-site unless the ticket is for that same company"*), and a shift named for absence — **Annual Leave**, **Holiday**, **Sick**, **Bank Holiday** — is read as time off, not as a reason to prefer that technician. **Time off.** From the same rota team(s), Neo reads each mapped technician's **Shifts time off**, together with the **reason** you picked for it. The reason decides what happens, because teams use this calendar for more than absence: * A reason that means the person is **away** — *Annual Leave*, *Holiday*, *Sickness Absence*, *Bank Holiday*, *Compassionate Leave* — is a **hard block**. They're excluded from work overlapping it even when their PSA calendar looks clear, because the commitment lives only in Shifts. This is what lets a rota that records only time off (no shifts at all) still keep people off dispatch while they're away. * A reason that records **where or how someone is working** — *London Office*, *Working from Home*, *On Call*, *Training*, *Early / Late Shift*, a client visit — does **not** block them. Neo reads it as context, and you can act on it with a custom instruction (e.g. *"Don't assign to someone recorded as on a client visit unless the ticket is for that client"*). So you don't have to restructure a Shifts calendar that doubles as a location tracker: name your absence reasons plainly and Neo will tell the two apart. **Fallbacks.** The integration never blocks dispatch. If Teams can't be reached, consent was revoked, or no technicians are mapped, dispatch falls back to its normal PSA-based logic and the run output notes why presence wasn't used. Technicians without a mapping are simply judged on the other criteria — they are never penalized for missing presence data. ## Check that it's working Run the dispatch workflow on a test ticket and open the execution's details: * When presence was used, the dispatch reasoning references the technicians' Teams availability (on a break vs. working). * When it wasn't, the run output says why in plain words — for example, *"Teams availability is enabled, but none of the candidate technicians are mapped to a Microsoft user — dispatch used PSA-only availability."* That message points you back to the auto-map step. ## Custom instructions The default break rules can be overridden per workflow with dispatch custom instructions, for example: * *"Treat Do not disturb as unavailable."* * *"Ignore Teams presence for P1 tickets."* ## Troubleshooting <AccordionGroup> <Accordion title="The team list says consent hasn't been granted (or keeps failing)"> Consent must be granted by an admin of **your own** M365 tenant. Grants can take a minute to propagate — click **Retry**. If it persists, re-open the consent page and make sure the flow completed: you should land on a "Consent granted" confirmation before returning to the integration. </Accordion> <Accordion title="Auto-map says no technician profiles are configured"> Add the technicians you want Neo to map on the [Technicians](https://dashboard.neoagent.io/profiles) page, then run auto-map again. Auto-map maps those profiles; it does not add every PSA account automatically. </Accordion> <Accordion title="I don't see a Team picker for auto-map"> This is expected. Auto-map scans every Team so it can find each technician by email or sign-in name. The Team picker appears only when you turn on the optional Teams Shifts rota. </Accordion> <Accordion title="A technician is told their account isn't mapped"> Neo knows who is speaking, but no technician record matches that Microsoft account. The mapping is missing or points at a different account, or that person has no technician profile yet. Open [Technicians](https://dashboard.neoagent.io/profiles) and find that person — if they have no row, add them with **Add Technician** first. Then check their Microsoft Teams Mapping: re-run auto-map, or set the Microsoft Entra object ID by hand (the UPN is optional). The agent declining is the expected behaviour for an unmapped speaker: it never chooses a technician for them. </Accordion> <Accordion title="Auto-map returns everyone as Unmatched"> The match key is the technician's **email address in your PSA** versus the Microsoft account's email/sign-in name. Spot-check a couple of technicians: if your PSA stores a different address (alias, distribution address, personal email), either fix the PSA email or map those technicians manually on the [Technicians](https://dashboard.neoagent.io/profiles) page. </Accordion> <Accordion title="A technician on a break still got a ticket"> Two by-design cases: the assignment was a **schedule entry starting more than \~2 hours out** (live presence only blocks imminent work — the calendar and shifts govern later slots), or the technician shows **Do not disturb / Busy / Be right back**, which count as working. To change the defaults, use custom instructions (e.g. *"Treat Do not disturb as unavailable"*). </Accordion> <Accordion title="A technician's presence is never considered"> Check, in order: the **Teams availability** toggle is on for that workflow; the technician is **mapped** (Technicians page → Microsoft Teams Mapping); and they actively use Teams — accounts without a Teams license or an active session report an unknown presence, which Neo treats as "no signal" rather than on-break, so those technicians are judged on the other criteria only. </Accordion> <Accordion title="Shifts don't seem to influence ranking"> Shift preference requires: the rota Team(s) saved in the integration or selected in the **dispatch action's** Teams availability settings, the rota living in the Teams **Shifts** app of those Teams, and the technicians being mapped. It is also a soft preference for AI dispatch only — Round Robin doesn't consult shifts. </Accordion> <Accordion title="Time off in Shifts isn't excluding a technician"> Shifts time off is read from the **same rota team(s)** as shifts, so it needs the same setup: the rota team(s) set in the dispatch action's Teams availability settings, the time off recorded in the Teams **Shifts** app of those teams, and the technician **mapped**. It applies to AI dispatch only — Round Robin uses the presence check. If the setup is right and the technician still isn't excluded, check the **reason** on the entry: only a reason that reads as absence is a hard block, so someone recorded as *Working from Home* or *On Call* stays dispatchable by design. Rename an ambiguous reason (or add a custom instruction naming it) if you want it treated as absence. </Accordion> </AccordionGroup> ## Security and data * Access is **read-only** and confined to **your own tenant** — the four application permissions above, granted through Microsoft admin consent and revocable in your Entra admin center at any time. * These permissions do **not** let Neo read your chats, files, mail, or calendars. * The only thing Neo stores is the per-technician mapping (the Microsoft account ID and sign-in name on the technician record). Presence and shift data are read at dispatch time and never persisted. ## Public API The integration can also be configured programmatically: * `GET /public-api/teams-availability/consent-url` — get the admin-consent URL * `GET /public-api/teams-availability/teams` — list your tenant's Teams * `POST /public-api/teams-availability/auto-map` — run the technician auto-map Full request/response schemas are in the public OpenAPI spec at `GET /public-api/openapi.json`. # Connecting ThreatLocker to Neo Source: https://docs.neoagent.io/integrations/threatlocker/connecting-to-neo Save your ThreatLocker Portal API URL and key in Neo, and decide what each agent can do You connect ThreatLocker once at the MSP level, then turn it on per agent. Setup takes a few minutes. <Info> ThreatLocker uses a single API URL and key per MSP. Save them once and every agent that has ThreatLocker permissions can use them. </Info> ## 1. Find your API URL and key in ThreatLocker <Steps> <Step title="Find your Portal API URL"> In the ThreatLocker Portal, open the **Help** menu and look for **ThreatLocker Access**. Copy the API URL shown there exactly — it's specific to your ThreatLocker instance, so don't guess or reuse another MSP's URL. </Step> <Step title="Create an API Auth Key"> Go to the **Administrators** page and create an API User, then generate its Auth Key. <Tip> Copy the key somewhere safe once it's generated — you won't be able to view it again in ThreatLocker. </Tip> </Step> </Steps> ## 2. Add the credentials in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the ThreatLocker card, under Security. </Step> <Step title="Save the API URL and key"> Paste both values and click **Save**. Neo checks the key against your portal before storing it — a refused key fails the save with the reason, so a wrong instance letter or a geolocation restriction never saves as "Connected". The **Organization Mapping** tab fills separately: check it a few minutes after the save, and again after the next nightly PSA sync. </Step> </Steps> ## 3. Turn ThreatLocker on per agent Each agent decides whether it uses ThreatLocker and which areas it can touch. Open the agent, go to the Integrations section, and configure the ThreatLocker block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area set to read only. The agent can look up computers, applications, policies, and approval requests, but never makes changes. </Card> <Card title="Helpdesk" icon="headset"> Approval Requests set to read and write — still requires technician approval on every one. Everything else read only. Fits a helpdesk agent resolving the "app is blocked" workflow. </Card> <Card title="IT Admin" icon="user-shield"> Computers, Applications, Policies, and Approval Requests all read and write, but every write waits on a technician. A cautious rollout tier. </Card> <Card title="Full Automation" icon="bolt"> Computers and Applications writes go through on their own. Policies and Approval Requests still always require technician approval — that never turns off. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Computers** | Disabled, Read Only, Read and Write | Computers, computer groups, online status, maintenance mode. | | **Applications** | Disabled, Read Only, Read and Write | Applications and application files seen across the fleet. | | **Policies** | Disabled, Read Only, Read and Write | Application Control / Config Manager policies, network access policies. Writes always wait on a technician. | | **Approval Requests** | Disabled, Read Only, Read and Write | Pending Application/Elevation/Storage Control approval requests. Writes always wait on a technician. | | **Organizations** | Disabled, Read Only | Organization hierarchy and scoping. Neo keeps this read only. | ## Safety controls * **Approving/denying software and editing policies always wait on a technician.** This holds regardless of the agent's automation level or the access profile you picked — it's not a setting you can turn off. The [ThreatLocker API tool](/agents/tools/security/threatlocker-api#safety-controls) reference lists every action that always needs approval. * **Organizations is always read only.** Neo uses it only to see and scope to your organization hierarchy — it never changes it. * **Path safety.** Suspicious URL paths (anything containing `..`, for example) are rejected before they reach ThreatLocker. ## If ThreatLocker refuses Neo's requests ThreatLocker answers a refused request with an error message, and each one has a different fix. Match the most specific row first. | What the error says | Cause | Fix | | - | - | - | | `Unauthorized` on its own, with or without a `TOKEN_REVOKED` code | Either the API user's Auth Key was regenerated or the API user was removed, or your portal's country allowlist does not permit Neo's requests | If the API user still exists, generate a new Auth Key for it in **Administrators**. If it was removed, create the API User again with the access levels your agents need — for each area, the highest level any agent enables (read and write where an agent is set to Read and Write, otherwise read only), plus read only on Organizations for company mapping. An area every agent leaves Disabled needs nothing: Neo blocks those calls before they reach ThreatLocker. Then generate its Auth Key. Either way, save the new key in Neo. If the key is already current, open **Settings > Options** and permit the **United States** in the country allowlist — every one of Neo's [IP addresses](/integrations/ip-whitelisting) egresses from a US region | | `Unauthorized - Request was made from a disallowed geolocation` | Your ThreatLocker portal restricts API access by geolocation, and Neo's requests come from outside the permitted regions | In that restriction, permit the **United States** — every one of Neo's [IP addresses](/integrations/ip-whitelisting) egresses from a US region — or exempt your API user from the restriction. A geolocation control takes regions, not addresses, so listing the addresses on their own will not help — and neither will a new Auth Key | | `Forbidden` | Either the API user does not hold the permission the call needs, or something in front of your portal refused where the request came from | Check the API user's access levels first: for each area it needs the highest level any agent enables — read and write where an agent is set to Read and Write, otherwise read only — plus read only on Organizations. An area every agent leaves Disabled needs no permission at all. If those levels are already correct, the call was refused before ThreatLocker saw it — check any geolocation or address restriction on the portal, as for the row above | Until it is fixed, agents that use ThreatLocker report the failure on the ticket they were working. Neo's ThreatLocker organization mapping also stops refreshing if the refusal reaches the Organizations read it depends on — every `Unauthorized` does, and a `Forbidden` does only when that area is the one being refused. The rest of Neo keeps running. ## Disconnecting ThreatLocker <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the ThreatLocker card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault. </Step> </Steps> Your Organization Mapping is kept, including any mapping you set by hand, so reconnecting later picks up where you left off. Agents that use ThreatLocker stop working until you connect it again. ## Security * The API key lives in Azure Key Vault. It is never stored in plaintext. * All traffic to ThreatLocker goes over HTTPS, to the Portal API URL you saved for your instance. * Write access to ThreatLocker is opt in per area, per agent. Once your credentials are saved and an agent has permissions, the ThreatLocker tool is added to that agent automatically. # Overview Source: https://docs.neoagent.io/integrations/threatlocker/overview What the ThreatLocker integration brings to your Neo Agent setup ThreatLocker is an application allowlisting and endpoint security platform many MSPs run alongside their RMM and PSA. When you connect ThreatLocker to Neo, your agents can look up computers, applications, and pending approval requests, and — with a technician's sign-off — act on them without you switching to the ThreatLocker portal. <Info> ThreatLocker uses a single API key per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with ThreatLocker <CardGroup> <Card title="Computers" icon="desktop"> Search computers and computer groups, check online status, and manage maintenance mode windows. </Card> <Card title="Applications" icon="grid-2"> Search applications and application files ThreatLocker has observed running or being blocked across managed computers. </Card> <Card title="Approval Requests" icon="circle-check"> Find pending software-approval requests and approve or deny them — the "an app won't run" workflow. Approving or denying always waits on a technician. </Card> <Card title="Policies" icon="shield-halved"> View and, with technician approval, edit allowlist policies, Config Manager policies, and network access policies. </Card> </CardGroup> Organizations is also available, read only — ThreatLocker's API doesn't expose a write endpoint for it. ## Why connect ThreatLocker * **The approval queue stops waiting on a human to notice it.** An agent can watch for pending approval requests and hand a technician a ready decision instead of the technician finding it themselves. * **Endpoint security context inside ticket work.** Any ticket agent can check whether a computer is online, what's currently blocked, or what policy applies before touching anything. * **Approving software and editing policies always requires a technician's sign-off**, no matter how automated the rest of the agent is — this is by design, not a limitation you need to work around. The [ThreatLocker API tool](/agents/tools/security/threatlocker-api#safety-controls) reference lists every action that always needs approval. ## How agents reach ThreatLocker When you enable any ThreatLocker permission group on an agent, Neo automatically adds the ThreatLocker tool to that agent's toolbox. There is nothing extra to install and no toolbox tweaking needed. The agent uses the API URL and key you saved in the dashboard, and every call stays inside the areas and access levels you allowed. ## Where to go next <Card title="Connecting ThreatLocker to Neo" icon="plug" href="/integrations/threatlocker/connecting-to-neo"> Setup steps for the API URL and key, per-agent access levels, and the safety controls that stay in place. </Card> # TimeZest Source: https://docs.neoagent.io/integrations/timezest/overview Connect TimeZest to Neo Agent for automated appointment scheduling and calendar management TimeZest integration enables Neo Agent to create and manage scheduling requests, allowing end users to book appointments directly from ticket communications. <Info> TimeZest uses API key authentication for a simple and secure setup process. You'll create an API key in TimeZest and add it to Neo Agent. </Info> ## Prerequisites Before starting the integration setup, ensure you have: * **Admin Access**: Administrator access to your TimeZest account * **PSA Connected**: Your PSA (ConnectWise, Autotask, or HaloPSA) must already be connected to both TimeZest and Neo Agent ## Setup Guide <Steps> <Step title="Navigate to API Keys in TimeZest"> Log in to your TimeZest admin portal and navigate to **API Keys** in the left sidebar menu. <Frame> <img alt="TimeZest admin panel showing API Keys menu option" /> </Frame> Click the **+ New API Key** button in the top right corner. </Step> <Step title="Create a new API Key"> Configure the new API key with the following settings: | Field | Value | | - | - | | Name | `neoagent` (or any descriptive name) | | Permissions | **Read and write** | <Frame> <img alt="TimeZest Create new API Key form" /> </Frame> Click **Save** to create the API key. <Warning> Copy the API key immediately after creation. TimeZest will only display the full key once. If you lose it, you'll need to create a new one. </Warning> </Step> <Step title="Add the API Key to Neo Agent"> Navigate to the [Neo Agent Dashboard](https://dashboard.neoagent.io/integrations) and select the **TIMEZEST** tab. <Frame> <img alt="Neo Agent TimeZest integration page" /> </Frame> 1. Paste your TimeZest API key into the **API Key** field 2. Click **Save API Key** <Check> Neo Agent will verify the API key by connecting to TimeZest. If successful, the integration is complete and ready to use. </Check> </Step> </Steps> ## What Neo Can Do With TimeZest connected, Neo Agent can automate appointment scheduling within your workflows: <AccordionGroup> <Accordion title="Create Scheduling Requests"> * Generate scheduling links for end users to book appointments * Associate scheduling requests with PSA tickets, contacts, and companies * Select specific technicians or teams for appointments * Choose from your configured appointment types </Accordion> <Accordion title="Manage Resources"> * Access your list of available technicians/agents * View team configurations * Identify appropriate resources for scheduling </Accordion> </AccordionGroup> ## Use Cases TimeZest integration enables powerful scheduling automation scenarios: <CardGroup> <Card title="Ticket-Based Scheduling" icon="ticket"> Automatically send scheduling links when tickets require on-site or remote appointments. </Card> <Card title="Self-Service Booking" icon="calendar"> Include scheduling links in ticket responses so end users can book at their convenience. </Card> </CardGroup> ## External Resources <CardGroup> <Card title="TimeZest API Documentation" icon="link" href="https://developer.timezest.com"> Official TimeZest API reference and documentation. </Card> <Card title="TimeZest Help Center" icon="headset" href="https://help.timezest.com"> TimeZest support articles and guides. </Card> </CardGroup> # Connecting UniFi to Neo Source: https://docs.neoagent.io/integrations/unifi/connecting-to-neo Choose a UniFi connection type, save its credentials, and set each agent's access Save one UniFi connection at the MSP level, then enable access per agent. Choose credentials for the API your controller exposes. ## Which setup applies to you | Your controller | What to enter in Neo | | - | - | | **UniFi Site Manager** at unifi.ui.com | Select the Site Manager connection type and enter its **API Key** (step 1). | | **UniFi OS Server or console by URL** with the Network Integration API | Select the UniFi OS URL connection type. Enter **Controller URL** and a console-created **API Key** (step 1b). Use it for a UniFi OS Server adopted into Site Manager when Ubiquiti's Connector refuses that server on its firmware version (see Troubleshooting). | | **Self-hosted Network Server** using the legacy session API | Select the self-hosted connection type. Enter **Controller URL**, **Username** and **Password** for a local controller admin (step 1c). | The legacy login was verified in a lab running Network 10.6.101. That lab did not expose API-key creation; this does not establish a limit for every self-hosted deployment. HostiFi compatibility is unverified. Confirm the API your deployment exposes before choosing a connection type. ## 1. Create an API key in UniFi Site Manager <Steps> <Step title="Sign in to unifi.ui.com"> Use the UI account that manages your customers' consoles. The key sees exactly the consoles that account can manage — for an MSP that is usually the organization owner account. </Step> <Step title="Create the key"> Open **Settings → API Keys** and click **Create New API Key**. <Tip> Copy the key somewhere safe once it's generated — UniFi shows it only once. </Tip> </Step> </Steps> ## 1b. Or: create an API key in your UniFi OS console <Steps> <Step title="Sign in to the controller"> Open your UniFi OS Server or console in the browser. This connection uses its Network Integration API at `/proxy/network/integration/v1/`. A controller URL alone does not establish that this API is available. </Step> <Step title="Create the key"> Open **Settings → Control Plane → Integrations** and click **Create API Key**. Copy it once it's generated — it is shown only once. <Tip> The key inherits the permissions of the admin who creates it, so create it from an account that can see every customer site you want Neo to work on. </Tip> </Step> </Steps> A Site Manager key and a console-created key serve different APIs. Use the console-created key for a direct connection. ## 1c. Or: use a local controller admin Create a dedicated local admin on the self-hosted Network Server, with access only to the sites Neo needs. Enter that account's username and password in Neo. This login cannot answer an MFA challenge; use a dedicated account compatible with password-only login, subject to your security policy. Neo logs in through `/api/login` and uses the returned session cookie for the legacy API. You do not enter a cookie or an API key. Both URL connection types reach one controller's Network application. They do not provide the Site Manager fleet views or cloud ISP and SD-WAN endpoints. Available network operations depend on the controller's API and version; the legacy API does not have the same endpoints as the modern Integration API. ### Controller URL and TLS Use the controller root, including its port, such as `https://unifi.example.com:8443`. Omit browser paths such as `/manage`. The URL must be reachable from Neo's backend and present a certificate trusted by that backend, with a matching hostname. TLS certificate verification stays enabled for credential checks, legacy login and subsequent requests. Neo has no option to bypass verification. A private address reachable only from your workstation will not work without a network route from Neo. ## 2. Add the credentials in Neo <Steps> <Step title="Open Integrations"> Open [**Integrations**](https://dashboard.neoagent.io/integrations?open=unifi) and find **Ubiquiti UniFi** under **Networking**. </Step> <Step title="Save the credentials"> Select **Connection type** and enter the fields listed above. Click **Save**. Neo checks Site Manager access, direct Network site access, or the legacy login and site list before it stores the connection. </Step> </Steps> ## 3. Turn UniFi on per agent Each agent decides whether it uses UniFi and which areas it can touch. Open the agent, go to the Integrations section, and configure the UniFi block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Every area set to read only. The agent can look up consoles, sites, devices, clients, networks and firewall rules, but never makes changes. </Card> <Card title="Helpdesk" icon="headset"> Hotspot Vouchers and Clients read and write — issuing a voucher goes through on its own; authorizing a guest still waits on a technician. Devices, networks and firewall read only. </Card> <Card title="IT Admin" icon="user-shield"> Every writable area read and write, but every write waits on a technician. A cautious rollout tier. </Card> <Card title="Full Automation" icon="bolt"> Issuing vouchers goes through on its own. Device restarts, network or firewall changes, guest authorization and voucher deletion still always require technician approval — that never turns off. </Card> </CardGroup> ### Or set each area by hand These groups cover the APIs Neo exposes. The selected connection type and controller version determine which operations are available. Fleet inventory, cloud ISP metrics and SD-WAN require Site Manager; legacy controllers use their own device, client, network, firewall and voucher endpoints. | Area | Access levels you can pick | Notes | | - | - | - | | **Consoles & Sites** | Disabled, Read Only | Consoles, sites, fleet-wide device inventory, ISP health, SD-WAN. Read only by API design. | | **Devices** | Disabled, Read Only, Read and Write | Adopted and pending devices, statistics, restart, PoE power-cycle, adopt/unadopt. Writes always wait on a technician. | | **Clients** | Disabled, Read Only, Read and Write | Connected clients and guest authorization. Writes always wait on a technician. | | **Networks & WiFi** | Disabled, Read Only, Read and Write | Networks/VLANs, SSIDs, WANs, VPNs, RADIUS, switching, DNS policies. Writes always wait on a technician. | | **Firewall & ACLs** | Disabled, Read Only, Read and Write | Firewall policies and zones, ACL rules, traffic matching lists. Writes always wait on a technician. | | **Hotspot Vouchers** | Disabled, Read Only, Read and Write | Guest hotspot vouchers. Deleting always waits on a technician; issuing follows the group setting. | ## Safety controls * **Device restarts, adopt/unadopt, PoE power-cycles, every network or firewall change, guest authorization and voucher deletion always wait on a technician.** This holds regardless of the agent's automation level or the access profile you picked. * **Consoles & Sites is always read only.** Neo does not expose site creation or deletion. * **Only the Network application is reachable.** Protect (cameras) and other UniFi applications are not exposed to agents. * **Path safety.** Suspicious URL paths (anything containing `..`, for example) are rejected before they reach UniFi. * **Company mapping.** Neo matches UniFi site names to PSA companies during PSA metadata sync. With Site Manager, a site still named "Default" that is the only site on its console is matched by the console's name instead, when the console reports one; a "Default" site on a console with several sites keeps its own name. Review matches on **Organization Mapping**, especially after a change of connection type. Legacy requests use the site's `name` slug (for example `default`); modern direct requests use its Integration API UUID. These identifiers are not interchangeable. * **Rate limiting.** Neo paces calls at 100 requests per minute per Connector console, or in a shared bucket for calls without a Connector console ID. ## If UniFi refuses Neo's requests | What the error says | Cause | Fix | | - | - | - | | `401 Unauthorized` with API-key authentication | The key may be invalid, revoked or lack access | Check the selected connection type and the key's source and permissions | | Legacy login rejected or MFA required | The local account's credentials or login requirements do not match this connection | Check the dedicated local admin and its site access; Neo cannot answer MFA challenges | | Certificate verification or connection failure | Neo cannot reach or trust the Controller URL | Check DNS, routing, port and the certificate's trust chain and hostname; keep TLS verification enabled | | Save fails with `404` on a Controller URL | The URL or selected API does not match the deployment | Use the controller root and confirm which API it exposes; do not assume a hosting provider supports either API | | `403 forbidden: host not found` | The console is not one this key's account can manage | Give the UI account admin access to that console in Site Manager, or create the key from an account that has it | | `408 DeviceTimeout` on a console path | The console is offline, or it is a self-hosted UniFi Network Server — Ubiquiti's Connector only proxies to UniFi OS consoles | Cloud-level data (consoles, sites, devices, ISP health) still works for that server; per-site detail needs a UniFi OS console | | `400 ... console firmware version ... is below minimum required version v5.0.3` on a console path | The Connector refused the console on the firmware version Site Manager reports. A UniFi OS Server can report a placeholder version (ending in `+mock`) while it runs 5.x; on console hardware, the firmware is older than 5.0.3 | For a UniFi OS Server, connect it by URL instead (step 1b); this replaces the Site Manager connection. For console hardware, update the console | | `404 device_offline` on a console path | The console is known to Site Manager but not connected to the cloud right now | Bring the console back online; cloud-level data still works meanwhile | | `404` on a console path | The console's firmware or Network application is older than the endpoint (the Connector needs UniFi OS 5.0.3 or newer) | Update the console | Until it is fixed, agents that use UniFi report the failure on the ticket they were working. The rest of Neo keeps running. ## Disconnecting Ubiquiti UniFi <Steps> <Step title="Open the integration"> In the Neo Dashboard, open **Integrations** and select the Ubiquiti UniFi card. </Step> <Step title="Disconnect"> Click **Disconnect** and confirm. Neo removes the credentials from Key Vault. </Step> </Steps> Your Organization Mapping is kept, including any mapping you set by hand, so reconnecting later picks up where you left off. Agents that use Ubiquiti UniFi stop working until you connect it again. ## Security * Neo stores connection credentials in Azure Key Vault. A self-hosted login is exchanged for a session cookie, cached for 20 minutes per tenant, controller URL and admin account. The password itself is never cached. Changing the Controller URL or the admin retires the cached session. * All traffic goes over HTTPS. In the Site Manager setup calls go to `api.ui.com` and per-console calls are proxied by Ubiquiti's cloud Connector, so Neo never connects to a console directly. With a Controller URL, Neo connects to that controller over HTTPS with TLS certificate verification enabled. `http://` URLs are refused. * Write access to UniFi is opt in per area, per agent. Once your credentials are saved and an agent has permissions, the UniFi tool is added to that agent automatically. # Overview Source: https://docs.neoagent.io/integrations/unifi/overview What the Ubiquiti UniFi integration brings to your Neo Agent setup UniFi is the network hardware most MSPs run at their customers' sites — gateways, switches and access points. When you connect UniFi to Neo, your agents can see your sites, check which devices and clients are online, and — with a technician's sign-off — restart a device or change a network without you opening the UniFi console. How much they see depends on how you connect. Through UniFi Site Manager at unifi.ui.com, agents reach every console and site your account manages. Through a controller's own URL, they reach that one controller. <Info> You connect UniFi once per MSP and every agent you enable can use it, with permissions you control per agent. Pick one of three connection types: a Site Manager API key, a UniFi OS console's own API key with its URL, or a self-hosted Network Server's URL with a local admin's username and password. [Connecting UniFi to Neo](/integrations/unifi/connecting-to-neo) says which one your controller needs. </Info> ## What Neo can do with UniFi <CardGroup> <Card title="Consoles & Sites" icon="server"> List the consoles and sites your account manages, every device across the fleet with its online state, and ISP latency, packet-loss and uptime metrics. The fleet view and the ISP metrics come from the Site Manager cloud; a controller connection lists that controller's own sites. </Card> <Card title="Devices" icon="wifi"> Read a site's access points, switches and gateways with live statistics; restart a device, power-cycle a PoE port or adopt hardware — always with technician approval. </Card> <Card title="Clients" icon="laptop"> Find the client behind a connectivity complaint — IP, MAC, uplink device, signal, uptime — and, with technician approval, authorize or revoke guest access. </Card> <Card title="Networks, WiFi & Firewall" icon="shield-halved"> Read and, with technician approval, change networks and VLANs, SSIDs, WANs, VPNs, DNS policies, firewall policies and ACL rules. </Card> </CardGroup> Hotspot Vouchers is also available — generating a guest WiFi voucher is the routine helpdesk write. ## Why connect UniFi * **Check the network before touching the ticket.** A "WiFi is slow" or "internet is down" ticket gets answered from the gateway's WAN status, the AP's client count and the client's signal — not from a round trip to the console. * **The whole fleet in one place.** With Site Manager, the cloud view spans every customer console your account can see, so an agent can tell which site a device belongs to without knowing the console's address. A controller connection trades that cross-console view for direct access to one controller. * **Device restarts, any network or firewall change, and guest authorization always require a technician's sign-off**, no matter how automated the rest of the agent is — this is by design. The [UniFi API tool](/agents/tools/networking/unifi-api#safety-controls) reference lists every action that always needs approval. ## How agents reach UniFi When you enable any UniFi permission group on an agent, Neo automatically adds the UniFi tool to that agent's toolbox. Per-console detail (clients, SSIDs, firewall) is reached through Ubiquiti's cloud Connector, so there is no VPN, port forward or per-site address to configure — UniFi OS console hardware (Cloud Gateways, Dream Machines, Cloud Keys) on firmware 5.0.3 or newer that is adopted into Site Manager just works. A UniFi Network Application that you or a provider such as HostiFi runs is different. Adopted into Site Manager it appears in the fleet view, but the Connector cannot reach it, so per-site detail (clients, SSIDs, firewall) needs a direct connection. A UniFi OS Server can also be refused by the Connector on the firmware version it reports to Site Manager, and then needs the same direct connection. Connect such a deployment by its own URL: a UniFi OS Server or console takes an API key created in that console, and a classic Network Server takes a local admin's username and password. Choosing a direct connection trades the cross-console fleet view for that per-site detail. See [Connecting UniFi to Neo](/integrations/unifi/connecting-to-neo). ## Where to go next <Card title="Connecting UniFi to Neo" icon="plug" href="/integrations/unifi/connecting-to-neo"> Setup steps for the API key, per-agent access levels, and the safety controls that stay in place. </Card> # Connecting Uniview to Neo Source: https://docs.neoagent.io/integrations/uniview/connecting-to-neo Save a Uniview API credential in Neo and turn it on for the agents that handle backup alerts You connect Uniview once at the MSP level, then turn it on per agent. ## 1. Create an API credential <Steps> <Step title="Open API Access"> Sign in to the Uniview portal, click the settings icon, and open **API Access**. </Step> <Step title="Create the credential"> Click **+ New**, give the credential a name such as "Neo", and click **Save**. Copy the **Client ID** and the **Client Secret**. The secret is shown only once. </Step> </Steps> ## 2. Add the credential in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the Uniview Backup card, under Backup & Recovery. </Step> <Step title="Save the credential"> Paste the Client ID and the Client Secret and click **Save**. Neo checks them against Uniview before saving, so a wrong or deleted credential is rejected straight away. The **Organization Mapping** tab fills separately after the save, and again on each nightly PSA sync. </Step> </Steps> ## 3. Turn Uniview on per agent Open the agent, go to the Integrations section, and configure the Uniview block. The **Read Only** profile turns on every area. To leave an area out, set it to Disabled: | Area | Access levels you can pick | Notes | | - | - | - | | **Customers** | Disabled, Read Only | The clients in your portal. | | **Backups** | Disabled, Read Only | Endpoints, appliance-protected assets, backup jobs and appliances. This is the area a backup-failure agent needs. | | **BackupIQ Alerts** | Disabled, Read Only | BackupIQ alerts. | | **Microsoft 365 Backup** | Disabled, Read Only | Spanning tenants and users, and Entra ID tenants. | ## Example: close backup alerts that have recovered Give an agent that runs on your backup-alert tickets the Uniview **Read Only** profile and instructions like these: > For a backup-failure ticket, look up the device in Uniview. If it has a successful backup later than the alert, add a note with the backup time and close the ticket. If the device was offline, note when it was last online and leave the ticket open. Otherwise, assign the ticket to the backup queue with what you found. See [Uniview API](/agents/tools/backup/uniview-api) for what the agent can read. # Overview Source: https://docs.neoagent.io/integrations/uniview/overview What the Uniview Backup integration brings to your Neo Agent setup Uniview is the backup portal at backup.net for Unitrends appliances, Kaseya endpoint backup and Spanning Microsoft 365 backup. Its most common ticket is a backup-failure alert. Connect Uniview to Neo and your agents can check each alert against the portal: close the ticket when the device has backed up since, and tell a technician when it has not, and why. <Info> Uniview uses one API credential per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with Uniview <CardGroup> <Card title="Backups" icon="hard-drive"> Find a device by name and read its last successful backup, its online status and its recent backup jobs. Check appliances for free space and online status. </Card> <Card title="BackupIQ Alerts" icon="bell"> List BackupIQ alerts for a client or a device, with severity and whether they were dismissed. </Card> <Card title="Microsoft 365 Backup" icon="cloud"> Read the last Microsoft 365 backup of a tenant, or of one user's mail, drive, contacts and calendar. </Card> <Card title="Customers" icon="building"> Find the client in your portal by name, so an agent can list its devices. </Card> </CardGroup> Neo only reads from Uniview. It cannot start, retry or dismiss a backup. ## Your clients are mapped automatically Neo matches your Uniview customers to the companies in your PSA and keeps the mapping on the Uniview card's **Organization Mapping** tab, refreshed on each PSA metadata sync. Matching starts with the Microsoft 365 tenant: a customer whose Microsoft 365 backup protects the same tenant Neo has on a company is an exact match. Then comes the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. **A tenant match, a name match, or one you confirm, is handed straight to your agents**, so they look up a device within the right customer. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect Uniview" icon="plug" href="/integrations/uniview/connecting-to-neo"> Save an API credential in Neo and turn Uniview on for your agents. </Card> # Connecting WatchGuard to Neo Source: https://docs.neoagent.io/integrations/watchguard/connecting-to-neo Enable API access in WatchGuard Cloud and save the credential in Neo You connect WatchGuard once at the MSP level, with the API credential of your own WatchGuard Cloud account: the region, your account ID, an Access ID with its password, and the API key. ## 1. Enable API access in WatchGuard Cloud <Steps> <Step title="Open your own account"> Sign in to WatchGuard Cloud with the Owner or Administrator role. As a Service Provider, switch to **Subscriber view** for your own account, not a customer's. </Step> <Step title="Note your account ID and region"> Open **Administration** > **My Account**. The **Details** section shows your account ID (it starts with `ACC-` or `WGC-`) and your data zone. </Step> <Step title="Enable API access"> Open **Administration** > **Managed Access** and click **Enable API Access**. Set a read-write password and a read-only password (at least 12 characters, with a lowercase and an uppercase letter, a number and a symbol), accept the license agreement and click **Save**. </Step> <Step title="Copy the credential"> Copy the **Access ID (Read-write)**, the read-write password you set, and the **API Key**. The **API URL** shows your region: `usa`, `deu` or `jpn`. </Step> </Steps> <Note> The read-only Access ID also connects, but it cannot make changes in WatchGuard Cloud. </Note> <Warning> Do not change the API passwords or disable API access in WatchGuard Cloud after you connect. Neo loses access until you save the new values here. </Warning> ## 2. Add the credential in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **WatchGuard**](https://dashboard.neoagent.io/integrations?open=watchguard), under Networking. </Step> <Step title="Save the credential"> Pick the region, then paste your account ID, the Access ID, its password and the API key, and click **Save settings**. Neo checks them against WatchGuard Cloud before saving, so a wrong value is rejected straight away. </Step> </Steps> ## 3. Turn WatchGuard on per agent <Steps> <Step title="Open the agent's integrations"> Open the agent in the Neo Dashboard and go to its **Integrations** tab. </Step> <Step title="Pick an access profile"> Under **WatchGuard**, pick an access profile, or set each permission group by hand. | Profile | What it does | | - | - | | **Read Only** | Checks Fireboxes, access points, endpoints, incidents and licences; changes nothing | | **Helpdesk** | Also makes Firebox, endpoint, incident, account and AuthPoint changes, each with technician approval | | **IT Admin** | Isolates and scans endpoints and contains threats on its own; exceptions, Firebox configuration and account changes, and the changes Full Automation also asks about, ask a technician | | **Full Automation** | Every supported write without approval, except FireCloud allow exceptions, policy, VPN, certificate and template changes, disabling global exceptions, deployments, protection uninstalls, moving devices to another security configuration, undoing a containment, operator changes, deallocations, purchase orders and contract suspends or cancels | | Group | Covers | | - | - | | Firebox Devices and Reports | Status, offline since, uptime and reports of Fireboxes and access points (read-only) | | Firebox Exceptions | Blocked sites, WebBlocker, botnet, file, IPS, geolocation and HTTPS exceptions | | Firebox Configuration | Firewall policies, BOVPN tunnels, certificates, templates and deployments | | Endpoint Security | Devices, protection, security events; isolate, reboot and scan | | ThreatSync and NDR | Incidents, actions and comments; NDR assets and Smart Alerts | | Accounts and Licensing | Managed accounts, operators, licences, allocations and contracts | | AuthPoint Authentication | Test push and its result, the authentication policy for a user | With the read-only Access ID saved, every write fails in WatchGuard Cloud whatever the profile says. See [WatchGuard API](/agents/tools/networking/watchguard-api). </Step> <Step title="Tell the agent what to do"> Add an instruction, for example: "When WatchGuard Cloud reports a Firebox offline, check the Firebox in WatchGuard, and write in an internal note whether it is back online and since when it was down." </Step> </Steps> # Overview Source: https://docs.neoagent.io/integrations/watchguard/overview What the WatchGuard integration brings to your Neo Agent setup WatchGuard Cloud manages your clients' Firebox firewalls, access points and WatchGuard endpoint security. Connect WatchGuard to Neo once, at the MSP level, with the API credential of your own WatchGuard Cloud account. As a WatchGuard Service Provider, your credential reaches every account you manage in WatchGuard Cloud. A Subscriber account's credential reaches that account only. Fireboxes you manage locally show in WatchGuard Cloud once they are registered there, with their status. Their configuration stays on the Firebox. ## What Neo can do with WatchGuard * Check a Firebox or access point after a WatchGuard Cloud offline alert: whether it is online now, since when it was down, and its uptime * Read Firebox reports, VPN tunnels, firewall policies and exceptions for a firewall, VPN or blocked-site ticket * Unblock or block a site and deploy the change to the named Firebox * Find a computer in WatchGuard Endpoint Security, read its protection and security events, and isolate or scan it * Read a ThreatSync incident and act on it * Read licences and contracts, and send an AuthPoint test push Every deployment to a Firebox, FireCloud allow exceptions, policy and VPN changes and protection uninstalls always ask a technician. AuthPoint token and user changes stay in the AuthPoint console. See [WatchGuard API](/agents/tools/networking/watchguard-api) for the permission groups and access profiles. ## Your WatchGuard accounts are mapped to clients Neo matches each WatchGuard Cloud account you manage to a client in your PSA and keeps the mapping on the WatchGuard card's **Organization Mapping** tab, refreshed on each PSA metadata sync. With the mapping, an agent works in the right client's WatchGuard account by its account ID. Neo lists the accounts you manage, delegated accounts included. A tier-n Service Provider's own clients are listed too, at every tier. A Subscriber credential maps its own account. An account that does not give you access stays unmapped. Leave it unmapped until WatchGuard Cloud gives you access to it: Neo cannot work in an account your credential cannot reach. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Last comes an AI match for the long tail. A name match, or one you confirm, is handed straight to your agents. An AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right client by hand. A mapping you set by hand survives every later sync. ## Next steps <Card title="Connect WatchGuard" icon="plug" href="/integrations/watchguard/connecting-to-neo"> Enable API access in WatchGuard Cloud and save the credential in Neo. </Card> # Connecting Wizer to Neo Source: https://docs.neoagent.io/integrations/wizer/connecting-to-neo Save a Wizer API key in Neo, and decide what each agent can do You connect Wizer once at the MSP level, then turn it on per agent. ## 1. Copy your API key <Steps> <Step title="Sign in to your partner account"> Sign in to the Wizer admin panel with your partner account, so the key reaches every client company. </Step> <Step title="Copy the key"> Open **Settings**, then **Integration**, and copy the API key. Generate one if none exists. </Step> </Steps> ## 2. Add the key in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open **Integrations** and find the Wizer card, under Security. </Step> <Step title="Save the key"> Paste the key and click **Save**. Neo checks it against Wizer's Partner Portal before saving, so a wrong key, or one that is not your partner account's, is rejected straight away. The **Organization Mapping** tab fills separately after the save, and again on each nightly PSA sync. </Step> </Steps> ## 3. Turn Wizer on per agent Open the agent, go to the Integrations section, and configure the Wizer block. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Read users, client companies and training progress. Nothing is changed. </Card> <Card title="Helpdesk" icon="headset"> Add, disable and regroup users, and start or share training, with technician approval. </Card> <Card title="IT Admin" icon="user-gear"> Add, disable and regroup users, and start or share training, on its own. </Card> <Card title="Full Automation" icon="bolt"> Manage users and training assignments without approval. </Card> </CardGroup> ### Or set each area by hand | Area | Access levels you can pick | Notes | | - | - | - | | **Users** | Disabled, Read Only, Read and Write | Users, groups and departments of a client. Write adds, disables, renames and regroups users. | | **Training Assignments** | Disabled, Read Only, Read and Write | Start or share a course for a client. Read checks a batch operation. | | **Reports** | Disabled, Read Only | Training, policy, video and phishing progress. | | **Customers** | Disabled, Read Only | The client companies under your partner account. | ## Safety controls * **You decide what waits on a technician.** Each area has its own approval setting. Helpdesk asks on every user change and every course start; IT Admin and Full Automation ask on nothing. * **Leavers are disabled, never deleted.** Disabling keeps the user's training record, which your clients may need as compliance evidence. Neo does not delete Wizer users. * **A batch names its clients.** Neo refuses a course start or share for "all customers" at once. The agent names each client company. * **Only what the job needs.** Neo sends only user, training, report and customer-list requests. Login links, inviting or disabling a client company, and launching phishing campaigns are unreachable. * **Path safety.** A URL path with a `..` segment is rejected before it reaches Wizer. ## If Wizer refuses Neo's requests | What comes back | Cause | Fix | | - | - | - | | `401` | The key was regenerated or removed, or it is not your partner account's key | Copy the current key from your Wizer partner account and save it in Neo | | `403` | The key may not use that area, for example a direct (non-partner) account on a partner endpoint | Use your partner account's key, or ask Wizer support to enable the endpoint | | `429` | Rate limited | Wait. Neo retries a read a few times first; if the limit holds, the agent stops calling Wizer for that run and reports the call it could not make | | A failed **Wizer Company Mapping** row with a `401` or `403` | The key is refused, or it is not a partner key | Fix the key as above. The next PSA sync rebuilds the mapping | ## Disconnecting Wizer In the Neo Dashboard, open **Integrations**, select the Wizer card, click **Disconnect** and confirm. Neo removes the key from Key Vault. Agents that use Wizer stop working until you connect it again. Your Organization Mapping is kept, including any mapping you set by hand. ## Security * The key lives in Azure Key Vault. It is never stored in plaintext. * All traffic goes over HTTPS to `gateway.wizer-training.com`. * Write access is opt in per agent and per area. # Overview Source: https://docs.neoagent.io/integrations/wizer/overview What the Wizer security awareness training integration brings to your Neo Agent setup Wizer runs security awareness training for your clients: short courses, policies, monthly videos and phishing exercises. The work it causes for an MSP is routine: add a new hire to their company's training, take a leaver out, start this year's course, and answer "who has not finished yet". Connect Wizer to Neo and your agents do that from the ticket. Nobody opens the Wizer admin panel. <Info> Wizer uses one API key per MSP. Connect it once and every agent you enable can use it, with permissions you control per agent. </Info> ## What Neo can do with Wizer <CardGroup> <Card title="Users" icon="users"> Add users to a client's training, disable a leaver, fix a name, and move a user into the group or department a course is assigned to. </Card> <Card title="Training Assignments" icon="graduation-cap"> Start a course for a client, or share your own custom course with them, and check the result of a batch start. </Card> <Card title="Reports" icon="chart-line"> Read training, policy, video and phishing progress for a client and for each user: who started, who finished, who is overdue. </Card> <Card title="Customers" icon="building"> List the client companies under your Wizer partner account. </Card> </CardGroup> ## Your clients are mapped automatically Neo matches your Wizer customer companies to the companies in your PSA and keeps the mapping on the Wizer card's **Organization Mapping** tab, refreshed on each PSA metadata sync. It reads every customer under your partner account. Matching starts with the name: exact, then after stripping a legal-form suffix (Ltd, Inc, LLC). Then the domain of the customer's admin email address, against the website on each PSA company, when no other customer has the same domain. Last comes an AI match for the long tail. **A name match, or one you confirm, is handed straight to your agents**, so they know the client's Wizer company without looking it up. A domain match or an AI match is not handed to your agents automatically. It shows on the Organization Mapping tab, where you can confirm or correct it. Anything Neo could not match stays unmapped and visible on the same tab, where you can set the right company by hand. A mapping you set by hand survives every later sync. <Note> Connect the key of your Wizer partner account. Agents find each client's company through Wizer's Partner Portal customer list, which Wizer documents as a partner feature. </Note> ## Next steps <Card title="Connect Wizer" icon="plug" href="/integrations/wizer/connecting-to-neo"> Save an API key in Neo and choose what each agent can do. </Card> # Connecting Zabbix to Neo Source: https://docs.neoagent.io/integrations/zabbix/connecting-to-neo Save your Zabbix address and an API token in Neo ## Before you start * Neo needs **Zabbix 6.4 or later**, the first release that accepts an API token in the `Authorization` header. * Neo reaches your Zabbix frontend over the internet. It must answer on **HTTPS** with a certificate from a public certificate authority, at a public address. If a firewall or reverse proxy limits who can reach it, allow [Neo's addresses](/integrations/ip-whitelisting) to reach `api_jsonrpc.php`. ### If Zabbix is only on your internal network Publish only the API, not the whole frontend. Put a reverse proxy at your network edge that: * answers on a public name over HTTPS, with a certificate from a public certificate authority; * forwards only `/api_jsonrpc.php` (under the frontend's path, such as `/zabbix/api_jsonrpc.php`) to your Zabbix frontend, and refuses every other path; * accepts connections only from [Neo's addresses](/integrations/ip-whitelisting); * passes the `Authorization` header through to Zabbix. Save the proxy's public address in Neo. nginx passes the `Authorization` header on by default. Apache in front of PHP-FPM can drop it: add this line to the Zabbix site. ```apache theme={null} SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 ``` ## 1. Prepare a Zabbix user and token <Steps> <Step title="Create a user for Neo"> In Zabbix, open **Users → Users** and create a user for Neo. Its **role** decides which API methods Neo may call: on the role, keep **Access to API** on. Its **user groups** decide which host groups Neo can read or change, so give the groups read access to the clients' host groups, or read-write where you want agents to make changes. A **User** role reads hosts and problems and acknowledges problems. Maintenance and configuration changes need an **Admin** role, and users, roles and global settings need **Super admin**. </Step> <Step title="Create the API token"> Open **Users → API tokens**, click **Create API token**, choose Neo's user, and set an expiry date if your policy needs one. Copy the token: Zabbix shows it once. </Step> </Steps> <Warning> If the token expires, or you disable the token or its user, Neo loses access until you save a new token here. </Warning> ## 2. Add the token in Neo <Steps> <Step title="Open Integrations"> In the Neo Dashboard, open [**Integrations** → **Zabbix**](https://dashboard.neoagent.io/integrations?open=zabbix), under Networking. </Step> <Step title="Save the address and token"> Enter the address you open Zabbix at, including a path such as `/zabbix` if it has one (for example `https://monitor.example.com/zabbix`), and the API token, then click **Save settings**. Neo reads your Zabbix version and checks the token before saving, so a wrong address, an older Zabbix or a refused token is rejected straight away. </Step> </Steps> ## 3. Turn Zabbix on per agent Open the agent, go to the Integrations section, and configure the Zabbix block. Agents see only what Neo's Zabbix user can see. ### Pick an access profile <CardGroup> <Card title="Read Only" icon="magnifying-glass"> Read hosts, problems, latest data, history and configuration. Nothing is changed. </Card> <Card title="Helpdesk" icon="headset"> Acknowledge, comment on and close problems without approval. Maintenance and running a script wait on a technician. Everything else is read only. </Card> <Card title="IT Admin" icon="user-gear"> Problems, hosts, maintenance, items, triggers and templates change without approval, except deleting a host. Scripts, actions and media types, users and access, and administration wait on a technician. </Card> <Card title="Full Automation" icon="bolt"> Every change runs without approval, except the [changes that always ask a technician](#changes-that-always-ask-a-technician). </Card> </CardGroup> ### Or set each area by hand | Area | Notes | | - | - | | **Problems and Events** | Current problems, events and sent alerts. Write acknowledges, comments on, closes, suppresses or changes the severity of a problem. | | **Hosts** | Hosts, host groups and interfaces, with availability, inventory and tags. Deleting a host always waits on a technician. | | **History and Trends** | Collected values and hourly trends. Write sends values to trapper items. | | **Maintenance** | Maintenance periods. | | **Scripts** | Global scripts. Write runs a script on a host, or creates and changes scripts. | | **Items, Triggers and Discovery** | Items, triggers, graphs, web scenarios, low-level discovery, host macros, value maps and "check now". | | **Templates** | Templates, template groups and template dashboards. | | **Actions and Media Types** | Actions, media types and event correlation. | | **Dashboards, Maps and Reports** | Dashboards, network maps, images and scheduled reports. | | **Services and SLAs** | Business services and SLAs. | | **Network Discovery and Proxies** | Network discovery, proxies and active agent autoregistration. | | **Users and Access** | Users, user groups, roles, API tokens, LDAP and SAML, MFA and authentication. The changes listed under [Changes that always ask a technician](#changes-that-always-ask-a-technician) always wait on a technician, and Neo never creates an API token. | | **Administration** | Global settings, housekeeping, modules, regular expressions, connectors, global macros, the audit log and HA nodes. | Each area can be Disabled, Read Only or Read/Write, and has its own technician approval setting. ### Changes that always ask a technician These wait on a technician under every profile, whatever the area's own approval setting: * Changing authentication settings (HTTP, LDAP and SAML sign-in, the default sign-in method, the password policy). * Creating, changing, testing or deleting an LDAP or SAML user directory. * Creating, changing or deleting an MFA method. * Creating, changing or deleting a user role or a user group. * Creating, deleting or provisioning a user from LDAP, or changing a user's role, user groups or user directory. Disabling a user means moving them to a disabled user group, so it asks too. * Resetting a user's MFA. * Changing or deleting an API token. * Deleting a host, which removes its collected history. * Any change that stores a credential: a password, a secret macro, a credential header or parameter, the user name and password in a URL, or an HTTP agent's request body. ## Troubleshooting | Error when you save | What to check | | - | - | | No Zabbix API answered | The address, including a path such as `/zabbix`. Open `<address>/api_jsonrpc.php` in a browser: Zabbix answers it. | | This Zabbix runs version ... | Upgrade to Zabbix 6.4 or later. | | Zabbix rejected the API token | The token, its expiry, and that its user is enabled and its role has API access. If all are right, a web server in front of Zabbix may drop the `Authorization` header: see [If Zabbix is only on your internal network](#if-zabbix-is-only-on-your-internal-network). | | A web server in front of Zabbix refused Neo | Allow Neo's addresses to reach `api_jsonrpc.php`. | | ... is a private or reserved address | Use the public address of your Zabbix frontend. | # Overview Source: https://docs.neoagent.io/integrations/zabbix/overview What the Zabbix monitoring integration brings to your Neo Agent setup Zabbix monitors your clients' servers, network devices and services: it collects values such as CPU, disk and ping, and raises a problem when a trigger fires. Connect your Zabbix server to Neo once, at the MSP level, with its address and an API token. ## What Neo can do with Zabbix <CardGroup> <Card title="The host behind a ticket" icon="server"> Find the host by name, IP address or the client's host group. Read whether Zabbix can reach it, its open problems, and which templates monitor it. </Card> <Card title="Is it really down?" icon="heart-pulse"> Tell a host that is down from a stopped Zabbix agent or an offline proxy, from ping, agent availability and the proxy's last contact. </Card> <Card title="Latest data and history" icon="chart-line"> Read the latest CPU, memory, disk or any other value, and its history or hourly trend, to see when a problem started. </Card> <Card title="Alert tickets, linked both ways" icon="link"> When a Zabbix alert email opens a ticket, Neo finds the problem behind it, notes its state on the ticket, and acknowledges the problem with the ticket number. Recovery emails, and the update emails its own acknowledgement causes, go to the original ticket. </Card> <Card title="Acknowledge and maintenance" icon="bell-slash"> Acknowledge, comment on and close a problem with the ticket number, put a host in maintenance for planned work, and run a script you defined in Zabbix. </Card> </CardGroup> With the access you choose, Neo can also change hosts, templates, items, triggers, macros, users and other Zabbix settings. Some changes always ask a technician first, under every access profile, such as changing authentication, a role or a user group, deleting a host, or storing a credential: [the full list](/integrations/zabbix/connecting-to-neo#changes-that-always-ask-a-technician). ## Alert tickets Most MSPs have Zabbix email its alerts into the PSA, so each alert opens a ticket that knows nothing more about the problem. The **Zabbix Alert Ticket Handler** template, under **Monitoring & Alerts** in the template catalog, runs on each new alert ticket: * It finds the Zabbix problem behind the ticket: by the event id when the email carries one (Zabbix's default email has `Original problem ID`), else by the trigger id, else by host, problem name and start time. * It adds an internal note with the problem's state: severity, start time, whether it is still a problem, and the latest values. * It acknowledges the problem in Zabbix with the ticket number, so a technician in Zabbix sees which ticket owns it. * A recovery email that opens its own ticket, or the update email that Neo's acknowledgement causes, is noted on the original ticket and merged into it. Zabbix's default update email for a comment a technician makes in Zabbix carries no event id or host, so that ticket only gets a note that no original matched. When it cannot match exactly one problem, it adds a note that says what it searched and changes nothing. Set the template's scope filter to the board or source your alert tickets land on. If your Zabbix action also emails problem updates to the PSA, the acknowledgement opens an "Updated problem" ticket; the agent merges it and never acknowledges from it, so no loop starts. ## Your clients in Zabbix Zabbix has no client object of its own: you group hosts by client in host groups (such as `Customers/Acme`) or with tags. Neo finds a client's hosts by searching host group names and tags, so it works with the naming you already use. There is no Organization Mapping tab for Zabbix. ## What Neo never does * Create an API token or read a token's secret, or start a Zabbix session. * Export or import a Zabbix configuration. An export can carry passwords Neo cannot remove, and an import makes many changes at once that Neo cannot check one by one. * Clear an item's history. Neo also removes the fields Zabbix keeps credentials in (passwords, SNMP communities and passphrases, pre-shared keys, credential headers, HTTP request bodies, and the user name and password in a URL) from every Zabbix answer before an agent sees it. Text you typed elsewhere, such as a script's command or a text macro, reaches the agent as written, so keep secrets in secret macros. ## Next steps <Card title="Connect Zabbix" icon="plug" href="/integrations/zabbix/connecting-to-neo"> Create an API token in Zabbix and save it in Neo with your Zabbix address. </Card> # Performance & Cost Source: https://docs.neoagent.io/product/analytics See what Neo delivered — time saved, tickets covered, resolution rates — and exactly where your credits and end-user charges go, per workflow, agent, and chat. The **Performance & Cost** page is where you measure Neo's impact and track every credit and charge. It has two tabs: * **Performance** — what Neo did for you: time saved, tickets covered, and how often work finished without a human. * **Cost Analysis** — where your spend goes, broken down by workflow, agent, and chat. <Info> Deciding what to automate *first*? [Neo Insights](/product/insights) projects the hours and money you could save — for your whole desk, a single end-client, or specific months — before you build anything. </Info> Open [**Performance & Cost**](https://dashboard.neoagent.io/analytics) from the main menu. ## Performance The [**Performance** tab](https://dashboard.neoagent.io/analytics?tab=performance) answers "what did Neo accomplish?" Use the **Agents / Workflows / All** toggle to scope every metric, and the period selector (top right) to choose the window. Presets wider than your history are disabled — the header shows **Execution data since** the first run. At the top, three tiles set what Neo saved against what it cost: <Frame> <img alt="Performance tab: Time saved · estimated, Value of that time and Neo cost tiles, with the line comparing value and cost under them" /> </Frame> | Tile | What it means | | - | - | | **Time saved · estimated** | Technician hours Neo saved across the successful runs that recorded an estimate in the period, split into agents' estimates and workflows' fixed minutes | | **Value of that time** | Those hours times your [cost of technician time](#your-cost-of-technician-time), for example **312 h × \$60/h** | | **Neo cost** | What the period's credits cost you, at your [price per credit](/product/billing-and-credits#what-your-credits-cost) | Until an admin enters your own cost per hour, **Value of that time** uses the typical rate for your region, shows smaller, and is marked **typical US rate** (or your region). Click the mark to enter your own rate. You may pay Neo in one currency and enter your cost per hour in another, for example US dollars against pounds. **Neo cost** is then converted into the currency of your hourly cost at the European Central Bank's reference rate of the last business day, and the line under it gives the billed figure: *from \$3,385 at the ECB rate of 2 Oct 2026*. Every other page keeps credits in your billing currency. Under the tiles, one line can compare the two: *Neo cost about £2,600 this month and did about £41,000 of technician work at your rate: more than 15× what it cost.* It shows only when all four hold: 1. An admin entered your own cost per hour. The typical rate never produces the line. 2. Neo knows your price per credit, and the cost is in the same currency as the value, converted at the ECB rate when needed. 3. The period has at least 100 runs that recorded time saved. 4. The multiple is above 5×. It is rounded down (to a whole number under 10×, to a multiple of 5 above), so it always understates. Time saved is an estimate, so its value is one too. It leaves out runs that paused, were cancelled or failed. A run in test mode records no time saved. A workflow counts fixed minutes for each action it runs, or the minutes you set for it under Time saved per run; an action that changed nothing counts none, except triage. An agent counts its own estimate of the manual time the run replaced. Time-saved reporting begins on 6 April 2026, so every figure on this tab, credits included, starts no earlier than that day and a longer period such as Last year shows the figures since then. Below the cards, the **Neo Impact** panel shows **ticket coverage** — the tickets Neo handled versus the tickets with PSA activity, summed over the periods of the Ticket Coverage Over Time chart, and the share handled by your agents, workflows, or Neo overall — next to **Goal fully met** (for agents) or **Success Rate** (for workflows). Goal fully met counts the runs the agent itself reported as having met its goal, including a run that paused for a technician's approval. The **Execution Volume** chart then shows one stacked bar per period: on Agents, the runs the agent reported as goal fully met, goal partially met, and the rest; on Workflows and All, successful and failed runs. The bar's height is the period's total. A line on the right axis gives the goal-met rate (Agents) or the success rate, on an axis that starts at the period's lowest rate rounded down to a multiple of five (never above 95%), so a small move is still readable. A period with no runs shows as zero rather than being skipped. The table of ticket categories below it shows, per category, the runs, the **Success** rate and, outside the Workflows tab, the **Goal met** rate, beside hours saved and credits. Its **Credits** count only runs that have a category, so they never exceed the Credits Used card and can be less: chat credits and runs without a category have no row. The table of automations below that shows each one's hours saved and **Credits** for the period, so the rows add up to the cards. In both tables, **Min Saved / Run** is the average estimate per run that recorded one: the hours saved divided by those runs. **Avg Run Time** is how long a run took, which is a different number from the time it saved. Every number on this tab counts only the agents you can view. Owners and admins see every agent, as does anyone given [every agent and workflow](/product/rbac#every-agent-and-workflow), and their totals also keep the history of agents you have since deleted; a user or viewer sees the agents they created or that were shared with them, so two people can see different totals. **Tickets received** is not per-agent and is not limited this way. The **Ticket Coverage Over Time** chart shows, per period, the tickets with PSA activity (**Total Tickets**) and how many of those Neo ran on (**Handled by Neo**). Handled is never higher than the total. Neo keeps PSA activity for the current and at least the previous calendar month, so this chart starts there even when you pick a longer period. Execution Volume reaches back to 6 April 2026. <Tip> For a single run's step-by-step detail — every action, input, and output — open [Executions](/product/executions). </Tip> ### Your cost of technician time Neo prices the hours it saves at your **fully loaded cost per hour**: a technician's gross salary plus employer taxes, benefits and overhead, divided by the hours they work. It is usually 1.25 to 1.4 times the hourly salary. An admin or owner sets it under [**Settings**](https://dashboard.neoagent.io/settings) → **Your cost of technician time**, then **Save Settings**; everyone else can read it there. <Frame> <img alt="Settings: Your cost of technician time, with an amount, a currency and the typical US rate as a one-click choice" /> </Frame> Until someone does, Neo uses the typical rate for your region: | Region | Typical rate | | - | - | | US | \$60/h | | UK | £45/h | | EU | €50/h | | Canada | C\$80/h | | Australia and New Zealand | A\$90/h | Your region comes from the currency you are billed in, else your timezone, else where your data is stored. The same rate prices [Neo Insights](/product/insights#your-hourly-rate), so both pages agree. You can also ask the [Neo Support Agent](/chat-agents/neo-support-agent) to set it. ## Cost Analysis The [**Cost Analysis** tab](https://dashboard.neoagent.io/analytics?tab=cost-analysis) breaks spend into three views: | View | Covers | | - | - | | **Workflows & Agents** | Credit spend by your automations and triggered/scheduled agents, sliceable by date, workflow, and action type | | **Dispatch** | Credits used by Neo's dispatch and triage layer | | **Chat Agents** | Conversational usage, split by audience — see below | ### Chat agents The **Chat Agents** view reports conversational usage, split by **audience** with the **Internal / End-user** toggle — because the two are billed on completely different models. Like the Performance tab, it counts only the agents you can view. #### Internal — your technician-facing agents **Internal** covers the chat agents your **technicians** talk to: the built-in [Neo Support Agent](/chat-agents/neo-support-agent) plus any dashboard or Teams [chat agents](/chat-agents/overview) you've built. These draw from your **credit pool**, billed **per tool call** — a turn with no tool calls is free. Pick a month to see: * **Credits Used**, **Messages**, **Sessions**, and **Active Agents** cards * **Chat credits & messages over time** — daily credits against message volume; a day with no messages shows as zero * **Per-agent** and **per-user** tables showing who and what is spending * **Tool usage** — calls and credits per tool, with plumbing tools (loading skills, Neo's API, memory) tagged **Free** so you can see what actually draws credits #### End-user — your branded Teams bot **End-user** covers your white-label [end-user Teams bot](/chat-agents/how-end-user-bots-work) — the branded bot your clients' employees message in Microsoft Teams. It is **not** billed in credits; it's priced **per client company** — a flat monthly price for each client where someone used the bot, and nothing for the rest — separate from your credit pool. The full pricing model lives in [Chat sessions & billing](/chat-agents/sessions-and-billing#billing). Pick a month to see: * **Active Users** (anyone who messaged the bot), **Projected charge** for the month, **Tickets Raised** by the bot, and **Status** — free trial with days remaining, active, trial ended, or disabled — with a shortcut to [Billing](https://dashboard.neoagent.io/billing) * **Active users over time** — the monthly-active-user trend * **Agents** — messages and sessions per end-user agent (no credits; it's billed per client company, not per message) * **End-clients** — active users, tickets and the month's price per client company, expandable to each employee and the specific tickets they raised. Clients nobody used the bot in show as \$0. <Info> The end-user bot runs a **14-day free trial** — usage appears here from day one, but nothing is charged until the trial converts. See [Chat sessions & billing](/chat-agents/sessions-and-billing#free-trial) for trial and billing mechanics. </Info> ## How to access <Steps> <Step title="Open Performance & Cost"> Select **Performance & Cost** from the main menu, or go straight to [dashboard.neoagent.io/analytics](https://dashboard.neoagent.io/analytics). </Step> <Step title="Choose a tab"> Switch between [**Performance**](https://dashboard.neoagent.io/analytics?tab=performance) to measure impact and [**Cost Analysis**](https://dashboard.neoagent.io/analytics?tab=cost-analysis) to track spend. </Step> <Step title="Scope and filter"> On **Performance**, use the **Agents / Workflows / All** toggle and the period selector. On **Cost Analysis**, pick **Workflows & Agents**, **Dispatch**, or **Chat Agents**, then a month. </Step> <Step title="Drill into a run"> For step-by-step detail on any single execution, open [Executions](/product/executions). </Step> </Steps> ## Why it helps * **Prove ROI** — show concrete time saved and ticket coverage from Neo's automations and agents. * **Control cost** — see which workflows, agents, tools, and chats consume the most credits, and where your end-user charges come from. * **Spot issues early** — a drop in success or resolution rate, or a spike in credits, surfaces here before it becomes a surprise. For how credits and end-user charges are calculated across every plan, see [Billing & credits](/product/billing-and-credits). # Announcements Source: https://docs.neoagent.io/product/announcements Stay informed about outages and newsletters from the Neo Team, and see how new features are introduced Neo Agent's Announcements feature keeps you informed about important updates from the Neo Team. These notifications cover system outages and newsletters that may affect your experience with Neo Agent. Major new features are introduced with a [Product Spotlight](#product-spotlights) instead. Announcements are automatically delivered through the Neo Agent dashboard and are also sent by email to every dashboard user who can sign in. ## How You Receive Announcements ### Dashboard Notifications All active announcements appear directly in your Neo Agent dashboard, ensuring you see important updates during your regular workflow. These notifications remain visible until the Neo Team marks them as resolved or no longer relevant. Some announcements carry an end date, and one of those disappears on its own when the date arrives. This is used for anything with a known end, such as a webinar or a scheduled maintenance window. An announcement with no end date stays up until the Neo Team clears it. <Frame> <img alt="Announcements displayed in Neo Agent dashboard showing active notifications" /> </Frame> ### Email Notifications Announcements are automatically sent by email to every dashboard user who can sign in. <Frame> <img alt="Sample announcement email showing formatted notification content" /> </Frame> ## Product Spotlights Alongside announcements, Neo occasionally highlights a major new feature with a **Product Spotlight** — a one-time modal that appears when you open the dashboard. It shows what shipped, a short description, and a screenshot, along with a **Docs** button linking to the feature's documentation and, when relevant, an action button that takes you straight to the feature inside the dashboard. Click the screenshot to open it full size, then press `Esc` or click anywhere to go back. Each spotlight appears **only once per user**: once a spotlight has been shown to you, it never comes back — on any device. If several features shipped since your last visit, they appear together as a small carousel (newest first, each stamped with its release date) so you can page through everything you missed. There is nothing to configure and no subscription to manage; spotlights are reserved for significant releases. ## Types of Announcements The Neo Team sends different types of announcements based on the nature of the update: ### General Outage System-wide issues affecting all Neo Agent users and services. These are high-priority notifications about service disruptions that may impact your operations. ### Partial Outage Localized problems affecting specific features or client groups. These announcements help you understand if certain Neo Agent capabilities are temporarily unavailable. ### Newsletter Periodic news from the Neo Team, such as a product roundup or an invitation to a live session. ### Payment Overdue Sent only to your workspace, when your account is overdue. It shows as a red banner at the top of every dashboard page and asks you to pay now, so that your agents and workflows keep running. You cannot close this banner. If you pay by card through Neo's billing, the banner appears by itself as soon as a payment fails, and goes away as soon as the payment goes through or when your account stops. Otherwise it goes away when the Neo Team confirms the payment or when its end date passes. To pay or update your card, open [Billing](/product/billing-and-credits). ## Who Receives Announcement Emails Every active user who can sign in to the dashboard receives outage and newsletter announcements by email. Chat-only members never receive them. There is no per-user setting to manage. The weekly **What's new in Neo** email goes to the same people, to people whose invitation is still pending, and to the users of a trial that ended without a paid plan. Each one carries an unsubscribe link, and a person who uses it stops receiving that email. Other emails choose their recipients by role: * **Inbox emails** that ask for a fix, such as a broken integration or a scheduled agent that failed on every retry, go to your workspace owners and admins. * **Credit and billing emails** are described in [Billing and credits](/product/billing-and-credits). ## Email Notification Details When announcements are sent via email: ### Email Format * **Subject Line:** "Neo Agent Announcement: \[Announcement Type]" * **Content:** The full announcement message formatted for easy reading * **Sender:** Official Neo Agent communications address: [neo.workflows@neoagent.io](mailto:neo.workflows@neoagent.io) The announcements system ensures you receive timely, relevant information about Neo Agent's status and capabilities, helping you maintain smooth operations and stay current with product improvements. # Audit Log Source: https://docs.neoagent.io/product/audit-log See every action your agents took in the last 30 days — one row per tool call — and check what an agent did, on which ticket or user, and how it went. Each row of the Audit Log is one tool call: the moment an agent added a note, updated a ticket, reset a password, ran a script, or read something from your PSA, RMM, or Microsoft 365. Open it from [**Activity → Audit log**](https://dashboard.neoagent.io/executions/audit-log) in the dashboard; the **Executions** tab beside it lists the runs those calls belong to. Use it when you want to know "did one of my agents do this?" — a ticket that changed status, a note nobody remembers writing, a user that was disabled. Search the ticket number or the user's name and the log shows which agent acted, when, with what input, and what came back. <Info> The log covers triggered agents, scheduled agents, and chat agents at once, and is scoped to your tenant. What you see follows your workflow access: an admin sees every agent, as does anyone given [every agent and workflow](/product/rbac#every-agent-and-workflow), including what agents you have since deleted did; a user or viewer sees the agents they created or that were shared with them. It keeps 30 days of history. </Info> ## What each row shows | Column | Meaning | | - | - | | **Time** | When the tool was called. Switch between your local time and UTC with the toggle at the top right. | | **Agent** | The agent that made the call. | | **Action** | The tool the agent used, for example *Add Internal Ticket Note* or *Update Ticket Fields*. | | **Result** | A one-line summary of what the tool returned. | | **Outcome** | **Success**, **Error** (the tool failed), or **No result** (the run stopped before the tool returned, or is still in progress). A script the agent ran in its sandbox shows **Error** when it exited with a non-zero code, or when Neo blocked API calls it made, for example for a missing permission or a required approval, even if the script itself reported success (test mode aside, below). Not every rejected call counts: a call to a Neo route that does not exist, for example, does not. | For a sandbox script, the **Result** starts with the script's exit code and, when Neo blocked any of its API calls, how many and why: for example `Exit code 0. Neo's proxy refused 77 API call(s): blocked_til_required x77.` A non-zero exit is not always a problem: a search that finds nothing exits with code 1. In [test mode](/core/configuration-reference#test-mode-and-re-running) Neo simulates each write a script makes that passes the proxy's own checks, so a simulated write is not counted and does not make the row an **Error**. A write those checks refuse, for example for a missing permission or a required approval, is still counted. When a write passed because you approved a request that listed that exact call (a plan of calls), the **Result** names that request: for example `Allowed by approved plan: request 9001 (77 planned call(s)).` A single request tool call shows the one it used. A sandbox script shows the listed calls it used when Neo could record them; if that record failed, the script's row leaves the request out, although the calls went through. A listed call can be used again for the same call while the approval stands. Each request tool call that uses it has its own row; a sandbox script's row lists the listed calls it used, however many times each ran. Click a row to expand it. The expanded view shows the exact input the agent sent to the tool, a summary of what the tool returned (the first 400 characters), the tool's internal name, and an **Open run** link to the full execution trace — every thought, tool call, message, and complete tool result of that run. ## Finding an action * **Search** matches the ticket number, user, device, or any other value in the tool's input, as well as the tool and agent names. Type a ticket number to see everything any agent did on that ticket. * **All tools** narrows the log to one tool, with the number of calls in the last 30 days next to each. * **All agents** narrows it to one agent. * **Errors** shows only calls that failed. Rows load 50 at a time, newest first. Use **Load older actions** at the bottom to page back through the 30-day window. ## Ask Neo Support The Neo Support Agent reads the same log. Ask it "did one of my agents touch ticket 48213?" or "who disabled this user last week?" and it searches the Audit Log for you, names the agent and the tool, and can open the run's full trace. It answers under your own access: it shows the same agents you would see on the page, and a person with no dashboard account is told to ask an administrator for one. ## Read it through the API The log is also available on the [public API](/developers/introduction), for your own scripts or reporting: | Call | Returns | | - | - | | `GET /public-api/audit-log/tool-calls` | The rows, newest first, 50 per page. Filters: `search`, `tool_type_name`, `agent_id`, `errors_only`. Each row carries an `execution_id`; `GET /public-api/executions/{execution_id}/steps` returns that run's full trace. | | `GET /public-api/audit-log/facets` | Call counts for the window: total, failed, and per tool and per agent. | The window is always the last 30 days. An API key with no acting user reads every agent; a call made on behalf of a dashboard user follows that user's workflow access, exactly as the page does. Full parameters and response schemas are under **Endpoints** in the API reference. <Note> Tool inputs are shown as the agent sent them, with two exceptions applied when the step is recorded. Fields named `password` or `secure` are masked whole. A password written inside a script is replaced by `***REDACTED-SECRET***` in the four places a PowerShell account-creation or password-reset step puts one: the literal given to `ConvertTo-SecureString`, the value of a `-Password` style parameter, a password assigned to a variable, and a quoted password written straight into an Active Directory `SetPassword` or `ChangePassword` call. The rest of the script stays readable, the script still runs, and technician approval still shows you the real one. A password written some other way into a script can still be stored. Everything else is stored as sent, so treat tool inputs as internal data. Loading a Neo skill shows as "Skill loaded" rather than the skill's content, here and in the run trace. Loading a skill your team wrote shows its content, because that text is yours. </Note> # Billing & credits Source: https://docs.neoagent.io/product/billing-and-credits How Neo Agent pricing works and what happens when you run out of credits Neo Agent uses **credits** to bill for automation work. Each plan includes a monthly bucket of credits. When automations run, they spend credits from that bucket. ## Plans <CardGroup> <Card title="Pilot" icon="paper-plane"> **\$500 / mo** 2,500 credits — around 750 tickets automated. No dedicated Microsoft Teams support channel. </Card> <Card title="Starter" icon="rocket"> **\$1,300 / mo** 10,000 credits — around 3,000 tickets automated. </Card> <Card title="Growth" icon="chart-line"> **\$2,340 / mo** 20,000 credits — around 6,000 tickets automated. </Card> <Card title="Custom" icon="building"> **Talk to sales** Unlimited automation, enterprise PSA support, custom integrations. </Card> </CardGroup> <Tip> All plans include reactive **and** proactive agents, every PSA integration, and full onboarding support. Plans from Starter up also include a **dedicated Microsoft Teams support channel** with the Neo team — Pilot uses email support instead. </Tip> ## How credits are spent **Workflows** (smart actions such as triage or dispatch) bill **1 credit per ticket** they work. That is the simple rule for most automations. **Agents** bill in two different ways. The same tool list can look cheap on a ticket-triggered agent and expensive on a scheduled or chat agent: | Agent | What you pay | | - | - | | **Ticket- or entity-triggered** | Once per run, at the highest tier among the tools *you chose* (1 / 2 / 3). The agent can call those tools as many times as it needs. Tools Neo adds for every agent never set this price. | | **Scheduled, with no ticket** | **Each tool call** at its per-call price. Ten 3-credit calls cost 30. Test-mode runs bill the same way. | | **Internal chat** | **Each tool call**, same prices. A turn with no billable tool costs 0. | | **End-user Teams bot** | Not credits — [per client company](/chat-agents/sessions-and-billing#billing). | | **Phone Agent** | A flat monthly fee, plus **1 credit per minute** of call time. See [Phone Agent](/core/phone-agent#what-the-phone-agent-costs). | Tiers: **Basic** = 1, **Standard** = 2, **Advanced** = 3. On a triggered agent, PSA, RMM, Microsoft 365, documentation and vendor APIs are Standard when every enabled permission is Read Only, and Advanced when any permission is Read / Write. On a scheduled or chat agent each of their calls prices by what it did. PowerShell and [External API Request](/agents/tools/management/external-api-request) are always Advanced. The full list — every customer-facing tool, what's Free, and what "Free" in Built-in Capabilities actually means — is on [Tool credit costs](/agents/tools/credit-costs). [A tool you can't switch off](/agents/tools/overview#credit-tiers) never sets a triggered agent's per-run price. On a scheduled or chat agent, that same tool still bills when it is called. You can see exact usage anytime under **Billing**, or break it down per workflow, agent, tool, and chat on the [Performance & Cost](/product/analytics) page. ### Ticket Dispatch Dispatch bills per ticket it works on, so re-running it over a backlog doesn't charge you repeatedly for tickets it leaves alone: * **A technician is assigned** — 1 credit. * **The ticket already had an owner** and *Skip if already assigned* is on — **free**. Dispatch checks ownership before it does any work, so a scheduled re-dispatch over an already-handled backlog costs nothing. * **Dispatch couldn't complete for a ticket** — for example it kept hitting calendar-slot conflicts and ran out of retries without placing it — **free**. The run output lists the ticket and the reason. * **Someone claimed the ticket while Neo was deciding** — 1 credit. Dispatch had already done the work by then; it discards the result rather than overwriting the human's assignment. With [Human in the loop](/building-automations/actions/ai/ticket-dispatch-suggest-technician#human-in-the-loop-approvals) on, you pay per outcome, not per approval round: the run that proposes an assignment or asks a question — the full decision work happens there — bills its normal 1 credit. Everything after is free: runs that pass a ticket still waiting on an answer, applying an approval, and the re-decision that follows a note or a picked option. A dispatched ticket costs 1 credit whether a human was in the loop or not. ### Scheduled agents and chat agents A [scheduled agent](/core/scheduled-agents) with no ticket bills the same way as an **internal chat agent**: **per tool call**, at each call's price. Test mode blocks writes; it does not stop those calls billing. The per-tool table is on [Tool credit costs](/agents/tools/credit-costs). Chat agents are also billed by **who they serve**: * **Internal chat agents** — your technicians chatting with Neo in the dashboard or Teams — spend credits **per tool call**. A turn with no billable tool costs nothing. * **The branded end-user Teams bot** — the white-label bot your clients' employees use — is **not** billed in credits. It's priced **per client company**, from \$9/month, and a client nobody used it in that month is free. See [Chat sessions & billing](/chat-agents/sessions-and-billing#billing). ## What your credits cost Wherever the dashboard shows credits, it also shows what they cost you in your billing currency: **1,234 credits ≈ \$160**. You see it on the agents list, **Performance & Cost**, **Executions** and each run, the **Billing** page, and chat **History**. Hover over the figure for the price per credit and where it comes from. The price per credit is what you pay, divided by the credits it buys: * **Plan and top-up packs**: your monthly plan charge plus the top-up packs you hold, after any discount, over the credits they include. A Growth plan at \$2,340 for 20,000 credits is \$0.117 a credit. * **Free credits do not lower the price.** Bonus, referral, reserve and trial credits cost nothing, so they count on neither side. Every credit you use is priced at the paid rate, including one that came from a free balance, so the figure is an estimate and never an invoice line. * **Custom plans** use the price per credit in your agreement. **Pax8** partners see Pax8's list price for their tier, in US dollars. A plan whose price no billing system holds shows credits only until the Neo team enters the agreed rate. * **Trials** show credits only, because nothing is paid yet. The price is the one in force today, so a past month is priced at today's rate. It refreshes once a day, and at once after you change your plan or packs. Exports carry it too: the executions CSV and **Export credits per ticket** have an **Estimated Cost** column. ## Credits per ticket To see what each ticket cost over a period, for example to work out your cost per client company, click **Export credits per ticket** on **Activity → Agent & Workflow Executions** for a CSV file. Or ask the [Neo Support Agent](/chat-agents/neo-support-agent): *"Show credits per ticket for the last 30 days."* It reads `GET /public-api/billing/usage-by-ticket`, which you can also call yourself with an [API key](/developers/quickstart). * One row per ticket: its ID, its number, its client company (ID and name in your PSA), the runs that billed credits, and the credits with what they cost you, highest first. * The company is the ticket's company in your PSA when Neo last synced the ticket, so a ticket moved to another company shows the new one. * An agent that runs on something other than tickets, such as time entries, bills per item: its rows show that item and its type, with no company. * A credit counts in the period it was billed in, as on your invoice. * Scheduled agents with no ticket, bulk runs and Chat Agents share one row with no ticket. * The total covers the whole period for the agents you can see, also when the answer lists only the highest tickets. * A period can be up to 93 days. Ask for a longer range one quarter at a time. ## Unusual agent usage Neo watches each agent's credit spend through the day and emails you when one of them uses far more than it normally does. The email names the agent, what it has spent so far today, and how that compares with its own average day, and links straight to the runs behind it. An agent you have since deleted is still named and still reported, without that link. A notice raised by the default detection also gives the share of your monthly credits that today's spend has used. A notice raised by a daily credit budget you set does not, because you chose the number it passed; it says so instead of calling the day unusual. The usual cause is a change to that agent. An agent that cannot finish its work will often repeat it, and a repeat every ten minutes adds up long before your monthly warning arrives. By default you are told when a single agent uses more than **8 times its average day** (the average of its last 7 days with credits in the last 30 days) and at least **5% of your monthly credits** in one UTC day. An agent with fewer than 3 days with credits in the last 30 days gets no default alert yet. Neo checks every 10 minutes, so the email arrives the same day, within about 10 minutes of the agent crossing that line. A crossing in the last minutes before 00:00 UTC is not reported for that day, because the next check starts a new day; an agent that keeps spending is reported on the new day. Each agent tells you at most once per UTC day. Agents that cross in the same check share one email; an agent that crosses later that day gets an email of its own. This default check covers every agent that has no [daily credit alert](#a-daily-credit-alert-for-one-agent) of its own. <Info> The notice goes to your account owners and admins. Manage it under [**Settings → Alerts**](https://dashboard.neoagent.io/settings?tab=alerts) → **Default alert for agents without a rule**. Under **Email the alert to** you can add more addresses in the email field under the **Account owners and admins** toggle, such as a shared mailbox or a Teams channel, and turn that toggle off to send the notice to those addresses only. You can also set a **daily credit budget per agent**, which replaces the default and tells you when any agent goes past that many credits in a UTC day, or switch the notice off. The notice needs **Account owners and admins** turned on, or at least one address in the email field. The default alert never turns an agent off. When no email gets through, Neo puts the notice in your Neo inbox instead. </Info> These emails are a warning, never a charge. The credits were already spent when the email arrives, which is why it is worth opening the agent it names. ### A daily credit alert for one agent Some agents use far more credits than others by design, so one threshold cannot suit them all. A daily credit alert gives one agent a cap of its own, and emails you on the same day that the agent goes over it, while there is still time to stop the spend. Rules live in [**Settings → Alerts**](https://dashboard.neoagent.io/settings?tab=alerts), under **Per-agent credit alerts**. Select **Add alert**, choose the agent, and set the rule. Select an agent's name in the list to edit its rule. From the same list you can switch a rule on or off with its **On** switch, or remove it, and each of those changes saves at once. A rule you switch off is paused: it keeps its settings, and the default check covers the agent until you switch it back on. Chat agents do not have this setting. You can also set the alert where you build the agent: switch on **Daily Credit Alert** on the **Overview** tab of the agent builder, or on the **Review & Launch** step of the workflow builder. It is off for a new agent or workflow. When you switch it on, it starts at 300% above the average, emails your account owners and admins, and leaves the agent running. Neo saves it when you save the agent; for a new agent, once the agent is created. **How the cap is set.** You choose how far above the agent's average day it may go, as a percentage. Neo takes the agent's last 7 days with credits within the last 30 days, and averages them. Days with no credits are skipped, so a week the agent was off does not lower its average. The cap is the average plus your percentage: 30% above an average of 100 credits is a cap of 130. The cap is never below **50 credits a day**, so a quiet agent does not alert on a day too small to matter: 300% above an average of 10 credits would be 40, and the cap is 50. You cannot change this minimum. An agent needs at least 3 days with credits in the last 30 days for an average. Until it has them, the rule has no cap and does not alert, and the list shows *Not enough history yet*. With 3 to 6 such days, the average covers the days there are. Before you save, the form shows what the rule would do for this agent, and on how many of the last 30 days it would have alerted. Each of those days is judged against the cap the rule would have given on that day. For example: *Average: 62 credits a day (last 7 days with credits). Alerts above 81\. It would have alerted on 2 of the last 30 days.* When it would have alerted, **Show chart** draws those 30 days against the cap. Neo works the cap out again every night, and each time you save the rule. **When it alerts.** The day is the UTC day, from 00:00 to 24:00 UTC, whatever your time zone. Every 10 minutes, Neo compares the agent's credits since 00:00 UTC with its cap. As with the default check, a crossing in the last minutes before 00:00 UTC is caught on the new day only if the agent keeps spending. When the agent goes over, Neo emails your account owners and admins while **Account owners and admins** is turned on, and also every address in the email field under that toggle. A new rule starts with **Account owners and admins** turned on. Add more addresses one at a time in the email field; a shared mailbox or a Teams channel address works. A rule needs **Account owners and admins** turned on, or at least one address in the email field. When no email gets through, Neo puts the notice in your Neo inbox instead. **Turning the agent off.** Switch on **Turn the agent off at the cap** to also disable the agent when it goes over. The email says that Neo turned it off. If Neo cannot turn it off, the email says so, and asks you to turn it off yourself. <Warning> While the agent is off, it does not process new tickets. Turning it back on does not process the tickets it missed. </Warning> When you turn the agent back on, its count for the rest of the UTC day starts again from the moment Neo turned it off: only the credits it uses after that count toward today's cap. If it goes over the cap a second time, Neo emails you again and turns it off again. At 00:00 UTC a new day starts, with a newly computed cap. Without this setting, a rule emails at most once per UTC day. **How it works with the default check.** An agent with an enabled rule is checked against its rule only: the default check and the account-wide **daily credit budget per agent** skip it. An agent with no rule, or with its rule switched off, stays on the default check. Delete the rule or switch it off to go back to the default. You can also read and set these rules through the public API, or ask the Neo Support Agent to set one for you. ## When you hit your monthly limit By default, automations **pause** until your credits reset on the **1st of the next month**. You won't be charged extra and no automation runs are lost — they resume the moment your credits reset. When this happens, the dashboard shows a banner explaining the pause, with a link to top up. You'll usually see it coming: when your current usage pace would use up your monthly credits, the dashboard warns you **before** you hit the limit — and as you get close it shows the date you're on track to run out (e.g. *"Credits run out around Jul 14"*). See [Will I be notified before I run out?](#faq) below. If you'd rather keep automations running, turn on **auto top-up**. ## Auto top-up <Info> Auto top-up is **off by default**. Turn it on in your dashboard under **Billing → When you reach your limit → Top up automatically**. Turning it back off stops us adding *new* packs. It does not remove the packs you already have — those keep billing monthly until you [remove or reduce them](#removing-or-reducing-your-top-up-packs). </Info> When auto top-up is on and you exhaust your monthly credits, we keep your automations running by adding credits — and, if you're on Pilot or Starter, we move you to the next plan up only at the point where that's genuinely cheaper for you: <Steps> <Step title="If you're on Pilot or Starter"> We add your selected **top-up pack** — 1,000 credits for \$250/month or 5,000 credits for \$750/month — to your subscription. Run out again and we add another. We keep topping you up until your plan plus the packs you've added would cost about the same as the **next plan up** (Pilot → Starter, Starter → Growth). At that point the bigger plan is the better deal — a larger base credit allotment for roughly the same monthly spend — so we move you up instead and **remove the top-up packs in the same change**, so you never pay for both. **When does the switch happen?** Each top-up adds its own monthly price, so the pack you pick decides when you cross over: | Your plan | Your top-up pack | You move up on your… | | - | - | - | | Pilot (\$500/mo → Starter \$1,300/mo) | 1,000 credits — \$250/mo | **4th** run-out | | Pilot (\$500/mo → Starter \$1,300/mo) | 5,000 credits — \$750/mo | **2nd** run-out | | Starter (\$1,300/mo → Growth \$2,340/mo) | 1,000 credits — \$250/mo | **5th** run-out | | Starter (\$1,300/mo → Growth \$2,340/mo) | 5,000 credits — \$750/mo | **2nd** run-out | For example, on Starter with the 1,000-credit pack your first four run-outs each add a pack (taking you to \$2,300/mo for 14,000 credits); the fifth would push your Starter + packs past Growth's \$2,340, so we move you to Growth — 20,000 credits — instead. We never switch you on your first top-up, only once the maths works in your favour. </Step> <Step title="If you're on Growth or higher"> We add your selected **top-up pack** (1,000 credits for \$250/month or 5,000 for \$750/month) to your subscription. The first charge is prorated for the remainder of your current billing period; from the next cycle the pack bills at full price with your plan, until you remove it. Hit the limit again? We add another pack. There's no upper limit — your subscription grows with your usage. </Step> </Steps> ### Removing or reducing your top-up packs Top-up packs are reversible, and you change them yourself. Go to **Billing → When you reach your limit** and choose **Manage top-up packs**. You need the Admin or Owner role. Set how many of each pack you want to keep — drop one, drop several, or remove them all. As you change the numbers, the dashboard shows what you will pay each month, the extra credits you keep, and the credit limit you are left with. <Warning> Changes take effect **straight away**, so your credit limit drops at once. If you have already used more credits this month than your new limit allows, your workflows and agents pause until your credits reset on the 1st. The dashboard warns you about this before you confirm. </Warning> Two more things happen when you reduce your packs: * **We credit you back for the unused part of the current billing period.** The credit comes off your next invoice. It is not a refund to your card. * **If you remove every pack, auto top-up switches off**, so we do not buy them again the next time you reach your limit. Keep at least one pack and your auto top-up setting is left alone. This screen only ever reduces your packs. To add more, turn on auto top-up and we add a pack when you reach your limit — or move up a plan, which is cheaper once your packs cost about as much as the next plan. <Check> You stay in full control. Neo Agent never charges you beyond what your plan and active top-up packs add up to. </Check> ## When does the top-up actually happen? Credit usage is checked **once an hour**. So if you blow through your monthly credits at, say, 14:23, the top-up applies sometime between 14:30 and 15:30. In that small window, automations might briefly pause. They resume as soon as the top-up lands. ## FAQ <AccordionGroup> <Accordion title="Is auto top-up a one-off charge or recurring?"> Recurring. Top-up packs are subscription items — they add to your monthly Stripe invoice until you remove them. This means you don't have to keep re-enabling auto top-up every month. </Accordion> <Accordion title="What happens if a subscription payment fails?"> Nothing changes at first. Neo keeps running throughout, and Stripe retries automatically **nine times** over about two weeks. We email you on each failed attempt, to the billing address on your invoice and to every owner and admin on the account. That needs two things: a payment link on the invoice, and at least one of those addresses. Keep one current — it is how we reach you about billing. If all nine fail, the subscription ends and we pause the account — see *My subscription ended* below. Paying any of the emailed links before then clears the invoice and nothing is interrupted. </Accordion> <Accordion title="What if my bank asks me to confirm the payment?"> Some banks require an extra confirmation step (3D Secure) before we can collect the charge. Your credits are added immediately either way — we email you a secure Stripe payment link so you can confirm whenever suits. If the payment can't be collected, our team will reach out before anything changes on your account. </Accordion> <Accordion title="What if I only need extra credits one month?"> Add the pack via auto top-up, then remove it yourself in **Billing → When you reach your limit → Manage top-up packs** when you no longer need it. Turning the auto top-up toggle off is not enough on its own — that only stops us adding *more* packs, and the packs you already have keep billing every month until you remove them. </Accordion> <Accordion title="Will I be notified before I run out?"> Yes — by email **and** in the dashboard. Who we email widens as the month gets tighter, so the warning always reaches the people it needs: | When | Who we email | | - | - | | **90% used** | Your owners and admins — the people who can turn on auto top-up or upgrade | | **On pace to run out** | Everyone with a dashboard login, since everyone's work is affected | | **Limit reached** | Everyone with a dashboard login, plus your billing contact in Stripe | No opt-in setting holds these emails back, because reaching your credit limit pauses ticket processing. Chat-only members are never emailed. In the dashboard, a banner escalates as you get closer, so you're covered even if you miss the emails: * **On pace to run out** — if your usage this month is trending over your monthly credits, a heads-up appears from the 3rd of the month. The forecast adds your usage so far to your usual usage for each remaining day, based on your last four weeks, so quiet weekends don't make it swing. * **Running out soon** — within about **5 days** of when we project you'll hit your limit, the banner shows the expected date (e.g. *"Credits run out around Jul 14"*). * **Paused** — if you use everything, a clear notice with a link to top up. If you have **auto top-up** on, these read as *"auto top-ups will begin"* rather than pausing. When auto top-up adds enough credits to keep your automations running, you get an email about the new pack or plan instead of the **Limit reached** email. There's also a neutral heads-up in the last few days before your monthly credits reset. </Accordion> <Accordion title="Do unused credits roll over?"> No. Your monthly credit allowance resets on the **1st of each month** — unused credits don't carry over. (This is separate from your billing date, which is when your subscription renews.) We size plans generously so most MSPs don't hit the limit — if you're consistently running low, Growth or Custom is usually a better fit than stacking top-up packs. </Accordion> <Accordion title="My subscription ended — what happens, and how do I restart?"> Neo pauses the account. Ticket processing stops, and we switch off the callbacks your PSA was sending us, so nothing runs and the plan stops billing. **Add-ons are separate subscriptions and do not stop with the plan.** If you have the Phone Agent add-on, it keeps billing until it is cancelled. A paused account cannot reach the Billing page, so email [support@neoagent.io](mailto:support@neoagent.io) and we will cancel it for you. **Your data is kept for a while, then deleted.** Nothing is deleted the day the account pauses. After that: * **60 days after the pause**, we delete your content: synced tickets and documentation, run history, chat, approvals, notifications, files, call transcripts and recordings, and the PSA and device data we copied. * **90 days after the pause**, we delete your setup: agents, workflows, dashboards, skills, memories, technicians, channels, dashboard users, API keys, integration settings, your end-client company list and its links, and the credentials you connected. Your account record keeps your plan, billing history and a few setup details, such as which PSA you used, with no credentials and no contact details. Restart before those dates to keep everything. Your billing records stay, so past invoices and credit usage are still right. To restart, sign in at [dashboard.neoagent.io](https://dashboard.neoagent.io) and pick a plan. Signing in still works while the account is paused — you land on the plan picker instead of the dashboard — until your setup is deleted at 90 days. After that, email [support@neoagent.io](mailto:support@neoagent.io) to restart. Choosing a plan switches everything back on with your configuration in place, and re-enables the PSA callbacks for you. If you restart after 60 days, Neo syncs your recent tickets and your documentation again on its own; run history and chat do not come back. Paying an old invoice from an email does **not** restart the account on its own — it settles that invoice, and the subscription behind it has already ended. Start a plan from the dashboard. If you have the **Phone Agent** add-on, your phone numbers stop taking calls when the account pauses. We hold the same numbers for **14 days**: restart inside that window and they come back by themselves, with nothing to set up. After 14 days the carrier takes them back and they cannot be recovered — so if you are close to that, email [support@neoagent.io](mailto:support@neoagent.io) rather than waiting. </Accordion> <Accordion title="Can I switch plans manually?"> Yes. To move up one plan (Pilot → Starter, or Starter → Growth), open **Billing** and, under **When you reach your limit**, click **Upgrade to Starter** or **Upgrade to Growth**. Before you confirm, you see the new plan's monthly price and Stripe's preview of today's charge; Stripe sets the final amount when you confirm. Any top-up packs you hold end with the upgrade, because the bigger plan's allowance replaces them. Only owners and admins can upgrade. If you are on **legacy pricing** (an older price we no longer sell), Billing shows it next to your plan, for example "10,000 credits a month for \$999, legacy pricing". You can upgrade the same way, and the upgrade ends your legacy price. Auto top-up never moves you off legacy pricing; only you can, from Billing. If your subscription has more than one plan item, bills yearly, or has a usage-based or tiered price, contact us to change it. To move down a plan, or to a Custom plan, contact your account manager or sales. </Accordion> <Accordion title="I bought Neo through Pax8 — how do I activate my account?"> Buying through Pax8 sets your order up, but it does not create your Neo account. We email an activation link to the admin address Pax8 collected at checkout, and opening it starts setup. See [Buying Neo through Pax8](/product/buying-through-pax8) for the whole flow, including what to do if the email never arrives. </Accordion> <Accordion title="I buy Neo through Pax8 — how does a plan change bill?"> A plan change bills the plan you **finish the month on**, for the whole month — so an upgrade removes the old plan and its overage, and a downgrade can raise this month's invoice. The rules, and what to check before you downgrade, are in [Buying Neo through Pax8](/product/buying-through-pax8#changing-plan). </Accordion> <Accordion title="How can I pay — card or Direct Debit?"> You can pay by **card** in any supported currency (USD, EUR, GBP). At checkout you'll also see bank Direct Debit options where available: **SEPA Direct Debit** for EUR and **ACH** for USD appear automatically. For **GBP Bacs Direct Debit**, tick **Pay by Direct Debit** on the pricing page before you subscribe — this sets your billing up for Bacs. Whichever method you choose, credits, top-ups, and renewals all work the same way afterwards. </Accordion> <Accordion title="We run several Neo accounts under one company — can they share one payer?"> Yes. One billing entity (with a single payment method or Direct Debit mandate) can pay for **multiple Neo accounts** — for example a group that runs several PSAs, or an MSP consolidation. Each account keeps its own plan, credit allowance, and invoice line, all billed to the shared payer. Ask your account manager to set this up; the accounts must all bill in the **same currency**. </Accordion> <Accordion title="Which email address do invoices go to?"> Whichever one you enter at checkout — so if invoices should reach your accounts team, use their address rather than your own. It doesn't have to match the email you sign in with, and the person paying doesn't have to be the person who set up the Neo account. You can change it any time afterwards from **Billing → Billing details → Manage billing details**, which opens Stripe. The same page also updates your payment method, downloads invoices, and edits your company name, address and tax ID. Receipts and any payment-confirmation emails follow the same address. </Accordion> </AccordionGroup> # Buying Neo through Pax8 Source: https://docs.neoagent.io/product/buying-through-pax8 Activating your account, how Pax8 invoices you, and what a plan change costs Your Pax8 order starts the activation; Pax8 then bills you for what your account uses. The plan and any credits above it appear on your normal Pax8 invoice, so there is no second bill and no card to add. ## Activating your account Buying does not create your Neo account. We email an activation link to the admin address Pax8 collected at checkout. <Steps> <Step title="Open the link and sign in"> Sign in with your **Microsoft 365 work account**. A personal Microsoft account will not work. </Step> <Step title="Finish setup"> Choose your plan and connect your PSA. Your account exists once you have been through this. </Step> </Steps> The link never expires, so an older copy of the email works as well as the newest one, and only the first sign-in claims the order. Cannot find the email? Raise it with Pax8 and they will have it re-sent. A missing email usually means a wrong address at checkout or a mail filter. ## Getting help Pax8 is your support contact for Neo. Raise anything you need through Pax8 — billing questions, account changes and product problems all start there. ## What you are charged for | Line | How it bills | | - | - | | Your plan | One month of the plan you finish the month on | | Credits above your plan | Charged per credit at your plan's overage rate | | Phone Agent | A flat monthly fee. Call minutes draw credits from your plan instead | | End-User Chat Bot | Per client company, banded by how many people there raise tickets | Everything reaches you on the Pax8 invoice. Your first month bills only from the day you chose a plan, so a free trial costs nothing. ## Changing plan Change your plan from **Billing → Plan & billing → Change plan**. A plan change bills the plan you **finish the month on**, for the whole month. * **Upgrade mid-month** — you pay one month of the new plan. The old plan and any overage it had built up come off the invoice. * **Downgrade mid-month** — you pay one month of the lower plan, plus any credits the month used above that plan's allowance. Two things follow. Upgrade once your overage already costs more than the higher plan. Upgrading with a few days left still bills a full month of it. <Warning> Check the credits you have already used before you downgrade. A downgrade can **raise** this month's invoice, because the whole month's credits are then measured against the smaller allowance. </Warning> Ask us to make the change on the 1st if you want it to apply from next month. ## What is different from buying direct * Pax8 invoices you. Pax8 billing needs no card, and there is no payment to manage in Neo. * No top-up packs to set up — credits above your plan simply appear on the next Pax8 invoice. * Cancelling goes through Pax8, not through Neo. Your account is switched off when Pax8 tells us, and switched back on with your plan intact if you buy again. Data in a switched-off account is deleted after 60 and 90 days; see [My subscription ended](/product/billing-and-credits). ## Moving from direct billing to Pax8 Already paying Neo directly and now buying through Pax8? Nothing is charged twice. Your existing subscription runs to the end of the period you have paid for, and Pax8 billing starts the day after it ends. You confirm both dates on screen before anything changes, and credit packs you have already bought stay usable. # Company Mapping Source: https://docs.neoagent.io/product/company-mapping How Neo recognizes the same customer company across your connected systems — and how to view and correct the mapping The same customer company exists in many of your systems — your PSA, your documentation platform (IT Glue), your RMM, Microsoft 365 — each under a **different ID** and often a slightly different **name spelling**. "Tool Supply, Inc." in your PSA might be "Tool Supply Inc" in IT Glue. Company Mapping is the directory Neo builds so it knows these are all the **same real-world company**. With it, Neo's agents read each system by its real ID instead of guessing from a name search — which is faster and far more reliable. ## Why it matters Without a mapping, an agent that needs a company's IT Glue documentation has to *search IT Glue by name*. That breaks constantly: a name like "Craig, Deachman & Associates" or "Tool Supply, Inc." won't match because of punctuation differences, and abbreviations or word-order changes miss too. Company Mapping resolves the company **once**, stores the link, and hands the agent the exact ID — so lookups just work. <Tip> You don't have to set anything up. Neo builds the mapping automatically as it syncs each integration. The pages below are for **seeing** what got mapped and **correcting** the occasional miss. </Tip> ## How Neo maps a company Neo resolves each external entity (e.g. an IT Glue organization) to one of your PSA companies using a ladder of methods, strongest first. The first confident match wins: | Method | How it matches | Confidence | | - | - | - | | **Native link** | The system's own built-in PSA link (e.g. IT Glue's PSA-integration) | Highest | | **Exact name** | Names match once punctuation, case, and spacing are ignored ("Tool Supply, Inc." = "tool supply inc") | High | | **Fuzzy name** | Names match after allowing for a legal suffix (Inc, LLC, Ltd, …) | Medium | | **AI match** | For the long tail the rules miss (abbreviations, trading names), Neo asks a small AI model to match against your company list — only when it's confident | Lower (flagged for review) | | **Manual** | You set it yourself — always wins, and survives re-sync | Definitive | The mapping is **built during sync** (in the background, over your whole company list at once) and **read instantly at runtime**. An AI match is deliberately kept below the bar for automatic use — it shows up for you to confirm rather than silently steering the agent. ## Where you see and manage it ### On the Companies page Each company row has a **Linked Systems** column showing the systems it's mapped to (e.g. its IT Glue organization). Click an entry to jump straight to that integration's mapping table. To add a mapping from here, click **Map system** on the row. Pick the system, then the organization that belongs to this company — the same manual mapping the Organization Mapping tab writes, without leaving the page. Microsoft 365 works differently: map its tenant with **Map GDAP tenant** in the **M365 Access** column (see [GDAP](/integrations/m365/gdap)). ### On the integration's "Organization Mapping" tab Open a connected documentation integration (e.g. **IT Glue**) and switch to the **Organization Mapping** tab. You'll see every organization with: * the **PSA company** it maps to, * a **Source** badge — **Auto** (Neo matched it), **Manual** (you set it), or **Unmapped** (no confident match yet), * how the auto-match was made and its confidence, * who set a manual mapping, and when. <Steps> <Step title="Find the organization"> Use the status filter (All / Mapped / Unmapped / Manual), the company filter, or search. </Step> <Step title="Map or re-map it"> Click **Map** (or **Re-map**) and pick the correct PSA company. This is a **Manual** mapping — it wins over any auto-match and survives future syncs. </Step> <Step title="Reset if needed"> **Reset** drops a manual mapping and returns the organization to Neo's automatic matching on the next sync. </Step> </Steps> <Note> For an RMM, the organization's **devices** pick up the new company on that integration's next device sync. Until then a device-scoped action — running a script on a device, or listing a company's devices — still sees the previous company. To move a device right away, map it in the **Device Mapping** tab. </Note> <Note> **Unmapped** means Neo hasn't confidently matched that organization to a PSA company yet — most often because the company isn't in your PSA, the names are too different, or that system hasn't finished syncing. Mapping it manually fixes it immediately. </Note> ### Through Neo Support or the public API Ask the Neo Support agent, for example "map the CIPP tenant Contoso Ltd to Contoso". It lists the integration's organizations and tells you the change. Say yes. With the default Neo Support permissions it then shows an approval card, and the mapping changes only after you approve it. The result is the same **Manual** mapping the tab writes. From your own scripts, use the public API with an API key: | Call | What it does | | - | - | | `GET /public-api/company-links?system=CIPP` | Lists the integration's organizations with their company, source, match method and confidence. Filter with `status`, `search` or `psa_company_id`. | | `POST /public-api/company-links/assign` | Maps one organization: `{"system": "CIPP", "external_id": "...", "psa_company_id": "..."}`. Same as **Map** or **Re-map**. | | `POST /public-api/company-links/clear` | Removes a manual mapping: `{"system": "CIPP", "external_id": "..."}`. Same as **Reset**. | Full request and response details are in the [API reference](/developers/introduction). ## Supported systems Every documentation platform and RMM Neo syncs has company mapping, and so do the security platforms **Huntress** and **ThreatLocker**: each one's organizations appear in the **Linked Systems** column and get their own **Organization Mapping** tab. Microsoft 365 is mapped by its tenant instead — see [GDAP](/integrations/m365/gdap). ## FAQ **Do I need to map companies before agents can use them?** No. Neo maps automatically during sync; agents use whatever's mapped and fall back to a normal lookup for anything that isn't. **Will a re-sync overwrite a mapping I set by hand?** No. Manual mappings always win and survive re-sync. Use **Reset** if you want Neo to take over again. **An organization shows the wrong company — what do I do?** Open the Organization Mapping tab, click **Re-map**, and choose the right company. From the other side, **Map system** on a company row does the same. Your correction sticks. # Dashboards (Beta) Source: https://docs.neoagent.io/product/dashboards Ask the Neo Support Agent for a dashboard of your data: it writes the code once, and the page shows the numbers until you refresh them <Note>Dashboards are in **Beta**. They are free, and a dashboard refreshes only when you ask it to.</Note> A dashboard is a page of widgets: headline numbers, tables, charts, and optionally a written summary. You describe it in a chat with the **Neo Support Agent**; it writes a small program for each widget that reads your systems, and the layout that draws it. From then on no AI runs unless a widget's code asks for it: every refresh runs those programs again, rather than asking a model to read your data afresh. A summary widget can ask for one, in which case its wording varies between refreshes. A dashboard is not an agent and not a workflow. It has no schedule, no runs in **Executions**, and it costs no credits. ## Building one Building a dashboard is for admins of your workspace: its code reads your whole workspace's data. Open [**Dashboards**](https://dashboard.neoagent.io/dashboards) and click **New dashboard** (admins see it when the workspace has the Neo Support Agent). The Neo Support Agent chat opens beside an empty page; ask for the dashboard you want. A pasted spreadsheet, CSV or example report is the best starting input. The agent asks at most a question or two (who reads it, where the data comes from), decides the rest itself, and lists its assumptions so you can correct any. Each time it writes the dashboard, every widget runs against your live data and the agent reads the first rows back. A widget that could not get its data says why, and the agent fixes it before it goes on. The dashboard appears beside the chat as it is built. To change it later, an admin opens the dashboard and clicks **Adjust with Neo**: a Neo Support chat opens beside it with the dashboard already named, and the page updates as the agent writes. Every version of the widgets is kept, so Neo can also restore an earlier one; a change to the name, period or permissions is not a version. An admin can also ask the agent to build, read, refresh and delete dashboards from any other Neo Support conversation, through the [Neo API](/agents/tools/management/neo-api); the card it posts opens the dashboard. In the chat, dashboards are for admins only: for other members the agent cannot open them, and they view and refresh dashboards on the page. Every call a dashboard makes is read-only, under the integration permissions the agent chose for it: it cannot change anything in your systems. ## Viewing and refreshing Open **Dashboards** in the sidebar and click one. The header says when the newest widget was read ("updated 4 minutes ago"), or **never refreshed**. Each widget shows its data and the time it was read. Opening the page does not refresh anything, the same way Grafana works: * **Refresh** reads every widget again now, over the dashboard's period as of now. While it runs the button spins and the widgets keep their last data. A widget is skipped when the refresh that last wrote it started less than a minute ago. * Each widget has its own refresh button, with the same one-minute cooldown. * **Auto-refresh** (Off, 5m, 15m, 30m, 1h) refreshes the page on that interval while it is open, counting from when you pick it. A refresh you start yourself does not move the next one. It is a setting of your browser, remembered per dashboard, and it pauses while the tab is hidden: a refresh that came due while you were away runs when you come back. * A widget read more than 15 minutes ago, or before the dashboard last changed, shows its time in amber, whether or not its last refresh failed. * A widget whose last refresh failed keeps showing its last good data, marked **refresh failed**; one that never got data is marked **failed**. Click the mark for the reason in one sentence. If the reason is a missing permission group, an admin can ask Neo to add it to the dashboard. The dashboard's creator and admins also see **Details**, the full error Neo uses to fix the widget. The page hides it from other members only: anyone who reads the dashboard through the API gets the full error. * A widget that has never been read says so and asks for a refresh. ## Period Every widget reads one data window, the dashboard's **period**: the last N days, the previous calendar week, or the month to date, in a timezone you choose. It is evaluated at every refresh. An admin can tell the agent to change it. ## Who can see and change a dashboard Every member of your workspace who can sign in sees every dashboard and can refresh it on the page. Only an admin builds one or changes its widgets or the integration permissions it reads with, and only an admin can ask the agent to rename it or change its period. The person who built it, or an admin, can delete it. Deleting a dashboard through the agent always asks for your approval first; from the list, the bin icon shows only to those who may delete. ## What is coming Schedules, delivery by email and Teams, stored history for trend widgets, and sharing per dashboard are planned for a later version. # Executions Source: https://docs.neoagent.io/product/executions Every run of your agents and workflows, with its steps, message and credits, and the PSA events that did or did not trigger them **Executions** (the first tab of **Activity**, under **Operate** in the sidebar) lists every run of your agents and workflows, newest first. The second tab, [Audit log](/product/audit-log), shows the same work one tool call at a time. Open it from the sidebar to see all runs, or from the history icon on an agent's row to see that agent's runs only. Each row carries the ticket, the status, when it started, how long it took, the credits it billed and the message it wrote; **Steps** opens the run's [Execution Log](#execution-log). <Tip> Start here when troubleshooting. The message column says what a run did, and **Include PSA events** on a ticket shows why an agent did or did not trigger for it. </Tip> With Executions, you can: * **Track Neo's actions:** see everything Neo has done, especially for a specific ticket * **Watch an agent:** filter to one agent to see its runs, start one with **Run now**, and stop one that is still running * **Understand triggering:** filter to a ticket and tick **Include PSA events** to see each time it was created or updated in your PSA and which agents that triggered, with the reason for every agent that did not match * **Hand a run back to Neo:** **Train** sends a run to the Neo Support agent, which reads the run and the approval decisions your technicians made on it and proposes an edit to the agent's instructions (your own feedback is optional). It is on the run's row and on its [Execution Log](#execution-log); **Skillify** turns a run that went well into a reusable skill Executions shows two kinds of rows: **runs** of your agents and workflows, and, for a ticket you filter to, its **PSA events** (ticket created or updated, trigger requested). The list keeps itself up to date while the tab is open: a running agent reaches its final status in place, and a run a PSA trigger starts appears on its own. Your filters and your open rows stay as they are. **Load older executions** turns the automatic update off until you next open the list, because you are then reading history rather than watching it; the refresh icon in the header reads the list again whenever you ask. Each time you open the list, it shows the newest runs. A tab in the background stops reading. When you return to it, the list reads again at once, or at its next scheduled update if you were away for less than one update interval. The page shows the runs of the agents you can open, and no others: an owner or admin sees every agent in the workspace, and everyone else sees the agents they created or that were shared with them. An admin widens that from **Roles & Access** — share one agent, or give the person [every agent and workflow](/product/rbac#every-agent-and-workflow). The same rule covers a run's [Execution Log](#execution-log), so a link to a run of an agent nobody shared with you opens a "not found" page. <Frame> <img alt="The Executions page showing runs and PSA events" /> </Frame> ## Row Types Executions shows these kinds of rows: ### Workflow Execution This event type logs the execution of one of your configured workflows. It shows the outcome of the workflow (e.g., Success, Failure, Skipped) and provides access to its output message or any errors encountered. Key information includes: * The specific workflow that ran * The ticket or entity it processed * Status, start time, duration, and credits billed for the run, with what they cost you * For a successful run, the technician minutes it is estimated to have saved * A detailed message, often including diagnoses, summaries, or actions taken <Frame> <img alt="Workflow Execution Details Modal showing detailed output message" /> </Frame> <Note> **A Failure can still have done some of the work.** If an agent is stopped part-way through — for example because a single model response stalled and Neo cut it off rather than letting it hang — the run is marked **Failure** even though the steps it had already completed stand. Neo retries the stalled step in place first, and only marks the run Failure if that doesn't recover it. It deliberately does **not** start the agent over from the beginning, because that would repeat actions it had already taken in your PSA (duplicate notes, time entries, or emails). The run's message says what happened and what was done. Open the run to see how far it got, then re-run it from Executions if the remaining work still needs doing. </Note> ### Other Event Types There are other types of events you should be aware of: * Entity Created: When a new entity (i.e ticket, project etc.) is created in the PSA. * Entity Updated: When an existing entity in your PSA is modified * Workflow Trigger Requested: When a Neo workflow triggers another workflow directly with the [Trigger or Schedule Workflow](/agents/tools/management/trigger-or-schedule-workflow) tool. This hand-off is matched on the target workflow's ID alone — it skips the target's configured trigger event and its Filter Ticket conditions, so the target can run even when a PSA event would not have matched it. Everytime one of these events happen, you can see whether each event led to a workflow kicking off on Neo's side. This is especially useful if you are confused as to ***why a specific workflow didn't run in response to something happening in the PSA***. <img alt="Screenshot 2026 01 18 At 14 49 51" /> To understand why a specific workflow was kicked off or not in response to an event, you can click on the eye icon next to the Triggered text (see screenshot above). You will then be able to clearly see the exact reason why a workflow kicked off or did not. <Note> **No PSA events at all for a ticket?** Check which boards Neo monitors, under **Integrations → PSA Filters**. An *include* filter accepts only the boards, queues or ticket types you list there; an *exclude* filter accepts every other one. Neo turns away the rest as they arrive, so a ticket the filter rejects produces no event row here, and no agent is ever considered for it. Neo keeps no record of a ticket it turned away, so an empty page here does not tell you whether your PSA sent the event. To start monitoring the board, add it to an *include* filter — Neo then indexes that board's recent history too — or take it out of an *exclude* filter. </Note> ## Filtering Filters live in the URL, so a filtered view can be bookmarked or sent to a colleague. * **Agent**: one agent's runs. The history icon on an agent's row opens this view, and **Run now** appears once an agent is picked. **Run now** can also supervise that one run, so every change waits for a technician you name: see [supervise a single run](/core/supervised-mode#supervise-one-run-or-every-run). * **Status**: the default set hides filter mismatches; pick statuses to narrow further, or tick **Filter mismatch** to see them. * **Ticket number / ID**: runs and events for one ticket. Digits are read as the PSA's ticket id; a value with letters, such as `T20260904.0009` or `INC0010530`, as the ticket number. * **Run ID**: one run. * **Started after** and **Started before**: rows that started inside a date and time range. Set one for an open-ended range. A [grouped run](#grouped-runs-approvals-and-script-waits) with one run inside the range shows all its runs, including those outside it. * **Include PSA events**: for the ticket you filtered to, also show its ticket created, ticket updated and trigger requested rows, with the **Event** and **Triggered / Processed** columns. Click **Triggered by a PSA event** under a run id to get there in one step. * **Local / UTC**: the time zone every timestamp is shown in. Click **Apply** to update the results, **Clear** to start over, and **Load older executions** at the bottom for the next page. **Export CSV** downloads the rows loaded on the page, with each run's ticket, credits, **Estimated Cost**, **Minutes Saved** and **Minutes Source**. To export one period, set **Started after** and **Started before**, then click **Load older executions** until it no longer appears. The file holds only rows that started inside the period, so a grouped run's runs outside it are left out. **Export credits per ticket** downloads one row per ticket, with its client company and the credits it billed in a period, in one click, however many runs the period holds. Set **Started after** (and **Started before**, or it runs to now) and click **Apply** first; the agents you picked narrow it too. A period can be up to 93 days. Runs with no single ticket (scheduled and bulk runs) and Chat Agents share one row, so the Credits column adds up to what the period billed. See [Credits per ticket](/product/billing-and-credits#credits-per-ticket). ## Understanding the Columns The Executions table displays the following columns: ### Run ID A unique identifier for the event. * For `Workflow Execution` events, this is the Temporal Run ID * For `Entity Created` / `Entity Updated` events, this is the Callback ID ### Event Type Indicates the type of event: * `Workflow Execution` * `Entity Created` * `Entity Updated` * `Workflow Trigger Requested` ### Workflow For `Workflow Execution` events, this column shows the **Name** and **ID** of the workflow that was executed. ### Ticket Displays the **Ticket Number** and/or internal **ID** of the PSA entity associated with the event. (Note: While labeled "Ticket", this can apply to other entities like Projects or Opportunities if they trigger workflows). ### Status The outcome or current state of the event processing: * **SUCCESS:** The workflow executed successfully, or the entity event was processed successfully (and may have triggered workflows) * **FAILURE:** The workflow encountered an error during execution, or Neo failed to process the entity event. A run that was stopped part-way through also lands here — see the note under [Workflow Execution](#workflow-execution) on why partly-completed work is still reported as a failure. When a **scheduled** agent's run fails on every retry, Neo also posts a warning to your Inbox and emails your workspace [owners and admins](/product/announcements#who-receives-announcement-emails), so you can rerun the agent with **Run Now** without watching this page. The Inbox card is one per agent and refreshes on each lost run; the email goes out at most once every seven days per agent * **SKIPPED:** The workflow was intentionally skipped (e.g., conditions not met, "Run only once" constraint, or scheduling restrictions). For entity events, it might mean the callback was superseded by a more recent one or did not match any workflow triggers * **RUNNING:** The workflow is currently in progress, or Neo is actively processing the entity event * **CANCELLED:** Someone stopped the run while it was in progress. Stopping is not immediate, but nothing new starts: an agent stops before its next action, so only what it is already doing finishes first. A workflow built from a fixed list of actions stops at the end of the action running now, which can take longer * **Awaiting approval:** The run is paused waiting for a technician to respond to an approval request. Once someone responds, a continuation run finishes the work * **Waiting for script:** The run is paused until an RMM script finishes on the device; a continuation run then picks up the result * **Resumed:** This run paused (for an approval or a script) and a later run already continued it — nothing is stuck. You'll see this on the individual runs inside an expanded group * **Superseded:** The run continued in a *different* run, so nothing more happens here. It is not a cancellation and not a failure: the steps it took and the credits it billed are real. Only historical runs carry this status; untick **Superseded** in the Status filter to hide them ### Runs the platform stopped A run can be stopped from outside by the platform itself — most often because it reached the time limit for a single run, but also if the machine executing it was replaced mid-run. In those cases the run has no chance to record its own outcome. Neo now recovers the outcome for you. Within a day or so, such a run stops showing **Running** and takes its real final status: * **Failed**, when the run was stopped before it finished. The message says the run never recorded an outcome of its own, and you can retry it from the row. * **Success**, when the run had in fact completed and only the final record was lost. * **Could not confirm**, shown as Failed with a message saying so, for very old runs whose record is no longer available to check, and for the rare run that left no record of how it finished. Until the outcome is recovered, a run in this state shows Running, and cancelling it returns an error saying it is no longer running. That error is correct — the run had already stopped. Once the status is recovered, both the display and the Retry action work normally again. ### Entity events Neo could not process An `Entity Created` or `Entity Updated` event can end before Neo matches it to any workflow. The usual causes are a PSA that does not answer in time, a PSA API rate limit exhausted during a busy period, or a ticket deleted in your PSA. These events show **FAILURE**, with the reason in the message column — for example `Autotask API hourly rate limit exceeded`. They used to show **RUNNING** and stay there. A deleted ticket is the exception: there is nothing left to act on and nothing to fix, so the event shows **SKIPPED** with the reason beside it. No workflow ran for that event, and Neo does not retry it. Read the reason, then trigger the agent manually from its page if you still need the work done. Rate-limit errors are also reported in your [Neo Inbox](/product/inbox). Events from before this shipped keep their old **RUNNING** display. ### Grouped runs (approvals and script waits) When a run pauses for a technician approval or an RMM script, the continuation is technically a separate run. Executions shows the whole thing as **one row**: the row carries the latest status, the start time of the first run, the combined runtime (with the waiting time shown separately, e.g. `+ 3h 12m waiting for approval`), and the total credits. A **"N runs" badge** with an expand arrow reveals the individual runs — each keeps its own Run ID, status, steps, and actions. Runs from before this feature shipped aren't grouped and keep their historical **PAUSED** label. ### Started At (UTC) The timestamp (in UTC by default, but can be adjusted with the timezone selector) when the event began. * For `Workflow Execution` events, this is when the workflow execution started * For `Entity Created` / `Entity Updated` events, this is typically the `created_in_psa_at` timestamp, meaning when the change actually occurred in your PSA ### Duration For `Workflow Execution` events, this shows how long the workflow took to complete. ### Credits For `Workflow Execution` events, this shows the number of credits billed for that individual run. This makes the cost of each execution transparent — it's especially useful for scheduled (ticketless) agents, where a run's cost isn't tied to a single ticket and would otherwise be hard to attribute. Beside the credits you see what they cost at your [price per credit](/product/billing-and-credits#what-your-credits-cost), and for a successful run the time it saved: **2 credits ≈ \$0.26 · \~6 min saved**. Hover over the minutes for where they come from: the agent's own estimate at the end of the run, a workflow's fixed minutes per action (an action that changed nothing counts none, except triage), the minutes your team set for the workflow, or the time a chat agent logged on the ticket. A run that paused, failed or was cancelled shows no minutes; the run that finishes the work records them. A grouped row adds up its runs, and the run detail page shows the same figures in its header. Entity events (`Entity Created` / `Entity Updated` / `Workflow Trigger Requested`) don't consume credits, so this column is blank for them. ### Triggered Workflows For `Entity Created` / `Entity Updated` events, this column lists the **IDs** of any workflows that were started as a result of this entity event. ### Processed Updates For `Entity Created` / `Entity Updated` events, clicking the icon in this column opens a modal displaying the **Processed Audit Trail**. These are the specific changes from your PSA's audit trail that Neo analyzed to determine if any workflow trigger conditions were met. ### Message/Error Provides a summary or detailed information about the event: **Workflow Execution events only:** This column shows the primary output message from the workflow (such as a diagnosis, summary, or confirmation of actions taken), or an error message if the workflow failed. > Note: Message/Error is currently populated only for Workflow Execution events. Entity Created and Entity Updated events do not display messages in this column. #### "This run made no tool call that can change a connected system" notice An agent changes your PSA, RMM or Microsoft 365 tenant only by calling a tool, and Neo records every tool call as a step on the run. Some tools cannot change anything — a search, a ticket read, a skill load. When a run's tool calls are all of that kind, or it made none at all, and its message still reports a completed change — a status change, a note, a logged time entry, a sent message — Neo appends a short system notice to the end of the message: > System note from Neo: this run made no tool call that can change a connected system, so it > changed nothing in any of them. Any change described above as completed was not carried out by > this run — it is context carried over from earlier activity. Please verify the ticket before > relying on it. This happens when an agent re-tells work from an earlier run on the same ticket as if it were its own. The notice is added, never substituted: the agent's own message is left exactly as written, so a mandated report format keeps every part of it. A run that reports no action ("reviewed, no changes needed") never gets the notice, and neither does a run that called at least one tool able to change something. Neo counts a tool that reads on one call and writes on the next — the PSA, Graph and RMM API tools, the sandbox — as able to change something on every call, so a run that only reads through one of those is not flagged. If you see the notice, treat the actions listed above it as unconfirmed and check the ticket itself. ## Execution Log **Steps** on a run's row opens its **Execution Log**: its own page, at `/executions/<run id>`, so you can bookmark a run, share the link with a colleague, or open several runs in tabs. The **Open run** link in the [Audit Log](/product/audit-log) and the per-subagent link in a fan-out land on the same page. The page reads the run as a story rather than a flat list of rows: * The header names the agent and the ticket, with the run's status, its run id to copy, how long it took, how many actions it made and how many of them failed. A supervised run carries a **Supervised** label, here and in the Executions list. * Each of the agent's **reasoning steps** is a heading. Click it to read the full reasoning summary. * Under each heading, one line per **action**: the tool the agent used, what came back, and how long the call took. A failed call is red. Click a line for the exact arguments and the full result, with the tool's internal name and a copy button. * Each **approval card** the run raised sits at the point where the agent raised it. While it waits, an admin or a technician it was sent to can answer it right there, with the same choices as the [Approvals page](/core/technician-in-the-loop#approvals-in-the-dashboard): only an agent's request offers **Ask for changes**, every dispatch request offers **Don't auto-assign**, and a dispatch proposal also offers **Offer to someone else**. An answered card shows the decision, who made it and their note. See [Watch the run](/core/supervised-mode#watch-the-run). * A run that paused for an approval or a script, and then resumed as a new run, shows as one flow: every run's steps in order, a line where each run starts with its run id to copy and how long it waited, and the newest run's status and outcome. The header counts the runs, the time spent waiting and the credits of all of them. * The run ends with its **outcome**: the agent's own verdict on how far it got (resolved, partially resolved, stopped for missing tools), the reason when it fell short, and the message it wrote. Once the run has finished, **Train** in the header hands it to the Neo Support agent. A supervised run also shows how many decisions were recorded, above its outcome, with **Train** beside it. The search icon filters the run by any word in a heading, an action's arguments or its result. The **⋯** menu switches between local and UTC times and downloads the run as JSON. Super admins can also show the run's inputs there: the user message and the model configuration. A supervised run you start with **Run Now** offers **Open the run**, which opens this page. Any other run you start there shows a notice with a link to it. For runs you start yourself with **Run Now**, Neo's reasoning streams onto the page live: the current heading shimmers while the summary grows, an action waiting for its result pulses, and the page follows the newest line. Scheduled and trigger-driven runs record the same steps, but each reasoning step appears once it completes. <Check> Use Executions to validate that your workflows are triggering correctly and producing the expected results. The detailed logs help you fine-tune filters and troubleshoot issues. </Check> # Inbox Source: https://docs.neoagent.io/product/inbox See account notifications and action items in one place ## What Inbox does Neo Agent's Inbox is your centralized place to see important account notifications and action items. It collects system notices, configuration prompts, and follow-ups so your team doesn't miss anything that needs attention. <Frame> <img alt="Inbox main view with notification list and details" /> </Frame> ## Message Details You can open a message to view the full context and next steps. There are a 4 types of messages that you should be aware of: * **Info:** General informational updates that help you stay aware of changes or results. * **Warning:** Potential issues that may require a review or follow-up soon. * **Error:** Failures that prevented an action from completing and likely need intervention. * **Action Required:** Items that explicitly need your confirmation, input, or a quick configuration change. When the same issue happens again, Neo updates the existing message instead of adding a new one, and counts the occurrences. The time shown on a message is when it last changed: when the issue happened again, or when Neo resolved it. Opening a message marks it as read without changing that time. The list shows unread messages first, and within each group the most recently changed first. <Frame> <img alt="Inbox message details view with full context and next steps" /> </Frame> ## Improvement suggestions from Neo Neo reviews its own Agent runs. When a run does not go perfectly, Neo looks at what happened and decides whether a change would have produced a better result. If it would, the suggestion arrives in your Inbox. Suggestions usually take one of three shapes: * **An edit to the Agent's instructions.** The message links you into Chat with Neo, where you review the exact wording change before anything is applied. Nothing changes until you approve it. * **A setting or permission change.** For example, a tool the Agent needs but does not have, or an integration permission that is switched off. The message names the change and links you into Chat with Neo to make it. * **A fact Neo learned.** Neo saved a durable detail about your environment to its memory, and the message tells you what it saved. You are never obliged to act on a suggestion; ignoring one leaves your configuration exactly as it is. # Neo Insights Source: https://docs.neoagent.io/product/insights Analyze your closed tickets to see which work your technicians still do by hand and what automating it could save, for your whole desk, a single end-client, or specific months. Neo Insights reads a sample of your closed tickets and shows which recurring problems an agent could take on, how many hours and how much money that work costs you today, and how to set it up. Open it from [**Insights**](https://dashboard.neoagent.io/insights) in the dashboard. The page has two tabs under the title. The line under the title names the question the open tab answers: | Tab | The question it answers | | - | - | | [**What to automate**](https://dashboard.neoagent.io/insights?view=problems) | Which types of tickets do your technicians still resolve by hand? Insights opens on this tab. | | [**Savings by category**](https://dashboard.neoagent.io/insights?view=categories) | What high-level categories do your tickets fall into, and what could automating each one save? | <Info> Insights reads only **closed** tickets that Neo has already processed with AI summaries, so a brand-new tenant sees a report once its first sync and AI processing complete. </Info> ## What to automate <iframe title="Neo Insights in 55 seconds" /> **What to automate** shows the specific, recurring problems your technicians still resolve by hand, measured from your own ticket data. ### Build a problem map Neo never builds a problem map on its own. Press **Build problem map** for the first one, or **New problem map** to run one for a company or a set of months, the same scoping as **Savings by category**. To leave a few companies out of a whole-desk map, such as an internal company or a client that has left, pick them under **Exclude companies**; the map's header and its entry in the report switcher name what was left out. Expect a run to take about 10 to 20 minutes, an estimate from our test desks that depends on ticket volume, and saves alongside your other problem maps in the report switcher. Only admins can build a problem map. Anyone else who opens an empty tab sees a request to ask an admin to build one, and a link to **Savings by category** when a category report exists. ### How Neo finds the problems Neo draws a random sample of closed tickets from the chosen window, groups tickets that need the same fix, and reads how each group was resolved. Grouping happens in two passes. Tickets written almost the same way, such as an alert stream, group first. Neo then writes a list of the jobs your desk does from the remaining tickets and files each of those tickets under one job, so requests worded ten different ways still land in one row. A row that holds more than one runbook is split, at most eight ways, and a row with fewer than eight sampled tickets goes to the long tail. The sample is drawn in two parts, alerts and system mail on one side and tickets people raised on the other, so that a busy alert stream does not crowd out the problems your users bring you. Each part is scaled to its own share of your desk, so the counts stay true. Neo keeps a list of your desk's problems, so a problem keeps its name from one map to the next. Your first whole-desk map creates the list. Each later whole-desk map files its tickets under the problems already on the list first, and adds a problem only for tickets no listed problem fits. A listed problem keeps its row with as few as one sampled ticket; a map that samples none of its tickets leaves it out. A map for one company, or with companies left out, uses the list and never changes it. Because whole-desk maps change the list, Neo builds one whole-desk map at a time. ### Read the problem table Each row is one problem, such as *INKY User Reported Spam Blocking* or *Exchange Online Mailbox Delegation*, with: | Column | What it means | | - | - | | **Tickets / mo** | How many tickets this problem produces a month, over the analysed window | | **Last 30 days** | Tickets created in the last 30 days of the window, so a stream that has stopped or grown shows up | | **Neo today** | Two shares of these tickets in the last 30 days of the window: the share that closed assigned to Neo, then the share a Neo agent ran on. Hover the value to read both in words | | **Median time** | The median time your technicians logged per ticket, from your PSA time entries | | **Opportunity / mo** | Hours a month an agent that resolves this problem would take on: the hours your technicians logged, plus an estimate for the tickets nobody logged time on. The logged hours appear underneath as the floor | | **Value / mo** | The opportunity hours a month times your cost per hour. A problem with no time logged shows no value | Open a row to see the steps technicians take today, including the different paths similar tickets follow, what still needs a person, any system an agent may need access to, and example tickets. To hand a problem to Neo, click **Set up with Neo** in the open row. Neo Support opens with a request to find the closest template or build an agent from scratch for that problem, walk you through it, and create it disabled so you review it before it runs. The request carries the problem's ticket volume and the evidence Insights found for it, so Neo Support starts from your own tickets. Owners, Admins and Users see the button when their account can message the Neo Support Agent; Viewers do not. ### Can Neo take it on today A chip under each problem name says whether Neo can take the work on with what you have today: * **Ready with current tools** (solid green) means every step has a route through an integration you have connected. The steps under *Still needs a person* still need a person. * **Ready · connect** (green, dashed border) means every step has a Neo route, and one or more of the integrations it uses is not connected yet, such as your RMM or IT Glue. Open the row to see the full list under *Connect in Neo*: each name there opens that integration on the [**Integrations**](https://dashboard.neoagent.io/integrations) page, and the RMM and PSA open the page itself, where you pick your vendor. * **May need** (amber) names a system no Neo integration reaches, such as Google Workspace or Duo. A system that Neo could reach only through a Custom API you would build yourself counts here too, and so does an order for hardware through a cloud marketplace, whose Neo integration reads licence subscriptions and changes seat counts only. Problem maps built before this check existed show no *Ready* chip, and maps built before the links existed show the names under *Connect in Neo* without links; build a new map to get both. ### Neo's share today Neo's share has two readings, printed as *resolved · touched*. *Resolved* means the ticket closed assigned to Neo. *Touched* means a Neo agent ran on the ticket, whoever closed it, so a triage or chase agent counts here and not under resolved. Both are split by close date into the last 30 days of the window and the months before them, so a problem you put Neo on last month shows the change at once. A small ▲ or ▼ after a value says that share moved from before the last 30 days to inside them; a move under 3 points shows no mark. Hover a value to read the two last-30-day shares in words. A row with fewer than 10 sampled tickets in the last 30 days shows its whole-window shares instead, and the hover says so. The **Last 30 days** tile carries the same two readings for the whole desk, and hovering it shows a small chart of both by month when the map's tickets closed in more than one month. Problem maps built before these readings existed show the whole-window resolved share alone. ### Hours and value Hours come from your PSA time entries. Median time counts only the tickets that carry one. Opportunity also counts the tickets without one: each of those adds the median logged time of its problem, or the median of the whole desk when the problem has 1 to 4 logged tickets, and the row says *desk median* when that happened. A problem that no technician has logged time on gets no estimate and shows *no time logged*, because a stream nobody logs time on is most often closed by a tool. Such a row ranks by ticket volume alone. Neo uses the median because on a desk that logs a small share of its tickets, the logged ones tend to be the long ones. The note under the table says what share of tickets carry a time entry; the lower that share, the more of the opportunity is estimate. Problem maps built before this estimate existed show the logged hours alone. The **Opportunity / month** tile also shows what those hours are worth a month and a year, and names the rate behind it. Value uses the **Avg. cost per ticket hour** from **Savings by category**, so the two tabs price an hour the same. ## Savings by category **Savings by category** turns your closed tickets into a projected return on investment from automation: how many hours and how much money you could reclaim, which categories to automate first, and how to set each one up. Your first category report runs automatically once your PSA sync finishes. After that you can run new reports any time, for your whole desk, for a single end-client company, or for specific months, and switch between the reports you've already run without re-running anything. ### What's in the report **Total annual savings opportunity** — one line at the top, and the only headline figure: money per year and hours per year. It updates when you edit the minutes per ticket in the table. **Savings breakdown by category** — every category ranked by projected monthly savings. Open a row to see its sub-categories and the agents and tools that would automate it. **Savings breakdown** — a chart of where the projected savings come from, by category. **Analysis details** — the parameters behind the numbers: | Field | What it means | | - | - | | **Company** | The end-client this report is scoped to, or **All companies** for your whole desk | | **Analysis period** | The date window the tickets were drawn from | | **Sample size** | How many tickets were classified to build the projection | | **Annual ticket volume** | Your total eligible tickets, extrapolated to a year | | **Region** | The region used to pick a default technician cost | | **Avg. cost per ticket hour** | Your fully-loaded technician cost (salary, benefits & overhead) that turns saved hours into money — editable inline | <Note> The projection extrapolates from a representative sample of your tickets to your annual volume, so the figures are directional estimates for planning, not exact accounting. </Note> ### Your hourly rate Insights and the [Performance & Cost](/product/analytics#your-cost-of-technician-time) page price an hour at one rate: your cost of technician time. While no admin has entered it, both use the typical rate for your region and mark it **typical US rate** (or your region). A rate an admin enters for a report becomes your cost of technician time everywhere, and the report's settings prefill with it next time. Keeping the typical rate stores nothing. Each report keeps the rate and the currency it ran with, so an old report reads as it did when it ran, also after the rate or your region changes. To price it at a new rate, run the analysis again. ### Switch between saved reports Every report Neo runs is saved. The **report switcher** in the top-right of the Insights page shows which report you're viewing (its company and time window) and lists every saved report — one per company-and-months combination, with the date it was run. Pick one to open it instantly; nothing is re-run and no analysis is consumed. ### Run a new analysis Use **New analysis** in the top-right (next to the report switcher) to open the settings and run a fresh report. <Steps> <Step title="Open the settings"> Click **New analysis** to open the settings popover. </Step> <Step title="Choose a company (optional)"> Pick a single end-client under **Company** to scope the whole report to that customer, or leave it on **All companies** to analyze your entire desk. </Step> <Step title="Pick a time window"> Either choose an **Analysis Period** (Last 30 / 90 / 180 / 365 days), or pick one or more **Specific months**. Selecting specific months **overrides** the rolling period. </Step> <Step title="Set your cost per hour"> Confirm the **Cost per Ticket Hour** — your fully-loaded technician cost — so the money figures reflect your team. </Step> <Step title="Run"> Click **Run Analysis**. A run typically takes **2–5 minutes** while Neo classifies your tickets and calculates the projection; the page shows progress and updates automatically when it's done. </Step> </Steps> <Tip> Scoping to a single end-client is ideal for a QBR or a per-customer ROI story — the report reads exactly like the desk-wide one, just for that company. </Tip> #### Choosing months The month picker lists every month you have ticket history for, newest first, and you can select several at once — including non-consecutive months. Neo analyzes only the tickets from the months you pick and annualizes from what it observed. Choosing months that span a limited part of the year can skew seasonal categories, so the analysis period shown on the report always reflects the exact window that was used. #### When a company doesn't have enough tickets A meaningful analysis needs at least **30** closed, AI-summarized tickets. When you scope to a company that has fewer than that in your chosen window, Neo automatically **widens the window to all time** for that company and tries again — so smaller clients still get a report where the data allows. If there still aren't enough tickets, Neo shows a clear **"not enough data"** message instead of an unreliable projection; pick a different company or period and try again. ## Good to know * **Who can run it** — only tenant admins can start a new analysis or problem map. Everyone with access can view saved reports. * **Re-running is safe and cheap** — each run replaces the saved report for that exact scope; running a company or month view never overwrites your whole-desk report. * **Export** — use **Export PDF** on **Savings by category** to share the report on screen outside the dashboard. ## Related * [Analytics](/product/analytics) — measure live workflow performance and credit consumption once your automations are running. * [Company mapping](/product/company-mapping) — how Neo recognizes the same end-client company across your connected systems, which is what powers the company filter here. # Role-Based Access Control (RBAC) Source: https://docs.neoagent.io/product/rbac Comprehensive user management and permission controls for your organization Administrators can assign user roles, share workflows with individual users, restrict dashboard sections, and review activity logs. ## User Management ### Dashboard Overview Find RBAC under **Roles & Access**. It lists users in your organization with their roles, status, and recent activity. Only users with **ADMIN** role can view/manage other users. <Frame> <img alt="RBAC Dashboard showing all users in organization with roles and status" /> </Frame> ### User Roles and Permissions Neo Agent supports different user roles with varying levels of access: * **Owner:** Everything an Admin can do, plus the workspace-wide [chat History](/chat-agents/using-chat#history-owners) and the right to make or remove owners. The first user of a workspace starts as its owner; a workspace always keeps at least one. * **Admin:** Full access to all features and user management capabilities * **User:** Regular Users can create any workflow as well as can edit any workflow shared with them. To give one User every agent in the workspace without making them an Admin, see [Every agent and workflow](#every-agent-and-workflow) * **Viewer:** Read-only access, can view execution history of any workflow shared with them, but cannot create or edit any workflow * **Chat only:** No dashboard access. They keep using Neo in Microsoft Teams, and you can pick them for a chat agent's **Specific people** list. See [Adding technicians in bulk](#adding-technicians-in-bulk). <Info> Users with OWNER or ADMIN role have access to all dashboard sections. Users with USER/VIEWER role need to be granted access to restricted dashboard sections. </Info> ### Workflow access applies everywhere — including Neo Support A user's workflow access (their role, the workflows they created, and the workflows shared with them) is enforced consistently across every surface: * **Dashboard:** the workflow list, editor, run-now, version history, and stats only cover workflows the user can access. * **Runs:** the Executions page, a run's page, and everything on it — the step trace, the files a run produced, the subagents it dispatched — cover the same workflows. Someone sent a link to a run of a workflow nobody shared with them sees the same "not found" page they would get for the workflow itself. Approving is the exception: a request sent to a technician stays on their [Approvals](/core/technician-in-the-loop) page and they decide it, whether or not they can open the agent that raised it. * **Audit Log and the public API:** the [Audit Log](/product/audit-log) lists the actions of the workflows the user can access, on the dashboard page and on `GET /public-api/audit-log/tool-calls` alike. The `/public-api/executions` endpoints answer the same way. An owner or admin sees every agent; a user or viewer only the agents they created or that were shared with them. * **Neo Support chat:** when a user asks the Neo Support Agent to list, inspect, edit, or train workflows, the agent operates under **that user's** permissions. It only sees the workflows they can see, and edits (including training suggestions) require edit access — a Viewer, or a User the workflow isn't shared with, will be told to ask an administrator instead. * **Training suggestions:** reviewing or applying a suggested change to a workflow requires access to that workflow. * **People with no dashboard account:** a technician who can chat with the Neo Support Agent (for example in Teams) but has no account in **Roles & Access** cannot list, view, or edit any workflow through it. Their company data comes from one workspace-wide default, which is empty until an admin sets it — see [People without a dashboard account](#ai-chat-data-access). The agent tells them to ask an administrator for an account. To let someone read workflows without changing them, invite them as a **Viewer**. * **Skills:** creating, editing, or deleting a [Skill](/agents/skills/overview) applies to every agent in your workspace, so the Neo Support Agent only does it for people whose role can write — a **Viewer** (or someone with no dashboard account) is told to ask an administrator instead. * **Intents:** a **Viewer** can open the [Intents](/chat-agents/intents) page and read every intent, but cannot create, edit, enable, disable, duplicate, or delete one, on the dashboard or through the Neo Support Agent. Owners, Admins and Users can. * **Company data in AI chat:** admins hold every data source implicitly. For everyone else, the Neo Support Agent uses only the sources granted on their page — open **Roles & Access** and click their row — the PSA (synced tickets, contacts and configurations, plus live reads), each documentation source separately, and devices (all connected RMMs together). Anything not granted is explained by the agent, with the fix, instead of failing. See [AI chat data access](#ai-chat-data-access). There is no way to use the Neo Support Agent to reach a workflow the user couldn't reach on the dashboard. ### Access Denied Scenarios When users don't have the necessary permissions to access the dashboard, they'll encounter an access denied screen that explains the restriction and provides contact information for administrators: <Frame> <img alt="Dashboard Access Denied screen with explanation and administrator contact information" /> </Frame> ### Inviting New Users To add new team members to your Neo Agent organization: 1. **Access User Management:** Navigate to the Roles & Access section 2. **Click Invite User:** Select "Invite New User" to open the invitation form 3. **Enter User Details:** Provide the user's name, email address, and assign their role 4. **Send Invitation:** The system automatically sends an email invitation to the new user <Frame> <img alt="Invite New User form with name, email, and role selection" /> </Frame> #### Example of Email: <Frame> <img alt="Sample invitation email sent to new users" /> </Frame> New users receive an email invitation with instructions to access the Neo Agent dashboard and will appear as "Pending" until they complete the activation process. ### Adding technicians in bulk **Add technicians**, beside **Invite User**, gives many of your PSA technicians a membership at once. **Specific people** can only name people who hold one, so use this for the technicians who work in Microsoft Teams and never open the dashboard. 1. Open [**Roles & Access** → **Users**](https://dashboard.neoagent.io/rbac) and click **Add technicians**. 2. Pick a role. **Chat only** is the default. 3. Tick the technicians, or use **Select all**, then click **Add**. What each person gets: | Role | Dashboard | Email | | - | - | - | | **Chat only** | None. They keep using Neo in Teams, and you can now choose them under [Chat Agent Access](#chat-agent-access) | None | | **Viewer**, **User** or **Admin** | They sign in with their Microsoft account; no invitation to accept | A notice with a link to the dashboard | Every membership is active at once, so Neo recognizes a technician in Teams from their next message. A non-admin starts on the no-account [AI chat data access](#ai-chat-data-access) default, so nobody loses data they could already read. Owners are appointed one at a time. The list shows technicians linked to a Microsoft account who have no membership yet. That link comes from the [Microsoft Teams — Technician Mapping](/integrations/teams/workforce-availability) integration. For someone who is not a technician, use **Invite User**. If a technician is missing from the list: 1. Look for them in **Roles & Access**. Someone with a membership, pending or inactive included, is not in the list; open their row there instead. 2. Check that they are on the [**Technicians**](https://dashboard.neoagent.io/profiles) page. A PSA sync does not add technicians there, so add them with **Add Technician**. 3. Under **Integrations** → **Microsoft Teams — Technician Mapping**, click **Run auto-map**. It matches each technician's PSA email to a member of one of your Teams. 4. If they stay unmatched, [map them by hand](/integrations/teams/workforce-availability#mapping-technicians) with their sign-in email, or use **Invite User**. The Neo Support Agent can do steps 2 and 3 for you, after you approve them. ### Changing someone's name or role Click their row in **Roles & Access**. The person's page opens with **Name & role** at the top. A new name saves when you click away from the field; a role saves as soon as you pick it. Only an owner can make someone else an owner, and a workspace keeps at least one owner, so the last one cannot be demoted. ## Permission Management ### Dashboard Tab Access Control access to dashboard sections through granular permission settings: <Frame> <img alt="Update permissions interface showing granular dashboard tab access controls" /> </Frame> Available restricted access tabs include: * **Integrations:** Configure PSA, RMM, and other system integrations * **Analytics:** View workflow performance and system analytics * **Phone Agent:** Manage AI Phone Agents settings and call history * **Companies:** Manage client companies and organizations * **Profile:** View and edit user profile information * **Billing:** Manage billing and subscription information * **Settings:** Configure system settings and preferences * **Feedback:** Provide feedback about workflows * **Chat:** Access chat agents for conversational AI assistance * **Backfills:** Create and manage workflow backfill runs over historical data * **Scheduled Work:** View and manage scheduled workflow runs #### Restricted Access Experience When users attempt to access a dashboard section they don't have permission for, they'll see an access restriction message: <Frame> <img alt="Tab restricted access screen with explanation and guidance" /> </Frame> The message directs users to their administrator to request access. ### Workflow Sharing Give one person access to agents and workflows they did not create. #### Every agent and workflow To let someone reach all of them at once, open **Roles & Access**, click the person's row, and turn on **Every agent and workflow** in **Agents & workflows shared with them**. It covers agents created later, so you never share one again for that person. Their role still decides whether they can edit: a **User** edits everything, a **Viewer** reads everything. It grants nothing else an admin can do — no member management, no dashboard sections, no company data in AI chat. For [Chat Agent Access](#chat-agent-access) it counts as sharing every agent, so it admits them to an agent set to **Specific people**; **Admins only** still admits your admins alone. Turn it off and they are back to the agents they created plus the ones named below. Both the switch and each individual grant appear in that person's [activity history](#activity-tracking). #### One agent at a time 1. Open **Roles & Access**, then click the person's row. 2. In **Agents & workflows shared with them**, click **Add agent**. Search by name or by id, then click every agent you want. Each pick gets a check, and the panel stays open. 3. Click **Add** to grant them all at once. Closing the panel first cancels your picks. 4. Use the bin icon on a row to take an agent back, then confirm. When the agent is part of a chain, the confirmation says how many go with it. Each agent's id sits beside its name in the list, so two agents that share a name can be told apart. Adding saves when you click **Add**; removing saves once you confirm. Shared workflows appear in that person's dashboard alongside the ones they created themselves. <Note> A workflow that runs as part of a chain is shared with the rest of its chain, and taken back with it. Half a chain shows someone a run that starts or ends in a workflow they cannot open. </Note> ### Chat Agent Access The **Chat Agent Access** tab controls who on your team may message each internal chat agent. This is separate from workflow sharing and dashboard tab access. It governs messaging only, not who can see or edit the agent's configuration. <Note> Controlling a chat agent is two independent questions. **Who may message it** is this tab. **What company data it uses for each person** is [AI chat data access](#ai-chat-data-access) on that person's page. Opening the agent to everyone grants nobody your ticket or documentation data, and granting someone that data does not let them message an agent this tab excludes. </Note> <Frame> <img alt="Chat Agent Access tab listing each chat agent in a table with a 'Who can message it' dropdown and a People column" /> </Frame> For each chat agent, an admin can choose one of three modes: | Option | Who can message the agent | | - | - | | **Everyone on your team** | Anyone on your team — the default | | **Admins only** | Your admins only | | **Specific people** | Admins, plus the individual people you choose (uses the same user picker as workflow sharing) | The picker lists people who hold a membership. A technician who only uses Teams has none until you add one with [Add technicians](#adding-technicians-in-bulk), where **Chat only** is enough. Under **Admins only** or **Specific people**, a technician with no membership cannot message the agent at all. Only admins can change these settings. The mode applies to every internal chat agent, including the **Neo Support Agent**. Agents that serve end users through a [channel](/chat-agents/channels) are governed by that channel instead, not by this tab. This setting drives what each person sees: the **Chat** page's agent list, the **Train**/**Skillify** buttons, and the **Need help?** widget all appear exactly for the people the agent's mode admits. Restricting the Neo Support Agent therefore also removes those affordances for everyone excluded. You no longer need to restrict the Neo Support Agent to protect your company data: what it may read for each person is a separate, per-person setting — see [AI chat data access](#ai-chat-data-access) below. A non-admin who chats with it always gets product help and can train the agents they have access to; company data follows their grants. ### AI chat data access Every person's page (**Users** → click their row) has an **AI chat data access** section. It lists the integrations you have connected that carry company data, and an admin ticks the ones the Neo Support Agent may use when that person is chatting — on the dashboard and in Microsoft Teams alike: | Group | What a grant unlocks | | - | - | | **Tickets** (your PSA) | Searching and summarising synced tickets, contacts and configurations, plus live reads from the PSA | | **Documentation** (IT Glue, Hudu, SharePoint, Confluence, Lexful…) | Searching that source's documentation, plus live reads from it — each source is granted separately. Read-only, with the source's credential area excluded. For IT Glue, [what the grant covers](/integrations/documentation/itglue-api#itglue-api-tool) and [Restricted documents](/integrations/documentation/itglue-api#restricted-documents), which are excluded by default | | **Devices** (your RMMs) | The synced device inventory. The device tools read across every RMM, so all connected RMMs are granted together | The Tickets grant carries two further reads that are assembled from PSA data: raw analytics queries over synced tickets, and resolving a company name to its ids in the systems that person is granted. Admins hold every grant implicitly. Nothing is granted to a new user by default — **an invitation on its own grants no company data**, whatever role it carries, so a new Viewer starts with every box unticked. When someone asks the agent for data outside their grants, it names the system it cannot read and points them to an administrator, with a link to [**Roles & Access**](https://dashboard.neoagent.io/rbac) so the admin lands on the right page. It also names which setting applies to that speaker: their own grants when they hold an active account, and the no-account default below when the workspace never registered them. A pending or disabled account reaches neither until it is active. A change you make here reaches an open conversation on that person's next message, so they do not have to start a new chat to pick it up. If the agent still repeats a refusal it gave before the change, a new chat clears it. <Tip> **To let some technicians ask for reports on tickets:** give them a membership under **Roles & Access** (**Chat only** if they only use Teams, **Viewer** if they should also open the dashboard), then open each person's page and tick the **Tickets** grant. If they will never hold a dashboard account and only chat from Microsoft Teams, add Tickets to the no-account default described below instead. Then check **Chat Agent Access** admits them: **Everyone on your team** does; under **Admins only** or **Specific people**, a person not listed cannot message the agent at all, whatever their grants. </Tip> Documentation stays separate from Tickets — a person with Tickets and no documentation source cannot reach your documents through an analytics query either. Saved memories follow the dashboard account rather than a grant. Anyone with an active Neo account can recall them in chat, exactly as they can read them on the **Memory** page; someone who only chats from Microsoft Teams with no account cannot, whatever their grants say. **People without a dashboard account.** Anyone in your Microsoft Teams can chat with the Neo Support Agent, including people you never invited to the dashboard. The **Users** tab has a collapsible card, *AI chat data for people without a dashboard account*, that sets what the agent may use for such a speaker — empty by default. To give one specific person more or less than that default, add them as **Chat only** with [Add technicians](#adding-technicians-in-bulk) (or invite them as a Viewer) and set it on their page. The same page carries that person's name and role, the **Dashboard sections** they may open (navigation only — it does not protect data), and the agents shared with them, so one page answers "what can this person reach" and is where every part of the answer is changed. See [Who can chat with the agent](/chat-agents/building-a-chat-agent#who-can-chat-with-the-agent) for how this appears when building an agent. ### API Keys The **API Keys** tab is where admins create and manage keys for the [Neo public API](/developers/introduction): the credentials your own scripts and integrations use to call Neo programmatically. From [**Roles & Access** → **API Keys**](https://dashboard.neoagent.io/rbac?tab=api-keys) an admin can: * **Create** a key, with an optional expiry. The full key is shown **once**, right after creation — copy it then, as it can't be retrieved later. * **Rotate** a key — issues a replacement immediately while the old key keeps working for 24 hours, so you can roll it over without downtime. * **Revoke** a key — disables it immediately and permanently. Only admins can manage API keys. See [Authentication](/developers/authentication) for how to use a key once you've created one. ## Activity Tracking ### Comprehensive Audit Trail Neo Agent maintains detailed activity logs for all user actions and administrative changes: <Frame> <img alt="Activity History showing comprehensive audit trail of user actions" /> </Frame> ### Tracked Activities The system automatically logs: * **Workflow Sharing:** When workflows are shared or access is revoked * **Role Changes:** Updates to user roles and permissions * **User Management:** User creation, activation, enabling, and disabling * **Permission Updates:** Changes to dashboard tab access * **All Agents And Workflows:** When the workspace-wide workflow grant is given or taken back ### Activity Details Each audit entry includes: * **Timestamp:** When the activity occurred * **User:** Who performed the action * **Activity Type:** What type of change was made * **Details:** Specific information about the change ### Access reviews The Users page shows a **Last Active** column: when that person's dashboard session last reached Neo. Neo refreshes it at most once every ten minutes, so it can sit up to ten minutes behind the real visit. It reads **No activity yet** when Neo holds no activity for that person. That covers someone who has not opened the dashboard since you gave them access, and it also covers an account that was last used before Neo started recording this, so treat an old account that reads No activity yet as unknown until its next visit. Use it to find dormant accounts during an access review. A **Chat only** member cannot sign in, so Last Active never moves for them: it reads No activity yet, unless you changed that person to Chat only from a dashboard role, when it keeps the older activity from that role. Either way it says nothing about whether they use Neo in Microsoft Teams. Last Active measures use. It moves whenever that person's dashboard session reaches Neo, and Neo keeps no sign-in record of its own. For sign-in events, use the Microsoft Entra sign-in logs for your directory. To collect the same list on a schedule, call `GET /public-api/memberships` with a [tenant API key](#api-keys). It returns every person who holds a membership, with their name, email, role, status, `all_workflows_access` and `last_active_at`. `all_workflows_access` is the switch above; an Admin reaches everything through their role and reads `false`. The endpoint is read-only and open to a workspace admin or an API key; inviting and revoking still need an admin signed in to the dashboard. ```powershell theme={null} $headers = @{ Authorization = "Bearer $Token" } $members = (Invoke-RestMethod -Uri 'https://api.neoagent.io/public-api/memberships' -Headers $headers).data $members | Select-Object user_name, email, role, status, all_workflows_access, last_active_at | Export-Csv access-review.csv -NoTypeInformation ``` ## Managing User Status ### User Status Types Users can have different statuses within your organization: * **Active:** Full access according to their role and permissions * **Inactive:** Temporarily disabled access while preserving user data * **Pending:** Invited but not yet activated their account ## Announcement Notifications Every active user who can sign in receives Neo's announcement emails; chat-only members do not. See [Announcements](/product/announcements#who-receives-announcement-emails). ## Access across workspaces An admin can give a person access to another MSP's workspace. Add the person from the **destination workspace's** Users page. Their role, shared workflows, and chat data access apply only there. Enter their name, email, and role, whether they work at your company or another MSP. Neo emails an **Accept invitation** link. The person opens it, signs in with the Microsoft work or school account for the invited email address, and selects **Accept invitation**. They do not need to provide Microsoft directory or object IDs. Personal Microsoft accounts cannot accept invitations. The email link expires after seven days and works once. For a pending user, select **Resend invitation** to send a replacement and invalidate the old link. **Cancel invitation** immediately invalidates the invitation. If email delivery fails, the pending user remains listed so you can resend it. If the recipient signs in with a different email address, they can select **Use a different Microsoft account** on the acceptance page. A person with one active workspace opens it directly. If their Microsoft directory has no Neo account yet, the chooser also offers **Set up my company**. With several workspaces or company setup available, they can use **Switch workspace** in the account menu. Each browser tab keeps its own selected workspace. A switch opens the new workspace's home page and clears the previous page's state. For example, an admin in Contoso MSP can add Alice from Acme Corp MSP. Alice can then access both workspaces with her assigned role in each. Bob's existing Contoso MSP membership gives him access only to Contoso MSP. Disable a person's membership to revoke access to that workspace. A later sign-in does not restore it. Their memberships elsewhere remain active. Acquisitions and shared billing accounts do not automatically grant access or change subscriptions. Public API admins can cancel a pending invitation without a Microsoft object ID using `DELETE /public-api/memberships/invitations` with an `email` field in the JSON body. This cancels only a pending invitation in the selected workspace. Active memberships use the user-ID revocation endpoint. # Referral Program Source: https://docs.neoagent.io/product/referral-program Earn monthly credits for a year by referring other MSPs to Neo Agent Refer other Managed Service Providers (MSPs) to Neo Agent. You earn bonus credits every month for a full year for each MSP you refer — and the MSP you refer gets a welcome bonus too. <Tip> For every MSP you refer, you earn **1,500 credits per month for 12 months**, and the MSP you refer gets a **one-time 2,500-credit welcome bonus**. There's no limit on referrals, and the monthly credits stack — refer three MSPs and that's **4,500 credits every month**. </Tip> ## What you earn <CardGroup> <Card title="You (the referrer)" icon="gift"> **1,500 credits every month, for 12 months**, for each MSP you refer. Each referral runs on its own 12-month clock, and the monthly amounts stack across referrals. </Card> <Card title="The MSP you refer" icon="gift"> **A one-time 2,500-credit welcome bonus**, available to spend over their first 12 months. </Card> </CardGroup> ## How it works <Steps> <Step title="Find your referral code"> Every Neo Agent account has a unique referral code, shown at the top of [**Settings**](https://dashboard.neoagent.io/settings) and on the [**Billing**](https://dashboard.neoagent.io/billing) page. It's assigned to you and can't be changed, so a code you've already shared keeps working. On Billing, **Copy invite message** copies a ready-made message with your code; in Settings, select **Refer & Earn** next to the code. </Step> <Step title="Share it with another MSP"> Send your code — or the ready-made share text — to MSPs who'd benefit from Neo Agent. </Step> <Step title="They sign up with your code"> When they enter your referral code during onboarding, the two accounts are linked automatically and our team is notified. </Step> <Step title="They convert to a paid plan"> Rewards begin once the referred MSP **converts to a paid plan** — nothing is granted during their trial. This applies to both sides: the referred MSP's welcome bonus and your monthly credits both start at conversion. </Step> <Step title="Credits are granted automatically"> The moment they convert, both bonuses are granted automatically — no one has to apply anything. The referred MSP's one-time welcome bonus and your first month of credits land right away, and from then on your monthly credits refresh on their own each month for 12 months. </Step> </Steps> <Info> **When do rewards start?** After the referred MSP converts to a paid plan — not at signup or during their trial. Both the referred MSP's one-time bonus and the referrer's monthly credits are keyed to that conversion. </Info> ## Tracking your rewards Both sides can see their referral rewards in [**Billing**](https://dashboard.neoagent.io/billing): * **Referrers** see every MSP they've referred, trials included. For an MSP that moved to a paid plan, you see the credits it adds each month, the date they stop, and how many of the 12 months remain. For an MSP still in trial, you see when the trial ends and what you get once they pay. * **Referred MSPs** see who referred them and their welcome bonus, with the date to use it by. Your active referral credits are added on top of your plan's monthly credit limit, so you can spend them just like your regular plan credits. <Info> The whole flow is automatic: entering a code at signup links the two accounts, and both bonuses are granted the moment the referred MSP converts to a paid plan — nothing to claim or apply. From there the monthly credits refresh on their own. </Info> ## Frequently asked questions <AccordionGroup> <Accordion title="How much do I earn per referral?"> 1,500 credits per month for 12 months for each MSP you refer. The MSP you refer separately gets a one-time 2,500-credit welcome bonus, valid for their first 12 months. </Accordion> <Accordion title="Can I refer more than one MSP?"> Yes — there's no limit, and the monthly credits stack. Refer three MSPs and you earn 4,500 credits a month. Each referral has its own independent 12-month window. </Accordion> <Accordion title="When do the credits arrive?"> Both rewards start **the moment the referred MSP converts to a paid plan** — nothing is granted at signup or during their trial, and nothing needs to be claimed or applied. On conversion the referred MSP's one-time welcome bonus and the referrer's first month of credits are granted automatically and available immediately; the referrer's monthly credits then refresh on their own at the start of each calendar month for 12 months. </Accordion> <Accordion title="What happens after 12 months?"> Each referral's reward runs for 12 months from when it's applied, then stops. Any other active referrals keep running on their own clocks — referring more MSPs keeps your monthly credits topped up. </Accordion> <Accordion title="Do referral credits count toward my monthly limit?"> They raise it. Your active referral credits are added on top of your plan's monthly credit limit, giving you more to spend each month. </Accordion> <Accordion title="How do I track my referrals?"> Open the [Billing](https://dashboard.neoagent.io/billing) page in your dashboard. Referrers see every MSP they've referred, in trial or converted to a paid plan, and for each converted one the credits a month and the date they stop. Referred MSPs see their welcome bonus and who referred them. </Accordion> </AccordionGroup> ## Getting started <Steps> <Step title="Find your referral code"> Go to [**Settings**](https://dashboard.neoagent.io/settings) — your code is at the top of the page, and **Refer & Earn** next to it has the share text. </Step> <Step title="Share with other MSPs"> Send your referral code to MSPs in your network. </Step> <Step title="Watch the credits roll in"> Track every referral and the credits you're earning on the [Billing](https://dashboard.neoagent.io/billing) page. </Step> </Steps> <Info> The Neo Agent Referral Program terms are subject to change. Current participants will be notified of any changes that affect their existing referral relationships. </Info> # Roadmap & Updates Source: https://docs.neoagent.io/product/roadmap-and-updates Where feature requests go — post an idea, vote on someone else's, and see what shipped **Roadmap & Updates** is Neo's public feedback board. It is where feature requests belong: you post an idea, other MSPs vote on it, and the team works from what the votes say. Click **Help** at the bottom of the dashboard's left-hand menu, beside the credit meter, then **Roadmap & updates** — the same menu as Documentation and Discord. That link signs you straight in, so there is no second password. The board also lives at [feedback.neoagent.io](https://feedback.neoagent.io). Anyone can read the requests, the roadmap and the changelog there; to post, vote or comment, sign in there with your Neo account, the same Microsoft sign-in as the dashboard. ## What goes where A feature request and a support issue are different things, and they go to different places. | You want to say | Where it goes | | - | - | | "Neo can't do X yet — please build it" | **Roadmap & Updates.** Post it, and other MSPs can vote | | "Neo does X, but it's doing it wrong" | **Support.** Ask your Neo Support Agent, or your support chat | | "This is broken and it's blocking us right now" | **Support**, and say it's blocking | | "What shipped recently?" | The [changelog](https://feedback.neoagent.io/changelog), also on the same board | A support ticket is for something that is broken. Putting a feature request in one hides it from the people who would vote for it, so it belongs on the board instead. <Note> If something is both — a missing feature that is also blocking live work today — do both. Post the request on the board so it gets votes, and raise the blockage with support so someone looks at it now. </Note> ## Asking the Neo Support Agent for a feature When you ask your [Neo Support Agent](/chat-agents/neo-support-agent) for something Neo cannot do yet, it will: 1. Tell you plainly that Neo can't do it today, and explain the limit. 2. Point you at Roadmap & Updates, and suggest you search the board first — someone may have asked already. 3. Offer you a short write-up you can paste straight into the post. It will **not** open a support ticket for a feature request. If it does open a support ticket for you — because something is broken or blocking — it will call it a support ticket, not a feature request. ## Writing a post other MSPs will vote for The people reading your post are other MSPs deciding whether they have the same problem. Write it for them: * **What you were trying to do.** The job, not the screen. * **What happens instead.** Including the part you have to do by hand. * **Why it matters to your team.** How often it bites, and who it costs. Keep it short and keep it in plain words. You do not need to name settings, fields or workflow numbers — if the team needs that detail, they will ask. <Note> **Search before you post.** A vote and a comment on an existing request carry further than a second copy of it, because the votes stay on one post instead of splitting across two. </Note> ## What happens to your post The team reads the board and works from it. When a request ships, it appears in the [changelog](https://feedback.neoagent.io/changelog), and everyone who voted on the post is notified — so you find out without having to check back. # Scheduled Work Source: https://docs.neoagent.io/product/scheduled-work Schedule workflows and agents to run at specific future dates and times ## What is Scheduled Work? Scheduled Work lets you plan workflow and agent executions for the future. Instead of running a workflow immediately, you can schedule it to run at a specific date and time — perfect for tasks that need to happen later, like employee offboarding after a last day or follow-up actions after a waiting period. <Frame> <img alt="Scheduled Work list view showing pending and completed entries" /> </Frame> ## How It Works There are two ways to create scheduled work: ### 1. From the Dashboard You can manually schedule any **Triggered** workflow to run at a future time: 1. Go to **Scheduled Work** in your dashboard 2. Click **Schedule New Work** 3. Select the workflow you want to run 4. Pick the date and time for execution 5. Optionally link it to a ticket and add custom instructions ### 2. From an Agent Neo Agents can schedule work automatically using the **Trigger or Schedule Workflow** tool. This is powerful for multi-step processes where some actions need to happen later. <Tip> **Example:** An offboarding agent processes a termination request today, but schedules the account deletion workflow to run on the employee's last day — two weeks from now. </Tip> <Note> When a ticket names a future date, an agent holds back only the work that date applies to, such as disabling a leaver's account on their last day. Everything else its instructions ask for happens in the same run: classification, field updates, notes and time entries. An agent without the **Trigger or Schedule Workflow** tool cannot book the later run itself, so it notes when the dated work is due and escalates it per its instructions. </Note> ## Use Cases ### Employee Offboarding When processing a termination ticket, the agent can: * Immediately remove the user from sensitive groups * Schedule email forwarding setup for the last day * Schedule account deletion for 30 days after departure ### Follow-Up Actions * Schedule a customer satisfaction survey to send 3 days after ticket resolution * Schedule a check-in workflow to verify a fix is still working after a week ### Compliance & Auditing * Schedule security review workflows to run at specific compliance deadlines * Schedule recurring cleanup tasks at month-end ## Managing Scheduled Work From the dashboard, you can view and manage all scheduled work entries: | Status | Description | | - | - | | **Pending** | Scheduled but not yet executed — can be edited or cancelled | | **Processing** | Currently being executed | | **Completed** | Successfully executed | | **Failed** | Execution encountered an error | | **Cancelled** | Manually cancelled before execution | ### Editing Scheduled Work While an entry is **Pending**, you can: * **Reschedule** — Change the execution date and time * **Update Instructions** — Modify the additional instructions * **Cancel** — Stop the scheduled work from running <Warning> Once a scheduled work entry starts processing, it cannot be modified or cancelled. </Warning> ## What Workflows Can Be Scheduled? Only **Triggered** workflows can be scheduled. Scheduled workflows (those that run on a cron schedule) already have their own timing mechanism. To schedule a workflow, it must be: * **Enabled** — Disabled workflows cannot be scheduled * **Triggered type** — Only event-triggered workflows support scheduling ## Viewing Scheduled Work Details Each scheduled work entry shows: * **Workflow** — The workflow or agent that will run * **Scheduled For** — When it will execute * **Ticket** — The associated ticket (if any) * **Status** — Current state of the entry * **Created By** — Who scheduled it (dashboard user or agent) * **Additional Instructions** — Any custom instructions provided ## Best Practices <CardGroup> <Card title="Use Descriptive Instructions" icon="pen"> When scheduling work, add clear instructions so the executing agent knows the context — especially if weeks pass between scheduling and execution. </Card> <Card title="Link to Tickets" icon="ticket"> Always link scheduled work to the relevant ticket. This ensures the agent has full context when it runs. </Card> <Card title="Review Pending Work" icon="calendar-check"> Regularly check your pending scheduled work to ensure nothing is outdated or needs rescheduling. </Card> <Card title="Consider Time Zones" icon="clock"> Scheduled times are in UTC. Make sure you account for time zone differences when scheduling. </Card> </CardGroup> ## Related <CardGroup> <Card title="Trigger or Schedule Workflow" icon="clock" href="/agents/tools/management/trigger-or-schedule-workflow"> Learn how agents trigger or schedule workflows </Card> <Card title="Triggered Workflows" icon="bolt" href="/core/triggers-and-schedules/triggered-workflows"> Understand how triggered workflows work </Card> </CardGroup> # Sharing agents Source: https://docs.neoagent.io/product/sharing-agents Generate a public, read-only link to an agent, chat agent, or workflow — no Neo login required A public share link is a read-only view of one of your automations that anyone can open in a browser — no Neo account needed. Use it to show a prospect or a peer exactly what an agent does: its instructions, how it's triggered, and the tools it uses, laid out just like the builder. It works for **agents**, **chat agents**, and **workflows** alike. The link is a showcase, not a copy: viewers can read and copy the prompt, but they can't run the agent, edit it, or pull it into their own Neo tenant. <Warning> Your instructions, triggers, filters, and tool configuration become publicly visible to anyone with the link. Review them for anything sensitive before sharing — or use the [visibility toggles](#control-what-is-shown) to mask filter values and tool settings. </Warning> ## Where to find it The **Share** action lives anywhere an automation does: * **Agents & Workflows list** ([dashboard.neoagent.io](https://dashboard.neoagent.io/)) — open a row's **⋮** menu → **Share**. * **Chat agents list** ([Chat → Agents](https://dashboard.neoagent.io/chat?tab=agents)) — open a row's **⋮** menu → **Share public link**. * **The builder** — a **Share** button sits to the left of **Save** in the header, and to the left of **Update Agent** in the footer. A green **Shared** badge appears on any row that currently has a live link, so you can see at a glance what's published. <Info> The **Neo Support Agent** and other Neo-managed agents can't be shared — the option is hidden for them. A brand-new agent must be saved once before it can be shared. </Info> ## Create a link <Steps> <Step title="Open the Share dialog"> Click **Share** (or **Share public link**) from any of the surfaces above. </Step> <Step title="Create the public link"> Click **Create public link**. Neo mints an unguessable URL of the form `https://dashboard.neoagent.io/anonymous/agents/<token>`. </Step> <Step title="Copy or preview"> Use the **copy** button to grab the link, or the **open preview** button to see exactly what a recipient will see. </Step> </Steps> ## Control what is shown The dialog has three toggles. They take effect immediately — no need to regenerate the link. | Toggle | When on | When off | | - | - | - | | **Show attribution** | Credits your company by name on the shared page (prefilled with your company name; edit it freely). | No attribution shown. | | **Show filter values** | Reveals the values inside triggers and filters. | Masks those values, which may name a specific client. | | **Show tool configuration** | Reveals per-tool settings — recipients, approvers, PSA options. | Hides per-tool settings; viewers still see *which* tools are enabled. | ## What the recipient sees The public page renders the real builder, read-only: * **Overview** — the agent's instructions, with a **Copy prompt** button. Chat agents also show their audience (Internal vs end-user). * **Triggers & Filters** — how the automation fires (for triggered and scheduled agents and workflows). Chat agents have no triggers, so this tab doesn't appear for them. * **Tools & Settings** — the enabled tools and a coarse summary of integration permissions (read vs read/write). Workflows show their **Actions** pipeline here instead. ## Manage a link Reopen the Share dialog at any time to: * **Regenerate link** — rotates the token. The old URL stops working immediately; share the new one. * **Disable link** — removes the public link entirely. The page goes dark for anyone who had it. ## What is never shared Regardless of the toggles, the public page never exposes: * Credentials or secrets of any kind (PSA, Microsoft, RMM, etc.). * The model, reasoning settings, credit cost, or any billing detail. * Internal tenant, routing, or share-token identifiers. <Note> This is different from [granting a teammate access to an agent](/product/rbac) or sharing a chat session with a colleague — those keep everything inside your Neo tenant. A public share link is a no-login, read-only page for an outside audience. </Note> # Technician companies Source: https://docs.neoagent.io/product/technician-companies Send a company's tickets to a technician first, keep a technician away from a company, or limit a technician to a set of companies Dispatch reads three company rules on a technician. Each company in the first two lists can carry an optional note: * **Preferred companies**: Neo sends their tickets to this technician first. The technician still takes other tickets. * **Never assign from**: Neo does not send their tickets to this technician, unless the note names an exception. * **Only these companies**: the technician takes tickets from the preferred companies only. You set them on the [**Technicians**](https://dashboard.neoagent.io/profiles) page, in two places that edit the same rules: open a technician and go to **Companies**, or open the **Companies** tab to work one company at a time. ## Add a company <Steps> <Step title="Pick the company"> Under **Preferred companies** or **Never assign from**, select **Add** and pick the company from your PSA. A company can be in one list only. </Step> <Step title="Add a note (optional)"> Type a note for dispatch, such as "Only P1 and P2 tickets" or "Except P1 outages". The note saves when you leave the field. Dispatch reads it with the company. </Step> </Steps> A technician can have up to 30 companies. ## Work by company The [**Companies**](https://dashboard.neoagent.io/profiles?view=companies) tab lists every company that has a rule, with its preferred technicians and the technicians who never take its tickets, and each note. **One person** marks a company with a single preferred technician. Search by company or technician name, or filter to the companies with preferred technicians, with never-assign technicians, or with a preferred technician limited to their preferred companies. Select a company to change who takes its tickets, or select **Add a company** to start one. Add technicians under **Preferred technicians** or **Never assign**, add a note to each, then select **Save**. The save changes only that company; every technician's other companies stay. **Only these companies** stays on each technician's own **Companies** pane. A save that would leave a technician limited to their preferred companies with none is refused: turn the switch off on their profile first. ## Limit a technician to their companies Turn on **Only these companies**. You need at least one preferred company first. * In a [Dispatch Ticket](/building-automations/actions/ai/ticket-dispatch-suggest-technician) action, Neo removes the technician from the pool for a ticket from any other company, before it decides. A ticket with no company goes to other technicians. * If every technician in the pool is limited to other companies, the ticket stays unassigned and Neo sends a message to your inbox. * An agent that uses [Get Technician Context](/agents/tools/psa/get-technician-context) gets a warning from Verify Dispatch Decision when it picks the technician for another company. A note cannot add an exception to **Only these companies**. Turn it off if the technician takes some other tickets, and write the rule in a note. ## How dispatch uses the lists Dispatch shows each technician's companies and notes next to their name, on Dispatch Ticket actions and on agents that use Get Technician Context. It shows them when the **Profile** setting of the Dispatch Ticket action is off too. Neo reads the preferred and never-assign lists as rules, together with the notes. A Dispatch Ticket action that uses **round robin** reads no notes. It skips a technician who never takes the ticket's company, and it tries the technicians who prefer that company first. If a rule is in both a list and the technician's custom instructions, keep it in one place, so dispatch reads one rule. ## Ask Neo to set it up The Neo Support Agent can set the companies for you, for example: "Make Harbor Dental Group a preferred company for Alex, only for P1 and P2 tickets." It can also move company rules from a technician's custom instructions into the lists. By default it asks for approval before each change. Companies are also in the [public API](/developers/introduction): `PATCH /public-api/technicians/<id>` per technician, and `GET /public-api/technicians/companies` and `PUT /public-api/technicians/companies/<psa_company_id>` per company. # Technician groups Source: https://docs.neoagent.io/product/technician-groups Name a set of technicians once, such as Tier 1 Helpdesk or On-call rota, then pick the group in dispatch and name it in custom instructions A **group** is a named set of technicians with one line on what it is for, such as "Tier 1 Helpdesk: first line for every new ticket" or "On-call rota: out of hours". Use groups for tiers, teams and rotas: a tier is simply a group. You manage groups on the [**Technicians** → **Groups**](https://dashboard.neoagent.io/profiles?view=groups) tab. ## Create a group <Steps> <Step title="Name it"> Select **New group**, give it a name, and describe in one line what it is for. Dispatch reads that line next to each member's name. </Step> <Step title="Write its instructions"> In **Instructions for dispatch**, write how dispatch should use the group, such as who takes P1 tickets, out-of-hours rules, or tickets the group never takes. Up to 4,000 characters. </Step> <Step title="Add members"> Tick the technicians who belong to it. You can also add someone from their own card: open the technician, go to **Groups**, and tick the group. </Step> </Steps> A technician can be in several groups. The **Groups** tab flags a group with **One person**: when that person is away, the group has no one else to take its tickets. ## Pick a group in dispatch In a [Dispatch Ticket](/building-automations/actions/ai/ticket-dispatch-suggest-technician) action, select **Choose technicians and groups**, then add groups in the **Technicians and groups** picker, next to any technicians you pick one by one. The list under the picker shows who is in the pool. On every run, the group's current members join the pool, so a person you add to the group later is included without editing the workflow. The **Groups** tab shows which workflows use each group under **Used by**, and counts the ones you cannot view here, such as workflows in another environment. Check it before you delete a group: a workflow that still names a deleted group gets no one from it. ## Group instructions Dispatch reads a group's instructions once per run, when one of its members is a candidate for the ticket. Write rules about a team here, in place of repeating them in each technician's custom instructions or in the dispatch instructions. A technician's own custom instructions still win over the group's. ## Name a group in custom instructions Dispatch sees each technician's groups next to their name, on Dispatch Ticket workflows and on agents that use [Get Technician Context](/agents/tools/psa/get-technician-context). So you can write rules such as "Send ransomware tickets to Tier 3 Escalations" or "After 18:00, assign only the On-call rota". An agent that reads "choose from Tier 1 Helpdesk" looks up your groups, matches the one you mean by its name and description, and asks Get Technician Context for that group alone, so it reads only those members' calendars and workload. Neo applies them together with the rest of your instructions; it does not route by group on its own. ## Ask Neo to set it up The Neo Support Agent can create groups, change their members and write their instructions for you, for example: "Make a group called Weekend cover with Casey and Finley." or "Move the Tier 2 rules from our dispatch instructions into the Tier 2 group." By default it asks for approval before each change. Groups are also in the [public API](/developers/introduction) under `/public-api/technician-groups`. # Technician Profiles Source: https://docs.neoagent.io/product/technician-profiles How Neo learns each technician's expertise — and uses it to assign the right tickets Neo keeps a short **profile** for each of your technicians describing what they're good at, so when it dispatches a ticket it can match the work to the right person. You manage these on the [**Technicians**](https://dashboard.neoagent.io/profiles) page. ## How a profile is built Neo writes each profile automatically — you don't fill it in: * When a technician is added — either directly on the **Technicians** page or by including them in a **Dispatch** workflow — Neo reads their **resolved and closed tickets** and summarizes the kinds of issues, technologies, and customers they handle well. * Neo **refreshes** profiles automatically over time as technicians close more tickets, so they stay current with no manual upkeep. * A profile can take a little while to appear after you add someone. Neo can only summarize the tickets it has synced from your PSA, and the first sync covers recent activity — so tickets resolved before you connected Neo may not be included. * A technician shows **No resolved tickets synced** when Neo has none of their resolved tickets to summarize. Their profile fills in once they resolve tickets Neo has synced. If someone has older history you want Neo to learn from, ask us to sync a longer period. You can also shape a profile yourself: * **Edit** the profile text directly. * Add **Custom Instructions** — notes that always take precedence over the generated profile (for example, "Never assign onsite work" or "Prefers networking tickets"). AI dispatch with **Include AI profile** on also reads them over a dispatch instruction that covers every technician, such as a lowest-workload rule, for this technician. * Turn **Automated Updates** off if you'd rather Neo never change a profile you've hand-written. <Info> Custom instructions are preserved whenever Neo refreshes a profile — your notes are never overwritten. </Info> <Warning> **Dispatch skips a technician whose profile is not ready while Automated Updates is on.** A technician with **No resolved tickets synced** stays not ready until they resolve a ticket and a later sync builds their profile. When dispatch is how they would get their first tickets, turn Automated Updates off and write the profile yourself. Neo never replaces it, and custom instructions stay. </Warning> <Warning> **Automated Updates off also means no first profile.** Neo only builds profiles for technicians with the setting on, so a technician who has it off and no profile yet stays that way — the technician's card shows **Profile not ready**, and dispatch skips them. Turn it on and Neo builds their profile on its next sync. </Warning> ## Skills and certifications Alongside the AI profile, Neo also **syncs the skills and certifications you've already recorded in your PSA** and weighs them when choosing who to assign: * **ConnectWise** — member **skills and certifications** * **Autotask** — resource **skills** (Autotask has no certifications) * **Halo / ServiceNow** — no skills are read; dispatch relies on the AI profile These sync automatically — there's nothing to enter in Neo. To change them, update the technician's record in your PSA and Neo picks up the change on its next sync. You'll find them on the **Skills** pane of each technician. ## Managing technician profiles Open [**Technicians**](https://dashboard.neoagent.io/profiles) in the dashboard. The **Team** tab shows one card per technician: their groups, skills, schedule and time zone, their Teams app status, and what needs attention for dispatch. A green **Teams installed** mark shows that their Microsoft account has the Neo AI Agent app, which delivers notifications and approval cards. Above the cards: * **Search** by name, skill, group or company, and filter by **group** or by **hours**: on a Neo schedule, or no Neo schedule. * **Teams app** shows everyone, or only the technicians whose app is **Installed**, **Not installed**, or who have **No Microsoft account** linked. * **Needs attention** names each reason that applies to someone on your roster, with a count: **Profile not ready** (dispatch skips them until Neo builds their profile from resolved tickets it has synced), **Inactive in PSA** (dispatch skips them), and **Hours in instructions** (they are on a schedule and their custom instructions also state hours). Select a reason to see only those technicians. * **Sort** by name, or put the technicians who need attention first. The line under the filters says how many technicians show, with a chip for each active filter. The filters are in the page link, so you can share a filtered view. **Add Technician** lists the technicians in your PSA who have no profile yet. A technician whose name matches, one to one, a Microsoft account that has the Neo AI Agent app and no technician yet is listed first, marked **Uses Teams**. Select a card to open everything you can set for that technician: * **Profile & instructions**: the generated summary, the **Update automatically** switch, and your custom instructions. Changes save as you go. * **Groups**: the [technician groups](/product/technician-groups) they belong to. * **Companies**: the [companies](/product/technician-companies) whose tickets go to them first or never, with a note for dispatch. * **Working hours**: hours from your PSA, a shared schedule, or hours for this technician only. See [Technician working hours](/product/technician-working-hours). * **Skills**: the skills and certifications synced from your PSA. * **Microsoft**: links the technician to their Microsoft account so dispatch can also weigh their live Teams presence and shifts. Pick the person from the list of people who use Neo in Teams or the dashboard, or type the Entra object ID. After each technician sync, Neo links a technician whose name exactly one Microsoft account shares; clear the link to keep a technician unlinked. See [Teams Technician Mapping & Availability](/integrations/teams/workforce-availability). <Tip> If a technician's custom instructions still state their working hours after you give them a schedule, the card and the profile pane say so. Select **Ask Neo to tidy this up** and the Neo Support Agent suggests the instructions without the hours, then asks before it saves. </Tip> ## How Neo uses profiles When a dispatch agent assigns a ticket, it brings each candidate's profile, skills, certifications, current workload, and availability together to pick the best fit. For the full picture of what dispatch considers, see [Get Technician Context](/agents/tools/psa/get-technician-context). # Technician working hours Source: https://docs.neoagent.io/product/technician-working-hours Set each technician's weekly hours, breaks and shifts in Neo, so dispatch reads the hours you set instead of your PSA calendar A **schedule** is a named set of weekly hours, such as "Day shift" or "Nights". You put each technician on one schedule, and dispatch then reads that technician's hours from it. Use it when your PSA has no working hours, when its hours are out of date, or when the hours you need are hard to keep in the PSA. You manage schedules on the [**Technicians** → **Schedules**](https://dashboard.neoagent.io/profiles?view=schedules) tab, and each technician's hours on their card. ## Hours from your PSA For a technician on no schedule, the card shows the hours dispatch reads and names where they come from: a calendar in your PSA, or one of the fallbacks below. The **Schedules** tab lists the PSA calendars under **From** your PSA, one card for each calendar. A PSA calendar's hours are read-only in Neo: change them in your PSA, and the change reaches Neo within a day. You do not need to copy them into schedules. | PSA | Where the hours come from | | - | - | | ConnectWise | The calendar on the member | | Autotask | The business hours of the resource's internal location, or of your default location when the resource has none | | Halo | The agent's Work Day | | Syncro | The account's business hours, the same for every technician | | ServiceNow | None. Put the technician on a schedule to give dispatch their hours | In every PSA but ServiceNow, when the PSA has no calendar for a technician who is active there, dispatch uses your account's default business hours, Monday to Friday, and the card shows **Neo default hours**. ## Set up schedules <Steps> <Step title="Create a schedule"> Select **New schedule**, give it a name, and pick a starting point such as **Mon–Fri 09:00–17:00**, **Mon–Fri with lunch** or **Nights 21:00–06:00**. Then adjust each day. </Step> <Step title="Adjust the week"> * Switch a day off for a day the technician does not work. * Use a day's **Add a break** button to split it around a lunch break, then move the times. * Use **Copy Monday to weekdays** to give Monday's hours to Tuesday through Friday. Each day's copy button copies that day instead. * An end time before the start time is a night shift. The editor marks it **Ends next day**. </Step> <Step title="Put technicians on it"> Open a technician's card and go to **Working hours** to choose a schedule. To move several technicians at once, use **Choose technicians…** on the schedule's card on the **Schedules** tab. </Step> </Steps> Make one schedule for each set of hours your team works. When the day shift changes, edit that one schedule and every technician on it moves with it. A technician with hours of their own gets a schedule with only them on it. ## Time zones By default a schedule's times are on each technician's own clock: the time zone set for them in your PSA. If a team works to a clock that is not their own, for example a remote technician who works US Central hours, pick a **Time zone** on the schedule. Neo converts the hours to each technician's clock before dispatch reads them. ## What dispatch reads | Technician | Hours dispatch reads | | - | - | | On a schedule | The schedule's hours, in place of the PSA working hours | | Not on a schedule | The [hours from your PSA](#hours-from-your-psa), as before | | Not on a schedule, and the workflow has **Should Neo respect PSA working hours?** off | The hours in your custom instructions, as before | A schedule applies whether that workflow setting is on or off, on [Dispatch Ticket](/building-automations/actions/ai/ticket-dispatch-suggest-technician) workflows and on agents that use [Get Technician Context](/agents/tools/psa/get-technician-context). Dispatch sees which schedule the hours came from. It also applies on a Dispatch Ticket workflow with calendar checking off, when Neo picks the technician (not in Round Robin mode): dispatch then reads the schedule's hours alone, with no calendar entries. A schedule replaces only the weekly hours. Time off, holidays, calendar entries and Microsoft Teams presence still count exactly as before. <Tip> Once a technician is on a schedule, remove the hours you wrote about them in custom instructions, so dispatch reads one set of hours. A technician's card shows **Instructions mention hours** when their custom instructions still state hours, and **Ask Neo to tidy this up** hands the edit to the Neo Support Agent. Keep a rule for a window on one day, such as "on-site Wednesdays 8 AM to 1 PM, only Contoso tickets", in the instructions: a schedule cannot hold it. </Tip> ## Ask Neo to set it up The Neo Support Agent can read and change schedules for you. For example: "Move the working hours in our dispatch instructions into schedules." It can also tell you which hours dispatch reads for a technician. It shows you the schedules and who goes on each before it saves anything, and by default it asks for approval before each change. Schedules are also available in the [public API](/developers/introduction) under `/public-api/technician-schedules`, and each technician's PSA hours under `/public-api/technician-schedules/psa-hours`. # Train Neo Source: https://docs.neoagent.io/product/train-neo Refine AI performance through feedback to improve workflow accuracy and outcomes Training Neo lets you refine and improve the AI's understanding and performance for your specific workflows and agents. When a run should have gone differently, click **Train** on that run: it opens a conversation with the **Neo Support Agent** (in Smart mode) with the run's details attached to the message box as a **training card**. Describe what should have happened, or send the card on its own. Neo reads the run and the approval decisions your technicians made on it, proposes the one change that would have made the run go right, and applies it once you confirm. ## Why Train Neo? * **Enhance AI Accuracy**: Teach Neo how to better interpret situations and data specific to your environment * **Tailor Workflow Behavior**: Guide Neo to make decisions and take actions that align more closely with your business processes and preferences * **Improve Automation Outcomes**: Get more precise and effective results from your automated workflows by refining the AI's instructions, and by spotting what an agent was missing * **Iterative Improvement**: Continuously make Neo smarter and more helpful through an interactive feedback loop <Tip> Most of the time the change is to your **custom instructions** — for a workflow, the instructions of its actions; for an agent, the agent's own instructions. Neo shows you exactly what it plans to change and why before anything is written, and it makes a surgical edit rather than rewriting your instructions wholesale. You can always update custom instructions manually in the editor instead. </Tip> Not every run is fixed by an instruction. An agent that could not finish because it was missing a tool, or an access level on one of your integrations, cannot be instructed out of that gap. Neo checks what you could still switch on for that agent before it answers, so it can name the tool or the permission instead of writing a rule about the limit. It can also propose a [memory](/core/memory) when the run only went wrong because Neo did not know something about that client. <Note> Train Neo is for runs that should have gone **differently** — your feedback, and your technicians' approval decisions, turn into better instructions. For a run that went **right** and that you want repeated identically, use the **Skillify** button on that run instead to capture it as a [skill](/agents/skills/creating-skills). </Note> ## How It Works 1. **Identify an Execution**: Find the past run where the outcome could have been better 2. **Click Train**: The Neo Support chat opens with a training card attached to the message box showing the agent, ticket, and run 3. **Add Feedback, or Just Send**: Type what went wrong, or what Neo should have done instead, and send. Feedback is optional: send the card on its own and Neo reviews the run by itself 4. **Neo Investigates**: The Neo Support Agent reads the run's step-by-step trace, the approval decisions technicians made on it, the configuration the run actually used, the ticket context, and its final output, alongside any feedback you gave. When the run paused for approvals, it reads every part of it — see [A supervised run is several runs](#a-supervised-run-is-several-runs) 5. **Review the Proposed Change**: Neo shows you the one change it wants to make and why — the exact instruction text and where it will sit, or the tool, permission or memory the run needed — before writing anything 6. **Confirm and Apply**: Once you agree, Neo applies it. Future runs use the updated configuration Because this is a conversation, you can push back, refine the wording, or ask Neo to take a different angle before anything is applied — and ask follow-up questions afterwards. ## Step-by-Step Guide to Training Neo Let's walk through an example using feedback on a "Triage" workflow run. ### Navigate to Workflow Executions From the Neo Agent dashboard, go to **Workflows**. You'll see a list of your "Triggered Workflows". Identify the workflow you want to improve (e.g., "Triage"). Click the history icon for that workflow to open its executions. <Frame> <img alt="Opening an agent's executions from the Workflows list" /> </Frame> ### Select a Specific Event Execution You'll be taken to the [Executions](/product/executions) page filtered to that agent. Filter by ticket number or ticket ID to find the run you want to give feedback on, then click **Train** on that row. <Frame> <img alt="Selecting a specific event execution and clicking the Train button" /> </Frame> ### Provide Your Feedback The Neo Support chat opens with a training card attached above the message box, showing which agent, ticket, and run you're training on. The message box takes your feedback — type specific details about what Neo should have done differently or what it missed, then send. The run details from the card ride along with your message automatically. The more context you provide, the better Neo can learn. **Example Feedback:** "This ticket should have 'Printer' type because it's related to the HP device in room 2." ### Or Send Without Feedback Feedback is optional. Send the card with an empty message box, and Neo works out what to change from the run itself: * **Approval decisions**: a change a technician rejected, a note they left on a card, and on a [supervised run](/core/supervised-mode) the plan they commented on and the choice they picked when the instructions left a decision open. When the agent asked about an unclear instruction, Neo starts from the wording the agent suggested and fits it to the technician's answer. * **The run's own trace**: tool errors, reasoning that weighs two readings of an instruction, and a final message that does not answer what the ticket asked. If nothing in the run went wrong, Neo says so and names what it checked. ### A supervised run is several runs Every time the run stops to wait — for your answer, or for a script to finish on a device — it ends there, and what follows is a new run. Its reasoning is spread across all of them. The [Execution Log](/product/executions#execution-log) already shows all of them as one flow, and Train reads them the same way — the whole execution, in order, whichever part you clicked Train on. A run that never paused is unaffected. ### Review the Proposed Change Neo investigates the run — its step-by-step trace, the instructions it ran under, the ticket, and what that agent could still be given — and replies with a concrete proposal, plus the evidence from the run that motivates it. **Example proposal:** "The triage step set `type` to None because nothing in the instructions covers printer hardware. I'd add one rule to the Ticket Triage action's instructions: *'If the ticket references printer hardware (e.g. an HP device, printer model, or print room), set the type to Printer.'* Want me to apply that?" **Example proposal when the agent was missing something:** "This run stopped at the mailbox reset and escalated instead, because that agent has no Exchange access. Exchange Mailbox Management is available on your account and switched off for this agent. Resetting a mailbox is a change, so it needs read/write — read-only would leave the next one stuck in the same place. Want me to apply that?" Review the proposal, and refine it in the conversation if you want it worded differently or scoped more broadly or narrowly. When Neo proposes a tool or a permission, it also tells you anything that comes with it — for example that enabling a tool can raise what that agent costs per run. When a proposed edit narrows an existing rule (it removes words from the rule, or adds a condition to it), Neo names the kinds of ticket the rule would stop covering and asks whether to keep them. To fix one ticket, Neo prefers an exception beside the rule, so the rule keeps covering every ticket it did before. If you later ask Neo why an agent's behaviour changed, it checks the agent's [version history](/building-automations/managing-workflows/version-history) for an edit to the rule that decided the run. It names any such edit, when it was saved and who saved it, before it says the wording of your tickets caused the change. That includes an edit Neo made in an earlier conversation: Neo says the edit was saved through the API for the person in that chat, the way a Neo Support chat saves, and not in the dashboard. ### Confirm and Apply Reply to confirm, and Neo applies the change. For an instruction edit, Neo shows you each sentence it adds or changes, and it can write only the text it showed you in the conversation — it cannot apply a rule you haven't seen. When a rewrite would drop a rule, default or condition from your instructions, Neo saves the edit only if it showed you that sentence as it stands now, or if the change you approved itself rewrites, removes or overrides that rule. It does not repeat the unchanged text around a change, even when that text is on the same line. A small wording difference that does not change what the agent does, such as a synonym, punctuation or formatting, usually needs no second confirmation; any change to a condition, a limit, a name or a step does. Every change of one edit must appear together in one message, so one confirmation applies the whole edit. An instruction edit changes only the targeted text — everything else in your instructions is left untouched. Neo confirms once it's done, and the agent uses the updated configuration on future runs. ## Important Considerations * **Usually Custom Instructions**: Most runs are fixed by the plain-English `custom_instructions` guidance on your workflow actions or agent * **Sometimes Something Else**: A tool the agent does not have, an integration permission, a fact worth remembering, a trigger filter, or a missing action. Neo checks what that agent could still be given before it answers, so it names the switch rather than writing a rule about the limit * **When the Problem Is on Neo's Side**: Sometimes a run goes wrong because of Neo itself, not your setup — for example, Neo ignored an event that should have started the agent. Neo tells you so, shows the evidence, and offers to raise it with the Neo support team. It does not ask you to write an instruction that works around it * **When the Rule Was Already There**: Before Neo suggests a new rule, it reads the instructions the run had. If they already forbade what the run did, Neo tells you so, because repeating the rule rarely changes the next run. It looks for what made the agent miss the rule, such as a rule that contradicts it, and offers to fix that. When the rule keeps a whole kind of ticket out of the agent's work, such as domain expiry alerts, and a ticket field marks that kind (its type, subtype, board or a phrase in the summary), Neo offers to exclude those tickets in the [trigger filter](/core/filter-tickets) of the Workflow or triggered Agent instead. The filter is checked before the AI reads a ticket, so it does not rely on the AI to follow a rule. When the rule only lists when to set a field, such as when to set a ticket to Complete, and says nothing about every other ticket, the agent still decides that field on the other tickets. Neo checks whether the run could keep the current value. When it could, Neo offers one line that says what to do with the other tickets, for example "For every ticket that matches none of the rules above, keep the current status." When the run's record shows it had to pick a new value, Neo explains that no line stops the change. Neo counts a rule as one the run had only when it finds a record of that run's instructions, and tells you when it cannot confirm one. If it finds nothing in your setup that explains the miss, it offers to raise it with the Neo support team. You can still ask for a temporary rule while the escalation is open * **One Change at a Time**: Neo proposes the single change that covers the class of case, not a list * **Manual Updates**: You can always edit the custom instructions, the toolbox or the integration permissions for any agent directly in the editor if you prefer * **Context is Key**: Feedback is optional, but clear, specific feedback helps when the run carries no approval decisions to learn from * **Iterative Process**: Training Neo is an ongoing process. The more feedback you provide over time, the more aligned Neo will become with your specific operational needs <Tip> The more you interact with and guide Neo, the smarter and more helpful it becomes. </Tip> # Alert P1 Tickets Source: https://docs.neoagent.io/recipes/alert-p1-tickets Instantly notify your team when critical priority tickets are created ## Setup <Steps> <Step title="Create the workflow"> Navigate to **Workflows** and create a new workflow. Name it "Alert P1 Tickets" and select **Triggered** as the workflow type. Set the trigger to **Ticket Created** to run immediately when new tickets arrive. <Frame> <img alt="Creating a triggered workflow named Alert P1 Tickets" /> </Frame> <Tip> Enable "Run Workflow only once per ticket" to prevent duplicate alerts if the ticket is updated shortly after creation. </Tip> </Step> <Step title="Configure priority filter"> Scroll down to the **Filter Tickets** section and add a rule: * Field: **Priority.Name** * Condition: **equals** * Value: Your critical priority name (e.g., "Priority 1 - Emergency Response", "Critical", or "P1") <Frame> <img alt="Setting up priority filter for P1 tickets" /> </Frame> <Note> Priority names vary by PSA system. Check your PSA configuration to use the exact priority name for critical tickets. </Note> </Step> <Step title="Add Build Message action"> Click **NEXT** to proceed to the Action step. Select **SMART ACTION** and choose **Build Message** as the action type. Configure the message: * Provide instructions describing what the alert should contain (e.g., "This should be an alert for P1 Tickets. Include ticket information such as company and contact.") * Set **Output message type** to **INTERNAL** <Frame> <img alt="Build Message action configuration" /> </Frame> Example message instructions: ``` Create an urgent P1 alert message that includes: - Clear "CRITICAL ALERT" header - Ticket number and subject - Customer/company name - Contact information - Brief issue summary - Direct link to the ticket ``` </Step> <Step title="Configure team notifications"> Add a **Notify Internal Team** action to send alerts to your team. Select **Teams** as the notification channel. <Frame> <img alt="Notify Internal Team action with Teams channel" /> </Frame> You have two options for Teams notifications: **Option 1: Notify specific users** * Select individual team members from the **Users** dropdown * Each user must have the Neo AI Agent Teams app installed **Option 2: Notify a Teams channel or chat** * Add the Neo app to the channel or chat, then pick it in the **Teams channels & chats** field * Use this option to alert a dispatch or escalation channel <Tip> Need a different responder list after hours? Build a second copy of this workflow with the other recipients, then give each copy an execution window (**Only run during these hours**, plus a timezone). A trigger event that fires outside a workflow's window is ignored — see [Triggered workflows](/core/triggers-and-schedules/triggered-workflows#execution-window). </Tip> <Info> For Teams setup instructions, see the [Microsoft Teams integration guide](/integrations/teams/intro). </Info> </Step> </Steps> ## Teams notification setup <AccordionGroup> <Accordion title="Individual user notifications"> Each user who needs to receive P1 alerts must: 1. Install the Neo AI Agent Teams app from Microsoft AppSource 2. Send a few messages to the Neo app to establish the conversation 3. They will then appear in the Users dropdown in Notify actions See the full setup guide: [Microsoft Teams - Install the app](/integrations/teams/intro#install-the-app) </Accordion> <Accordion title="Channel & chat notifications"> To post alerts to an entire Teams channel or group chat: 1. Add the **Neo AI Agent** app to the channel's Team (or to the group chat) - once per Team 2. In the Notify Internal Team action, set the channel to **Teams** 3. Choose the channel or chat from the **Teams channels & chats** field Neo posts as a message from the Neo app; no email connector is needed. See the full setup guide: [Microsoft Teams - Post to a Teams channel or chat](/integrations/teams/intro#post-to-a-teams-channel-or-chat) </Accordion> </AccordionGroup> # Assign Technician - Adding Schedule Entry Source: https://docs.neoagent.io/recipes/assign-technician-adding-schedule-entry Assign a technician and automatically create a schedule entry for work <Info> This is a Triggered workflow designed for tickets that need scheduled attention rather than immediate pickup. </Info> ## How it works * Selects a technician using your assignment rules * Books the entry on the selected technician's PSA calendar, linked to the ticket, with the duration and description you set * Assigns the ticket and leaves an internal note ## Setup <Steps> <Step title="Create the workflow"> Name it "Assign Technician - Adding Schedule Entry" and set the type to Triggered. </Step> <Step title="Configure filters"> Target boards/queues and priorities where scheduling is preferred (e.g., low/medium priority). </Step> <Step title="Add Dispatch Ticket"> Choose a technician pool. Enable workload balancing and calendar checks. </Step> <Step title="Enable Add schedule entry"> There is no separate schedule entry action. Turn on the **Add schedule entry** option on the same **Ticket Dispatch** action — it is available for ConnectWise, Autotask, and HaloPSA. Set duration (e.g., 60–90 minutes), add a clear subject, and include the ticket number in the entry. </Step> <Step title="Add Ticket Note and Assign Ticket"> Explain that the ticket was scheduled and assigned automatically. </Step> </Steps> ## Best practices * Route urgent tickets to immediate assignment recipes instead # Assign Technician - Basic Source: https://docs.neoagent.io/recipes/assign-technician-basic Automatically assign unassigned tickets to the best available technician <Info> This is a Triggered workflow that runs when tickets become unassigned or are created without an owner. </Info> <Tip> Prefer technicians to **pull** their own work on demand instead of Neo pushing it? See [Self-serve ticket dispatch](/recipes/technician-self-serve-dispatch). They ask Neo for their next ticket in Teams. </Tip> ## How it works * Triggered when tickets match your unassigned criteria * Evaluates technician workload, skills, and availability * Adds an internal note and assigns the ticket ## Setup Test with a subset before enabling broadly. <Steps> <Step title="Create the workflow"> Name it "Assign Technician - Basic" and set the type to Triggered. </Step> <Step title="Configure filters"> Filter for unassigned tickets using your PSA conditions. </Step> <Step title="Add Dispatch Ticket"> Select a technician pool. Enable checks for calendar, workload, and skills. Use workload threshold \~3. </Step> <Step title="Add Ticket Note and Assign Ticket"> Document the automatic decision and complete the assignment. </Step> </Steps> ## Variations ### Board-specific assignment Configure different technician pools and criteria per board (Help Desk, Infrastructure, Projects). ### Priority-based rules Use stricter balancing and senior pools for urgent tickets. ### Time-based rules Use business-hours vs after-hours pools and thresholds. # Assign Technician - Manage Calendar Source: https://docs.neoagent.io/recipes/assign-technician-manage-calendar Automatically assign tickets while honoring technician calendar events and availability <Info> This is a Triggered workflow that runs when tickets meet your assignment criteria. </Info> ## How it works * Checks technician calendars for conflicts and availability windows * Balances workload across the eligible pool * Chooses the best match and assigns the ticket ## Setup <Steps> <Step title="Create the workflow"> Name it "Assign Technician - Manage Calendar" and set the type to Triggered. </Step> <Step title="Configure filters"> Select boards/queues and conditions where automatic assignment is appropriate. </Step> <Step title="Add Dispatch Ticket"> Pick a technician pool. Enable calendar awareness and set a reasonable workload threshold (e.g., 3–5 active tickets). </Step> <Step title="Add Ticket Note and Assign Ticket"> Document the decision (calendar-aware assignment) and complete the assignment. </Step> </Steps> # Assign Technician - Oversee Board Source: https://docs.neoagent.io/recipes/assign-technician-oversee-board Scheduled oversight to catch and assign unassigned tickets on specific boards ## Overview Continuously monitor selected boards for unassigned tickets and automatically assign them to appropriate technicians. <Info> This is a Scheduled workflow that runs at regular intervals and complements your triggered assignment workflows. </Info> ## How it works * Runs every hour * Finds unassigned tickets on specific boards * Sends them over to trigger Dispatch workflow ## Setup <Steps> <Step title="Create the workflow"> Name it "Assign Technician left unassigned" and set the type to Scheduled. Choose the interval (e.g., every 1 hour). </Step> <Step title="Configure filters"> Filter for target boards and unassigned tickets. </Step> <Step title="Add Trigger Another Workflow"> Pick the target Triggered Workflow. Set bypassing of filters depending on whether you want double filtering. </Step> </Steps> <Tip> You can set the schedule workflow to run only once in the morning instead of hourly for less frequent oversight. </Tip> # Automate Dark Web Alert Tickets Source: https://docs.neoagent.io/recipes/automate-darkweb-alerts Automatically triage dark web alert tickets, notify end users, and close/update tickets with the correct status using two sequential workflows <Info> If your dark web alerts always enter a dedicated queue/board, you can rely on the workflow trigger or filtering by that queue and skip explicit "is this dark web?" checks. If not, add a brief detection step in the triage instructions to confirm it's a dark web alert before proceeding. </Info> ## Workflow 1: Triage Company and Contact ### Basic Configuration <Steps> <Step title="Create the workflow"> * **Name:** "Dark Web Alert - Triage" * **Type:** Triggered * **Trigger Conditions:** * Ticket created </Step> <Step title="Add Ticket Triage action"> **Action: Ticket Triage** Focus fields: Company, Contact (and optionally Type/Subtype if you want) This action will identify the correct Company and Contact from the alert details. </Step> <Step title="Add Update Ticket Fields action"> **Action: Update Ticket Fields** Add this action in the Write to PSA section so Company and Contact are set in your PSA. <Tip> When first enabling, you can start with an `Add Ticket Note` action to log what would have been applied, then switch to `Update Ticket Fields` once confident. </Tip> </Step> </Steps> ## Workflow 2: Build Message and Close/Update Status ### Basic Configuration <Steps> <Step title="Create the workflow"> * **Name:** "Dark Web Alert - Notify and Close" * **Type:** Triggered * **Trigger Type:** Add "Workflow Finished" trigger and select the previous Triage workflow </Step> <Step title="Add Build Message action"> **Action: Build Message** * Message Type: Customer Facing * Instructions (plain English; describe the style and content, not a fixed template): ``` Create a clear, concise message to the end user acknowledging the dark web alert. Include: - A brief explanation of what the alert means in non-technical terms - Any immediate recommended steps (e.g., reset password, enable MFA) - Reassurance on next steps and that we are monitoring - Keep professional, calm, and helpful tone ``` </Step> <Step title="Add Update Ticket Fields action"> **Action: Update Ticket Fields** * Add Update Ticket Fields in Write to PSA section * Mark the checkbox "Update Additional Fields" * A dropdown for the New Status will appear * Select the new `Status` (e.g., "Customer Notified" or "Closed - Notified") to move the ticket to </Step> <Step title="Add Notify Ticket's Contact action"> **Action: Notify Ticket's Contact** * Uses the message generated by `Build Message` * Selects the ticket contact as the recipient </Step> </Steps> ## Tips * Start with note-only runs to validate messaging and status changes * Need different wording for one client? Pin a [company memory](/core/memory) for them. Pinned memories are included when a workflow's Smart Actions run for that company. # Analyze Customer Sentiment Source: https://docs.neoagent.io/recipes/customer-sentiment-analysis Detect negative sentiment and alert management with weekly summaries Store sentiment and reasoning on tickets, then use Negative results to alert management and report on recent cases. ## Workflow 1: Analyze and store sentiment <Steps> <Step title="Create a triggered workflow"> Run on ticket creation and when customers reply. </Step> <Step title="Analyze sentiment"> Use the Analyze Customer Sentiment action. Save the result and reasoning so you can use it later. </Step> <Step title="Update ticket fields"> Store the sentiment and reasoning on the ticket for reporting and follow-up. </Step> </Steps> ## Workflow 2: Alert on negative sentiment <Steps> <Step title="Create a triggered workflow"> Run after Workflow 1 finishes. </Step> <Step title="Filter for negative cases"> Only continue when sentiment is Negative. </Step> <Step title="Build alert message"> Create a concise internal alert with ticket number, company, contact, and reasoning details. </Step> <Step title="Notify management"> Send via Teams or Email. </Step> </Steps> ## Workflow 3: Weekly summary <Steps> <Step title="Create a scheduled workflow"> Run every Monday at 9 AM. </Step> <Step title="Filter recent negatives"> Find tickets with Negative sentiment closed in the last 7 days. </Step> <Step title="Create report"> Generate a table grouped by resource with counts and ticket links. </Step> <Step title="Email the report"> Send to management. </Step> </Steps> # Disable Inactive M365 Accounts Source: https://docs.neoagent.io/recipes/disable-inactive-m365-accounts Automatically find and disable M365 accounts with no sign-in activity for 90+ days ## Overview This recipe creates a scheduled agent that checks for inactive M365 user accounts across your connected tenants. Accounts with no sign-in activity for 90+ days are flagged and, after technician approval, disabled. <Info> This is a **scheduled agent** — it runs on a cadence without processing a specific ticket. See [Scheduled Agents](/core/scheduled-agents) for how this works. </Info> ## How it works * Agent runs weekly and queries sign-in activity across connected M365 tenants * Accounts inactive for 90+ days are identified (excluding service and break-glass accounts) * Agent requests **Technician-in-the-Loop approval** before disabling each account * After processing, a summary is sent via Teams ## Setup <Steps> <Step title="Create the agent"> * **Name**: "M365 Inactive Account Cleanup" * **Type**: Agent * **Trigger**: Scheduled * **Cadence**: Weekly (e.g., Monday at 6:00 AM) </Step> <Step title="Configure M365 integration permissions"> Set these permission groups: * **User Management** — **Read/Write** with TIL enabled (to block sign-in) * **Audit & Reports** — **Read Only** (to check sign-in logs) <Warning> Use the **IT Admin** or **Helpdesk** access profile to ensure Technician-in-the-Loop is required for write operations. Never run account-disabling agents without TIL. </Warning> </Step> <Step title="Enable communication and approval tools"> * **Send Teams Message** — for the summary report * **Request Technician Approval** is automatically available when TIL is configured on the M365 permission group </Step> <Step title="Write custom instructions"> ``` For each connected M365 tenant: 1. Search for all user accounts and check their last sign-in date 2. Identify accounts where the last sign-in was more than 90 days ago 3. Exclude the following from processing: - Accounts with "svc-", "service", "breakglass", or "emergency" in the display name - Accounts that are already blocked from sign-in - Shared mailboxes and room/resource accounts 4. For each inactive account found, request technician approval before taking action. Include the user's display name, email, last sign-in date, and assigned licenses in the approval request. 5. Once approved, block sign-in for the account 6. After processing all tenants, send a summary to the IT-operations Teams channel listing: - Accounts disabled (with last sign-in dates) - Accounts skipped (with reason) - Accounts pending approval ``` </Step> <Step title="Test and enable"> * Enable **test mode** for the first 2-3 runs to verify the exclusion filters work correctly * Review execution logs in **Executions** — pay close attention to which accounts would be disabled * Once confident, disable test mode and enable the workflow </Step> </Steps> ## Variations ### 60-day warning + 90-day disable Create two scheduled agents: 1. **60-day warning agent** (runs weekly) — sends a report of accounts inactive for 60+ days without taking action 2. **90-day disable agent** (runs weekly) — disables accounts inactive for 90+ days with TIL approval This gives your team a 30-day heads-up before accounts are disabled. ### License reclamation Add instructions to also **remove licenses** from disabled accounts. This helps reclaim unused license spend. Include the license removal in the TIL approval request so technicians can review both actions together. ## Best practices * Always maintain an exclusion list for service accounts and break-glass accounts in your custom instructions * Start with a longer inactivity threshold (120 days) and tighten once you trust the process * Review the summary report each week to catch any false positives early * Consider creating a PSA ticket for each batch of disabled accounts to maintain an audit trail # Branded End-User Support Bot in Teams Source: https://docs.neoagent.io/recipes/end-user-support-bot Give a client's employees a Teams bot under your brand that answers questions, checks ticket status, and files tickets ## Overview This recipe builds a chat agent for **end users** — your clients' employees — and deploys it into a client tenant as your own branded Teams bot. Users ask IT questions, check on their tickets, and file new ones, all in Teams. <Info> This is a **chat agent** connected through a **channel**. See [Chat Agents](/chat-agents/overview) and [Channels](/chat-agents/channels) for how this works. </Info> ## How it works * An employee at your client messages your branded bot in Teams; their company is recognized automatically from the Microsoft 365 tenant * The agent answers from your knowledge base and their company's ticket history * It can create a ticket when the issue needs a technician — and that's its only write ## Setup <Steps> <Step title="Create the chat agent"> * **Name**: "IT Support Assistant" * **Type**: Chat Agent ([**Chat**](https://dashboard.neoagent.io/chat) → **New Chat Agent**) </Step> <Step title="Enable tools — read-only plus ticket creation"> * **Find Documentation** — answer from your KB * **Find Tickets by Content** — "what's the status of my request?" * **Create New Ticket** — escalate to a technician * PSA permissions: **Read Only** Avoid write permissions and M365 tools on end-user-facing agents — prefer "file a ticket" over direct action. <Warning> In end-user conversations (through a [channel](/chat-agents/channels)), Neo enforces company scoping on top of the toolbox: tools that operate across your whole client base never run for end users, regardless of what's enabled here. The toolbox above applies in full to dashboard testing; see [what end users can access](/integrations/teams/end-user-bot#what-end-users-can-access) for what's available in the deployed bot. </Warning> </Step> <Step title="Set where tickets land — and the ticket's statuses"> The bot's own ticket tools need a destination before the agent can be saved: the board/queue/type, plus the **initial** status (the bot has it) and the **resolved** status (done). There's a third, optional one: the **escalation** status, where the bot moves a ticket when it can't finish the job. Either way it leaves a handover note for the technician — the status just decides whether the ticket also moves. Set one if your tickets open somewhere your queue doesn't triage, or they'll sit there. Leave it empty if they already open in a status a technician sees. See [where end-user tickets land](/agents/tools/end-user/overview#configure-where-end-user-tickets-land) and [handing a ticket to a technician](/agents/tools/end-user/overview#handing-a-ticket-to-a-technician). </Step> <Step title="Write custom instructions"> ``` You are the IT support assistant for our clients' employees. 1. Answer how-to questions from the documentation. Keep answers short and non-technical. 2. When asked about an existing issue, look up the user's recent tickets and report status in plain language. 3. If the issue needs a technician (anything you cannot resolve by pointing at documentation), create a ticket. Collect: what happened, when it started, error messages, device affected. Confirm the ticket number back to the user. 4. Never discuss other companies, pricing, or internal MSP matters. 5. If the user is frustrated or the issue is urgent (outage, security), create the ticket immediately and say a technician will follow up. ``` </Step> <Step title="Add per-client instructions (optional)"> On [**Companies**](https://dashboard.neoagent.io/end-companies) → edit a client → **Chat Instructions**, add company-specific guidance — their VIPs, their escalation contact, software they use. </Step> <Step title="Test in the dashboard"> Chat with the agent on the **Chat** page. Ask the questions an end user would. Tune instructions until the tone and escalation behavior are right. </Step> <Step title="Create the channel and deploy"> [**Chat** → **Channels**](https://dashboard.neoagent.io/chat?tab=channels) → **New Channel**: transport **Teams**, audience **End-user**, assign the agent, **Create channel**. Set your branding on the channel's **Teams app** tab. Then follow [End-user Teams bot](/integrations/teams/end-user-bot) to install it in the client tenant — test against your own tenant first. For a client on Slack, pick transport **Slack** instead and follow [End-user Slack bot](/integrations/slack/end-user-bot). </Step> </Steps> ## Variations ### Password-reset triage Add instructions to walk users through self-service password reset first, and only create a ticket if that fails. Keep the agent itself without M365 write access. ### Status-only bot Drop **Create New Ticket** for a purely informational bot — useful as a first rollout while you build trust in the agent's tone. ## Best practices * Re-read transcripts weekly at first — end users phrase things in ways technicians don't * Set the welcome message to state what the bot can do, so users don't ask for the impossible # Hybrid AD User Onboarding Source: https://docs.neoagent.io/recipes/hybrid-ad-user-onboarding Set up Neo to onboard users in on-prem Active Directory and sync them to Microsoft 365 ## Overview Use this recipe when new users are created in on-prem Active Directory and then synced to Microsoft 365 through Azure AD Connect. In a hybrid identity environment, Neo creates or updates the user in Active Directory, then triggers an Azure AD Connect sync so the change appears in Entra ID and Microsoft 365. <Info> If users are created directly in Entra ID, use the [cloud Microsoft 365 setup](/integrations/m365/cloud). If users only exist in local Active Directory and never sync to Microsoft 365, use [on-prem Active Directory setup](/integrations/m365/on-prem) without Hybrid. </Info> ## When to use Hybrid | Scenario | Company identity provider | | - | - | | Users are created in on-prem AD and synced to Microsoft 365 | Hybrid | | Both directories exist but AD Connect does NOT sync them | Hybrid (no AD Connect sync) | | Users are created only in Microsoft Entra ID | Entra ID | | Users are created only in local Active Directory | On-prem AD | <Warning> "Hybrid" assumes a working Azure AD Connect sync. If your AD Connect was decommissioned (or never existed) but you still maintain both directories, pick **"Hybrid (no AD Connect sync)"** instead — Neo will then create and manage users in **both** on-prem AD and Entra ID directly. With plain "Hybrid" and no working sync, the on-prem user is created but never reaches Microsoft 365, so licensing and mailbox steps can't proceed. </Warning> ## Setup checklist | Check | What the MSP needs to do | | - | - | | Company is configured as Hybrid | Set **Identity Provider Type** to **Hybrid** in [Company Settings](/integrations/m365/on-prem#1-configure-company-settings) | | Neo can run AD PowerShell | Set the AD runner hostname, [upload the Neo wrapper script](/integrations/m365/on-prem#2-upload-the-neo-script-to-your-rmm), and run an RMM sync | | Neo can trigger AD Connect sync | Set the AD Connect server hostname and make sure the service account can trigger sync. Not needed for **Hybrid (no AD Connect sync)** — Neo writes to both directories directly | | Optional license buying is configured | If the agent should buy Microsoft licenses, connect a [license marketplace integration](/integrations/marketplaces/intro) and add the company's marketplace ID | ## Configure the company Go to **Companies** in Neo and open the end-client company. Set: * **Identity Provider Type:** Hybrid * **AD Runner Hostname:** the RMM device Neo should use to run Active Directory commands * **AD Connect Server Hostname:** the server running Azure AD Connect * **AD Service Account Username / Password:** only if the runner needs a dedicated domain service account <Note> Hostnames must match the device names discovered from your RMM. See the [on-prem setup guide](/integrations/m365/on-prem#1-configure-company-settings) for field details. </Note> ## Configure the RMM path Neo runs on-prem Active Directory commands through your RMM. Before using a hybrid onboarding agent: <Steps> <Step title="Upload the wrapper script"> Follow the [Neo wrapper script setup](/integrations/m365/on-prem#2-upload-the-neo-script-to-your-rmm) for your RMM. </Step> <Step title="Sync RMM devices and scripts"> After uploading the script, run an RMM sync in Neo so the script and devices are discoverable. </Step> <Step title="Confirm the runner machine"> If Neo should run AD commands from a runner instead of directly on the domain controller, follow the [runner machine setup](/integrations/m365/on-prem#3-set-up-a-runner-machine). </Step> <Step title="Verify connectivity"> Run the checks in [Verify Connectivity](/integrations/m365/on-prem#6-verify-connectivity) before running the agent live. </Step> </Steps> ## Configure the onboarding agent Create or edit an [Onboard/Offboard M365 User](/building-automations/actions/ai/onboard-offboard-m365-user) agent or workflow. On the agent's **Integrations** tab, use a Microsoft 365 access profile that allows the onboarding work you want Neo to perform. For hybrid onboarding, the key requirement is that Neo can make the on-prem AD change and trigger Azure AD Connect sync. If the agent also needs to create or manage mailboxes through on-prem Exchange, see [Exchange Hybrid setup](/integrations/m365/on-prem#exchange-hybrid). <Tip> Start with [Technician-in-the-Loop](/core/technician-in-the-loop) enabled for write actions. Once the workflow is proven, reduce approval steps where appropriate. </Tip> ## Common errors | Error | Meaning | Action | | - | - | - | | `AD Connect sync is only available for hybrid environments` | The agent tried to sync AD changes, but the company is configured as On-prem AD | Set the company Identity Provider Type to **Hybrid**, or remove AD Connect sync from the agent if the company is truly on-prem-only | | `...no AD Connect sync to trigger` | The company is set to **Hybrid (no AD Connect sync)**, where directories are independent | Usually nothing — Neo manages both directories directly in this mode. If the company actually has a working AD Connect, change its Identity Provider Type to **Hybrid** | | `Neo wrapper script not found in RMM` | Neo cannot run PowerShell through the RMM | [Upload the Neo wrapper script](/integrations/m365/on-prem#2-upload-the-neo-script-to-your-rmm), then run an RMM sync | | `Target server not found in RMM` | The configured runner hostname does not match an RMM device | Update the hostname in [Company Settings](/integrations/m365/on-prem#1-configure-company-settings) or sync RMM devices | | `No license marketplace integration is configured` | Neo cannot buy licenses automatically | Connect a [license marketplace integration](/integrations/marketplaces/intro) | | `Marketplace company ID is not set` | Neo knows the marketplace, but not this company's marketplace ID | Add the company's marketplace company ID in Companies | ## Before running live <Steps> <Step title="Confirm company identity mode"> The company should be set to **Hybrid** if Neo needs to trigger Azure AD Connect sync. </Step> <Step title="Confirm RMM script execution"> The Neo wrapper script should be uploaded and visible after RMM sync. </Step> <Step title="Confirm AD Connect access"> The service account should be able to trigger sync on the AD Connect server. </Step> <Step title="Run with approval first"> Use Technician-in-the-Loop approval for the first few onboarding runs. </Step> </Steps> # Inactive Ticket Follow-up Source: https://docs.neoagent.io/recipes/inactive-ticket-followup Automatically send customer updates and tech notifications for tickets without recent activity ## Overview Maintain customer confidence and ensure technician accountability by automatically following up on tickets that haven't had time entries or notes for a specified period. <Info> This recipe works best as a Scheduled workflow running daily to catch tickets that need attention without overwhelming customers or technicians. </Info> ## How it works * Monitors tickets for inactivity using time since last note or time entry * Sends reassuring messages to customers about ongoing work * Notifies assigned technicians via Teams to prompt action ## Setup <Steps> <Step title="Create the workflow"> Name it "Inactive Ticket Follow-up". Set as Scheduled workflow with daily intervals. </Step> <Step title="Configure the filter"> Add the filter **"Hours since the last time entry created"** and set your threshold (e.g., 24 hours for high priority, 48 hours for normal priority). </Step> <Step title="Add customer message action"> Add a **"Build message"** action: * Set message type to **Customer-facing** * Descirbe how you want the messageto look like * Include ticket reference and expected timeline Example message: ``` Hello [Customer Name], We wanted to provide you with an update on your support request #[Ticket Number]. Our technical team is actively working on resolving your issue and will have an update for you shortly. We appreciate your patience as we work to provide you with the best possible solution. If you have any urgent concerns or additional information that might help us resolve this faster, please don't hesitate to reach out. Best regards, [Company Name] Support Team ``` </Step> <Step title="Add internal tech notification"> Add another **"Build message"** action: * Set message type to **Internal** * Create a direct message for the technician * Include ticket details and urgency indicators Example internal message: ``` TICKET FOLLOW-UP NEEDED Ticket #[Ticket Number] - [Subject] Customer: [Customer Name] Last activity: [Hours] hours ago This ticket needs attention. Customer has been automatically notified that we're working on their issue. Please update the ticket with progress or next steps. ``` </Step> <Step title="Configure notifications"> Add two notification actions: 1. **"Notify Ticket's Contact"** - Sends the customer message to the ticket requester 2. **"Notify ticket owner"** - Sends the internal message to the assigned technician via Teams </Step> </Steps> ## Best practices * **Exclude certain statuses**: Don't send follow-ups for tickets waiting on customer response <Check> Test your workflow with a few sample tickets before enabling it organization-wide to ensure messages are professional and notifications work correctly. </Check> # Notify Contact After Ticket Dispatch Source: https://docs.neoagent.io/recipes/notify-contact-after-dispatch Automatically notify customers when their ticket is assigned, confirming details and introducing the assigned technician ## Overview Improve customer communication by automatically notifying contacts when their ticket is dispatched and assigned to a technician. This workflow sends a professional confirmation message that includes ticket details and introduces the assigned technician, creating transparency and setting clear expectations. <Info> This is a Triggered workflow that activates immediately after a ticket has been dispatched and assigned to a technician. </Info> ## Setup <Steps> <Step title="Create the workflow"> Name it "Notify Contact After Dispatch" and set the type to Triggered. </Step> <Step title="Configure triggers"> Set triggers for "Workflow Finished" and point to your Dispatch workflow </Step> <Frame> <img alt="Notify Contact configuration showing Time Entry notification mode" /> </Frame> <Step title="Add assignment filters"> Filter to only target tickets that have been assigned to a technician: <Tabs> <Tab title="ConnectWise"> Use the filter: **Owner.Name is not null** This ensures the workflow only runs when a ticket has an assigned owner. </Tab> <Tab title="Autotask"> Use the filter: **assignedResourceId is not null** This ensures the workflow only runs when a ticket has an assigned resource. </Tab> </Tabs> <Tip> You may also want to add filters for specific ticket types, priorities, or boards to limit which tickets trigger this notification. </Tip> </Step> <Step title="Add Build Message action"> In the Smart Actions section: 1. Select the **Build Message** action 2. Set the note type to **Customer Facing** 3. Add instructions for the message format Example of instructions: ``` Compose a professional message to the customer that: - Confirms we received their request and ticket details - Introduces the assigned technician by name - Maintains a friendly, reassuring tone ``` </Step> <Step title="Add Notify Contact action"> In the Notify Users section: 1. Select **Notify Contact** as the action 2. Set the notification mode to **Time Entry** </Step> </Steps> <Warning> Avoid creating notification loops by ensuring that the option "Run workflow only once per ticket" is enabled in case the ticket is assigned to a different technician. </Warning> # Reassign Incomplete Scheduled Work Source: https://docs.neoagent.io/recipes/reassign-incomplete-scheduled-work Daily oversight to catch and reassign tickets with past scheduled entries not completed The workflow finds open tickets with past scheduled entries that were not completed and no upcoming scheduled work, then sends them to a Dispatch workflow for reassignment. <Info> This is a Scheduled workflow that runs daily (e.g., at 7 AM) to catch incomplete work from the previous day and reassign tickets to available technicians. </Info> ## Setup <Steps> <Step title="Create the scheduled workflow"> Name it "Reassign Incomplete Scheduled Work" and set the type to **Scheduled**. Configure it to run daily at 7:00 AM (or your preferred morning time). An early-morning run gives dispatchers time to review the reassignments before the workday starts. </Step> <Step title="Configure filters"> Add the following filters to find tickets with incomplete scheduled work: <Frame> <img alt="Filter configuration for incomplete scheduled work" /> </Frame> **Filter criteria:** * **Board.Name** = Your target board (e.g., Professional Services) * **Closed Flag** = False (only open tickets) * **Status.Name** = Your in-progress status (e.g., "In Progress (plan of action)") * **\[Extra] Has upcoming Scheduled Entry** = False (no future work scheduled) * **\[Extra] Count of past Scheduled Entries not completed** > 0 (has missed scheduled work) </Step> <Step title="Add Trigger Another Workflow action"> Add a **Trigger Another Workflow** action and select your Dispatch workflow as the target. <Frame> <img alt="Trigger Another Workflow action configuration" /> </Frame> <Tip> Enable **Bypass filter ticket conditions** if your Dispatch workflow has its own filters that might exclude these tickets. Since you've already filtered in this workflow, bypassing prevents double-filtering. </Tip> </Step> </Steps> For less aggressive reassignment, add a filter for **\[Extra] Count of past Scheduled Entries not completed > 1** to catch only tickets with multiple missed entries. Related: the [Manage Calendar](/recipes/assign-technician-manage-calendar) recipe handles the scheduling side — creating and updating the schedule entries this workflow checks. # Reassign when Technician is unavailable Source: https://docs.neoagent.io/recipes/reassign-technician-unavailable Automatically reassign tickets when clients respond after the assigned technician's shift has ended <Info> Use as a Triggered workflow that activates when clients reply to tickets and the assigned technician is off-shift. </Info> ## How it works * Monitors for client replies on tickets * Checks if the current technician is within their working hours * Automatically reassigns to an available technician from the appropriate shift ## Setup <Steps> <Step title="Create the workflow"> Name it "Reassign After Hours Response" and set the type to Triggered. </Step> <Step title="Configure triggers"> Set triggers for "Customer Replied" and any other relevant events like ticket updates or status changes. </Step> <Step title="Add filters"> Use the "\[AI] Ticket Owner Available = False" filter to target tickets where the assigned technician is currently off-shift. The filter reads each technician's PSA working hours together with their schedule entries, appointments and time off. A technician whose schedule data is missing or not synced counts as unavailable, so the ticket gets reassigned. Confirm that every technician has working hours and a shift schedule in your PSA before you switch this on. </Step> <Step title="Add Dispatch Ticket action"> Configure the dispatch action with all relevant technicians. Include any other extra setting like Consider Workload or Expertise, if applicable. </Step> <Step title="Configure custom instructions"> Add instructions to reinforce that Neo should only reassign when the current technician is outside working hours and assign to someone within their working hours. Example custom instruction: ``` Only reassign this ticket if the currently assigned technician is outside their working hours. Find and assign to a technician who is currently within their working shift schedule. Prioritize technicians with relevant skills for this type of issue. ``` </Step> <Step title="Assign ticket to technician"> Add the "Assign ticket to technician" action to allow Neo to update the ticket's assigned technician in your PSA. Optionally, you can notify the new assigned technician by email. </Step> <Step title="Document the outcome"> Optionally, include "Add Ticket Note" to document the reassignment within the ticket. </Step> </Steps> Test the workflow during all shift transitions. ## Common use cases * **24/7 support operations** with day, evening, and night shifts * **Follow-the-sun support** across different time zones * **Weekend coverage** with rotating on-call schedules * **Holiday coverage** when regular technicians are unavailable # Rotate Admin & Service Account Passwords Monthly Source: https://docs.neoagent.io/recipes/rotate-service-account-passwords Automate monthly password rotation for privileged M365 accounts with technician approval ## Overview This recipe creates a scheduled agent that runs monthly to rotate passwords for admin and service accounts across your connected M365 tenants. Every password reset requires technician approval, and new credentials are delivered securely. <Info> This is a **scheduled agent** — it runs on a cadence without processing a specific ticket. See [Scheduled Agents](/core/scheduled-agents) for how this works. </Info> ## How it works * Agent runs monthly and identifies admin and service accounts across connected tenants * For each account, the agent generates a secure password and requests **Technician-in-the-Loop approval** * After approval, the password is reset and new credentials are delivered via a secure link * A summary of all rotated accounts is logged ## Setup <Steps> <Step title="Create the agent"> * **Name**: "M365 Password Rotation" * **Type**: Agent * **Trigger**: Scheduled * **Cadence**: Monthly (e.g., first Monday at 5:00 AM) </Step> <Step title="Configure M365 integration permissions"> Set these permission groups: * **Security** — **Read/Write** with TIL enabled (for password resets) * **Directory Roles** — **Read Only** (to identify admin accounts) * **User Management** — **Read Only** (to search for service accounts) </Step> <Step title="Enable tools"> * **Generate Password** — to create secure random passwords * **Generate Secure Link** — to deliver credentials safely * **Send Teams Message** or **Send Internal Email** — for delivery and summary </Step> <Step title="Write custom instructions"> ``` For each connected M365 tenant: 1. List all users with privileged directory roles: - Global Administrator - Privileged Role Administrator - Exchange Administrator - Security Administrator 2. Also find service accounts (display name contains "svc-" or "service") 3. Exclude break-glass/emergency accounts from rotation 4. For each account: a. Generate a new secure password (minimum 20 characters) b. Request technician approval, specifying which account and tenant c. Once approved, reset the password d. Send the new credentials to the designated admin via a secure link 5. After processing all accounts, send a summary to the security-ops Teams channel listing all accounts rotated and any that were skipped ``` </Step> <Step title="Test and enable"> * Enable **test mode** and run once to verify it identifies the correct accounts * Review the execution log to confirm the account list and exclusions are right * Disable test mode, enable, and monitor the first live run closely </Step> </Steps> ## Variations ### Separate schedules for admin vs service accounts Split into two agents with different cadences: * **Admin accounts** — monthly rotation * **Service accounts** — quarterly rotation (to reduce disruption to automated processes) ### Create audit tickets Add instructions to create a PSA ticket for each rotation cycle, logging which accounts were rotated, when, and by whom (the approving technician). This provides an audit trail for compliance reporting. ## Best practices * Always require TIL approval — automated password resets without human oversight can lock out critical accounts * Coordinate with your team on rotation schedules to avoid disruptions during business hours * Maintain a list of break-glass accounts that should never have passwords rotated by automation * Use the secure link tool for credential delivery — never include passwords in Teams messages or emails directly * Document the rotation schedule in your internal wiki so all technicians know when to expect approval requests # Run Triggered Workflows on a Schedule Source: https://docs.neoagent.io/recipes/run-triggered-workflows-on-a-schedule Use a Scheduled Workflow to execute an existing Triggered Workflow ## How it works * A Scheduled Workflow finds tickets via filters. * It triggers your existing Triggered Workflow for each ticket. ## Setup <Steps> <Step title="Create the scheduled workflow"> Name it "Scheduled \[Triggered Workflow Name]" and set your cadence (daily at 8AM, hourly, one-time via Run Now). </Step> <Step title="Filter tickets"> Add precise filters (e.g., New + Unassigned; Board = Help Desk; Created ≤ 7 days). </Step> <Step title="Add Trigger Another Workflow"> Pick the target Triggered Workflow. Set bypassing of filters depending on whether you want double filtering. </Step> </Steps> Test with **Run Now** and a narrow filter first, so the first pass covers a few tickets and you can read the results before you set the cadence. ## Use cases ### Morning dispatch Dispatch overnight tickets before the day begins. ### Apply to existing tickets Run a new Triggered Workflow against the last 7 days of tickets. ### Off-peak batch processing Run heavy workflows at night to reduce daytime load. ## Best practices <Warning> **Make sure a ticket can leave your filter.** The scheduled workflow re-runs its filter on every tick, so any ticket that still matches gets triggered again. If the target is meant to act once, either turn on **Run only once per ticket** on it, or filter on something the run itself changes (a status, or a custom field the agent writes). The trap is the second option failing quietly: if the agent skips that write - no data to compute a value, a condition not met - the ticket keeps matching and is re-triggered every cycle until you notice. Watch Executions for the same ticket number repeating at your schedule's interval. A time-bounded filter is the third option: with **Created ≤ 7 days**, a ticket leaves the filter as it ages, even if nothing writes to it. </Warning> # Scan for New M365 Admin Accounts Daily Source: https://docs.neoagent.io/recipes/scan-new-m365-admins Detect unauthorized admin role assignments across M365 tenants and alert your team automatically ## Overview This recipe creates a scheduled agent that runs daily to check for new admin role assignments across your connected M365 tenants. If any new privileged role assignments are detected, the agent sends a Teams notification so your team can verify they're authorized. <Info> This is a **scheduled agent** — it runs on a cadence without processing a specific ticket. See [Scheduled Agents](/core/scheduled-agents) for how this works. </Info> ## How it works * Agent runs daily (e.g., 7:00 AM) and queries directory role assignments and audit logs across connected tenants * If new admin role assignments are found in the last 24 hours, sends a Teams alert with details * If nothing new is found, the agent completes silently ## Setup <Steps> <Step title="Create the agent"> * **Name**: "M365 Admin Role Monitor" * **Type**: Agent * **Trigger**: Scheduled * **Cadence**: Daily at 7:00 AM (or your preferred time) </Step> <Step title="Configure M365 integration permissions"> Ensure your M365 integration has these permission groups enabled at **Read Only** (minimum): * **Directory Roles** — to list current role assignments * **Audit & Reports** — to query audit logs for recent changes </Step> <Step title="Enable communication tools"> Enable **Send Teams Message** (or **Send Internal Email**) so the agent can alert your team when new assignments are found. </Step> <Step title="Write custom instructions"> ``` For each connected M365 tenant: 1. Query the directory audit logs for the last 24 hours, filtering for role assignment events ("Add member to role") 2. Focus on privileged roles: Global Administrator, Exchange Administrator, SharePoint Administrator, Security Administrator, Privileged Role Administrator, Teams Administrator, Intune Administrator 3. For each new assignment found, collect: - The user who was assigned the role - Which role was assigned - Who performed the assignment - When it occurred 4. If any new assignments are found, send a Teams message to the security-alerts channel with a summary table of all findings 5. If no new assignments are found in any tenant, do not send any message ``` </Step> <Step title="Test and enable"> * Enable **test mode** for the first run * Review the execution log in **Executions** after the first scheduled run * Once satisfied, disable test mode and enable the workflow </Step> </Steps> ## Variations ### Alert via ticket instead of Teams Replace the Teams notification with a **Create New Ticket** instruction. The agent will create a ticket in your PSA when unauthorized changes are detected, letting your team track remediation through your normal workflow. ### Include all role changes (not just additions) Expand the audit log query to also include role removal events. This gives visibility into both escalations and de-escalations of privilege. ## Best practices * Run at a consistent time each day so your team knows when to expect alerts * Keep the privileged role list focused on the most critical roles to reduce noise * Consider creating a dedicated Teams channel for these security alerts # Status/Time-Based Escalation Source: https://docs.neoagent.io/recipes/status-time-based-escalation Escalate tickets automatically based on status, priority, and elapsed time ## Overview Ensure timely progress on tickets by escalating when they sit too long in a status, exceed SLAs, or require higher attention. <Info> This recipe can be implemented as a Scheduled workflow (e.g., every 15 minutes) or as a Triggered workflow using time-entry/status updates. </Info> ## How it works * Monitors ticket status age and SLA thresholds * Escalates priority, notifies leads, or reassigns per policy * Adds an internal note detailing the escalation reason ## Setup <Steps> <Step title="Create the workflow"> Name it "Status/Time-Based Escalation". Use Scheduled if you want periodic checks. </Step> <Step title="Configure filters"> Target tickets in specific statuses (e.g., Waiting on Technician) and priorities. </Step> <Step title="Add Checks and Updates"> If status age > threshold or SLA breach imminent, increase priority, notify channel, and reassign if needed. </Step> <Step title="Add Ticket Note"> Record the action taken and the timer/threshold that triggered escalation. </Step> </Steps> ## Best practices * Use different thresholds per priority * Notify both leads and the current owner * Combine with reassignment rules for stalled tickets # Self-Serve Ticket Dispatch in Teams Source: https://docs.neoagent.io/recipes/technician-self-serve-dispatch 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. * **"start a new chat"** 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. When the requester has no Technician Mapping, Neo replaces that section with a notice that it cannot place them. Tell them their account is not mapped and that a Neo administrator can map it on the Technicians page. Never pick a technician from the roster instead. ## 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](/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**: transport **Teams**, **Audience: Internal**, assign this agent, **Create channel**. Set your branding on the channel's **Teams app** tab. 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. Typing **"start a new chat"** 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. An unmapped requester gets the "cannot place you" notice instead of that section, so the agent declines rather than choosing someone | | 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 # Tickets Without Scheduled Work Source: https://docs.neoagent.io/recipes/tickets-without-scheduled-work Identify and follow up on service tickets that lack scheduled service calls or todos ## Setup <Steps> <Step title="Create the workflow"> Name it "Tickets Without Scheduled Work". Set it as a Scheduled workflow with daily intervals. Run it on weekdays inside business hours. The schedule's daily execution windows (or the older **Weekdays only** setting) stop it from raising alerts at night or over the weekend, when nobody can book the work. </Step> <Step title="Configure status filters"> Add filters for ticket statuses where scheduled work should exist: * Include statuses like "In Progress", "Assigned", "Scheduled" * Exclude statuses like "Waiting on Customer", "On Hold", "Resolved" Include only statuses where technicians should have active work planned to avoid false alerts. </Step> <Step title="Add service call filter"> Add the filter **"\[Extra] Count of Service Calls Scheduled for Anytime in the Future"**: * Set the condition to **equals 0** * This identifies tickets with no scheduled service calls <Warning> This filter counts every future service call, whatever its state. A call that a technician marked complete, or one your team cancelled, still counts. So a ticket whose only booked work was cancelled looks scheduled, and the workflow skips it. For Autotask, use **"\[Extra] Count of Open Service Calls Scheduled for Anytime in the Future (excludes complete and canceled)"** instead when you want only work that is genuinely still going to happen. It applies the same future-date test, then drops calls marked complete and calls whose status names a cancellation. Neo spots a cancelled call two ways: Autotask's own cancellation record on the service call, and the status. Cancellation statuses are not built into Autotask - each MSP creates its own - so for the status Neo reads the label and treats any label containing "cancel" as cancelled. If your cancellation status is named something else, such as "Aborted", rename it or include "Canceled" in the label so Neo recognises it. </Warning> </Step> <Step title="Add todo filter"> Add the filter **"\[Extra] Count of ToDos Scheduled for Anytime in the Future"**: * Set the condition to **equals 0** * This identifies tickets with no scheduled todos Both filters find tickets with no scheduled future work. </Step> <Step title="Create internal alert message"> Add a **"Build message"** action: * Set message type to **Internal** * Create an alert for the team about missing scheduled work * Include ticket details and suggested actions Example internal message: ``` SCHEDULING ATTENTION REQUIRED Ticket #[Ticket Number] - [Subject] Customer: [Customer Name] Status: [Status] Assigned to: [Assigned Resource] This ticket has no scheduled service calls or todos. Please review and schedule appropriate follow-up work: • Schedule a service call if on-site work is needed • Create todos for remote tasks or follow-up actions • Update ticket status if work is complete Ticket Link: [Ticket URL] ``` </Step> <Step title="Configure team notifications"> Add notification actions based on your team structure: **Option 1: Notify assigned resource** * Use **"Notify ticket owner"** to alert the assigned technician directly **Option 2: Notify internal team** * Use **"Notify internal team"** to alert supervisors or dispatch teams * Include relevant team members who handle scheduling **Option 3: Both notifications** * Notify the assigned resource for immediate action * Notify the internal team for oversight and support </Step> </Steps> # Teams bot for your clients Source: https://docs.neoagent.io/teams-bot Put your own branded support bot in your clients' Microsoft Teams, built on your Neo agents. The single starting point for the end-user Teams bot. Give your clients' employees IT support right where they already work — **Microsoft Teams** — from a bot that wears **your** brand, not Neo's. They ask a question, get an answer from your knowledge base, and raise a ticket without leaving the chat. Behind the scenes it runs on your Neo agents, under your permissions, and bills to you. This page is the starting point. Share it with anyone on your team who's rolling the bot out — it links to everything below in the order you'll need it. <Frame> <img alt="The Channels tab in the Neo dashboard, where you manage your branded Teams bots — here a live 'Acme Support' Teams channel" /> </Frame> ## How it works, in four steps <CardGroup> <Card title="1. Build a chat agent" icon="robot" href="/chat-agents/building-a-chat-agent"> Create a conversational agent for end users — instructions in their language, read-only tools plus "file a ticket". Test it in the dashboard before anyone sees it. </Card> <Card title="2. Brand it as a channel" icon="palette" href="/chat-agents/channels"> A channel ties the agent to Teams and carries the branding end users see — display name, icon, welcome message. Every field is optional; blanks use a Neo default. </Card> <Card title="3. Install in a client's Teams" icon="microsoft" href="/integrations/teams/end-user-bot"> Generate a magic install link and send it to the client's Microsoft 365 admin. One approval publishes your branded bot into their tenant — no zip to upload. </Card> <Card title="4. Employees get support" icon="comments" href="/chat-agents/how-end-user-bots-work"> Their employees message the bot in Teams. It answers, files tickets, and relays live ticket updates back into the same chat — all scoped to that one company. </Card> </CardGroup> ## What your clients' employees get * **Instant answers** from your customer-facing knowledge base — no waiting on a queue for the routine stuff. * **Their own tickets** — they can raise a ticket through the bot and check the status of any of their tickets at any time. * **Live updates in the same chat** — when a technician posts a client-facing update on their ticket, it arrives in the Teams conversation, and their reply goes straight back onto the ticket. See [live ticket updates](/integrations/teams/end-user-bot#live-ticket-updates-in-the-chat). * **Your brand, end to end** — your name, your icon, your welcome message. Neo is never visible to the end user. ## Why it's safe to put in front of end users Every conversation through the bot is **locked to the one company** the employee belongs to, recognized automatically from the Microsoft 365 tenant their message comes from. The bot can only see that person's own tickets and your customer-facing documentation — never your other clients, internal notes, or anything across your client base. That boundary is enforced by the platform, not by how you configure the agent, so there's no toolbox setting that can accidentally over-share. The branded app published into the client tenant is **messaging-only** — it has no Microsoft Graph access there. All the real work happens through *your* integrations, under *your* permissions and [technician approvals](/core/technician-in-the-loop). The full architecture is in [how end-user bots work](/chat-agents/how-end-user-bots-work), and the consent details a client admin might ask about are in [consent and security](/integrations/teams/end-user-bot#consent-and-security). ## Test before you roll out Two ways to try a bot before a client ever sees it: * **Its behavior** — chat with the agent [as a real end-client](/chat-agents/channels#testing-as-an-end-client) at a chosen company, right in the dashboard. No install, instant. * **The Teams experience** — branding, the welcome message, cards, proactive messages — by [installing into your own tenant first](/integrations/teams/end-user-bot#test-in-your-own-tenant-first). ## Roll it out <CardGroup> <Card title="Deployment guide" icon="list-check" href="/integrations/teams/end-user-bot"> The full procedure, top to bottom — install link, Teams admin center steps, verification, updates, and troubleshooting. </Card> <Card title="Recipe: end-user support bot" icon="book-open" href="/recipes/end-user-support-bot"> A worked end-to-end example, from a tested chat agent to a branded bot answering a client's employees. </Card> </CardGroup> <Note> **Your client works in Slack?** The same end-user agent runs there as a Slack app with your name and icon; see [Deploy your end-user Slack bot](/integrations/slack/end-user-bot). </Note> <Note> **Looking for Neo for your own technicians?** That's a different surface. The **Neo AI Agent** app delivers workflow notifications, approval cards, and the [Neo Support Agent](/chat-agents/neo-support-agent); or put one of your *own* agents in your technicians' Teams as a [custom internal bot](/integrations/teams/internal-bot). The [Teams overview](/integrations/teams/intro) lays out which is which. </Note>