Customer support
Zendesk
Tickets, replies, macros and views in your Zendesk, worked by your agent.
12 endpoints
Your agent reads tickets, adds notes, drafts replies from the knowledge base and logs time in HaloPSA. You sign in once with your own agent login, with no API application and no server to host. It works inside the ChatGPT and Claude apps.
14 tools Read and write
HaloPSA has an official REST API and its own MCP endpoint (checked 6 Nov 2026). A Halo admin turns each one on: an API application under Configuration > Integrations > Halo API, and "Enable the MCP Endpoint" under Configuration > AI > MCP Server. Cotlet adds 14 HaloPSA tools hosted, over MCP for agents and REST for scripts, with none of that setup.
| What you need | Official REST API | Halo MCP endpoint | Cotlet |
|---|---|---|---|
| Find and read tickets with their history | Yes, you code it | Yes | Yes |
| Create a ticket | Yes, you code it | With an admin's custom tool | Yes, after your OK |
| Add a private note | Yes, you code it | Yes | Yes, after your OK |
| Reply to the user | Yes, you code it | Through a set-up action | Yes, after your OK |
| Log time | Yes, you code it | Yes, a quick entry | Yes, after your OK |
| Look up clients and read a timesheet | Yes, you code it | Not in the tool list | Yes |
| No admin setup before you start | No | No | Yes, your own sign-in |
| Runs in the ChatGPT and Claude apps, 24/7 | No, your own code | Needs admin setup | Yes, hosted |
Checked 6 Nov 2026. Sources: Halo Guides: Halo MCP Server Connection · Halo Guides: MCP Server Settings · Halo Guides: Creating API Applications · n8n: HaloPSA integrations
Use your own agent login.
Paste one Cotlet address.
Your agent works the tickets.
We never keep your HaloPSA password, and no reply, ticket change or logged time happens until you approve it. Who can see your session
Use MCP with your AI agent, or the same tools over REST in n8n, Make and scripts.
Enable HaloPSA for agents. Sign up, log in to Halo in its Cloud Browser, then press Enable for agents.
Add the Cotlet address. Add https://cotlet.dev/mcp/v1 as an MCP server or connector in your agent.
Approve the connection. Chat apps ask you to sign in to Cotlet. Editors, n8n and scripts use an API key from the console.
One shared address, https://cotlet.dev/mcp/v1, also carries HaloPSA next to your other apps. If you enable HaloPSA after connecting, refresh the connector so the new tools show up.
Settings > Connectors > Add custom connector
URL: https://cotlet.dev/mcp/v1/connect
Claude Code:
claude mcp add --transport http cotlet-halopsa \
https://cotlet.dev/mcp/v1 \
--header "Authorization: Bearer $COTLET_API_KEY" Settings > Apps & Connectors > Create
MCP server URL: https://cotlet.dev/mcp/v1/connect
Authentication: OAuth // ~/.cursor/mcp.json
{
"mcpServers": {
"cotlet-halopsa": {
"url": "https://cotlet.dev/mcp/v1",
"headers": { "Authorization": "Bearer ${env:COTLET_API_KEY}" }
}
}
} # ~/.codex/config.toml
[mcp_servers.cotlet-halopsa]
url = "https://cotlet.dev/mcp/v1"
bearer_token_env_var = "COTLET_API_KEY" MCP Client Tool (inside an AI Agent)
Transport: HTTP Streamable
URL: https://cotlet.dev/mcp/v1
Auth: Bearer, <your key>
Tool: halopsa_read Make: MCP Client > Call a tool
Zapier: MCP Client by Zapier > Run Tool
Server URL: https://cotlet.dev/mcp/v1
Token: <your key>
Tool: halopsa_write Names of statuses, priorities and teams must match your Halo exactly. Read the ticket types first, because a type that agents may not log is refused.
Returns the tickets your Halo list shows, with ID, summary, client, ticket type, status, priority, assigned agent and team, and the response and resolution targets the SLA sets. Filters are optional and combine. Pass next_page back as page for the next page.
MCP callhalopsa_read → list_tickets
REST endpointGET https://cotlet.dev/api/v1/halopsa/tickets
| Name | Type | Description |
|---|---|---|
| query string | string | Only tickets whose summary or details contain this text. |
| status string | string | Status name exactly as your Halo shows it, for example "Open". |
| client_id integer | integer | Client ID from list_clients. |
| team string | string | Team name exactly as your Halo shows it. |
| agent string | string | Agent name, or "unassigned" for tickets with no agent. |
| open_only boolean | boolean | true skips closed tickets. |
| limit integer | integer | How many tickets to return. |
| page integer | integer | Page number from next_page. |
{
"tickets": [
{
"ticket_id": 4821,
"summary": "Printer offline on floor 2",
"client": "Northwind Logistics",
"ticket_type": "Incident",
"status": "Open",
"priority": "High",
"agent": null,
"team": "Service Desk",
"response_target": "met",
"resolution_target": "2026-11-05T15:00:00Z"
},
{
"ticket_id": 4822,
"summary": "VPN drops every hour",
"client": "Brightside Dental",
"ticket_type": "Incident",
"status": "Open",
"priority": "Medium",
"agent": "Lena Ortiz",
"team": "Service Desk",
"response_target": "met",
"resolution_target": "2026-11-06T09:00:00Z"
}
],
"next_page": null
} Returns the ticket fields, the user who raised it, and its actions in the order Halo shows them: replies, private notes and logged time, each with who added it. Use it before replying or adding a note so the agent reads the whole history first.
MCP callhalopsa_read → get_ticket
REST endpointGET https://cotlet.dev/api/v1/halopsa/tickets/{ticket_id}
| Name | Type | Description |
|---|---|---|
| ticket_id integer required | integer | Ticket ID from list_tickets. |
{
"ticket_id": 1
} {
"ticket_id": 4821,
"summary": "Printer offline on floor 2",
"details": "The shared printer shows offline since this morning. Restarting it did not help.",
"user": "Dana Whitfield",
"client": "Northwind Logistics",
"status": "Open",
"priority": "High",
"agent": null,
"actions": [
{
"action_id": 1,
"kind": "note",
"by": "Dana Whitfield",
"text": "Restarting it did not help.",
"created_at": "2026-11-05T08:12:00Z"
}
]
} Returns the ticket types set up under Configuration > Tickets > Ticket Types, and says which ones agents may log tickets of. Use the ticket_type_id with create_ticket.
MCP callhalopsa_read → list_ticket_types
REST endpointGET https://cotlet.dev/api/v1/halopsa/ticket-types
No parameters.
{
"ticket_types": [
{
"ticket_type_id": 1,
"name": "Incident",
"agents_can_log": true
},
{
"ticket_type_id": 2,
"name": "Service Request",
"agents_can_log": true
}
]
} Logs the ticket as you, with the ticket type, summary and details you give, and returns its ID and link. A ticket type that does not allow agents to log it is refused. Halo may email the user, depending on your notification settings. By default you confirm each call; you can switch that off for this tool.
MCP callhalopsa_write → create_ticket
REST endpointPOST https://cotlet.dev/api/v1/halopsa/clients/{client_id}/tickets
| Name | Type | Description |
|---|---|---|
| client_id integer required | integer | Client ID from list_clients. |
| user_email string | string | Email of the user who raised it, from get_client. |
| ticket_type_id integer required | integer | Ticket type ID from list_ticket_types. |
| summary string required | string | One-line title of the ticket. |
| details string | string | Full description. |
| priority string | string | Priority name exactly as your Halo shows it. |
{
"client_id": 1,
"ticket_type_id": 1,
"summary": "summary"
} {
"ticket_id": 4830,
"summary": "Laptop battery swells",
"client": "Brightside Dental",
"ticket_type": "Incident",
"status": "New",
"url": "https://yourcompany.halopsa.com/tickets?id=4830"
} Changes only the fields you pass and returns the ticket as it is now. A status change moves the ticket on in its workflow, and Halo may notify the user or the agent, depending on your notification settings. A change Halo does not allow for that ticket comes back as an error. By default you confirm each call; you can switch that off for this tool.
MCP callhalopsa_write → update_ticket
REST endpointPATCH https://cotlet.dev/api/v1/halopsa/tickets/{ticket_id}
| Name | Type | Description |
|---|---|---|
| ticket_id integer required | integer | Ticket ID from list_tickets. |
| status string | string | Status name exactly as your Halo shows it. |
| priority string | string | Priority name exactly as your Halo shows it. |
| team string | string | Team name exactly as your Halo shows it. |
| agent string | string | Agent name exactly as your Halo shows it. |
{
"ticket_id": 1
} {
"ticket_id": 4821,
"status": "Open",
"priority": "High",
"team": "Service Desk",
"agent": "Lena Ortiz"
} A private note is seen by agents only. A reply reaches the user by email and cannot be recalled.
Adds a note only agents see, never the user, and returns its action ID. A note cannot be deleted through Cotlet. Halo may notify the agent on the ticket. By default you confirm each call; you can switch that off for this tool.
MCP callhalopsa_write → add_note
REST endpointPOST https://cotlet.dev/api/v1/halopsa/tickets/{ticket_id}/notes
| Name | Type | Description |
|---|---|---|
| ticket_id integer required | integer | Ticket ID from list_tickets. |
| note string required | string | Text of the note. |
{
"ticket_id": 1,
"note": "note"
} {
"ticket_id": 4821,
"action_id": 2,
"kind": "note",
"created_at": "2026-11-05T08:40:00Z"
} Adds a reply the user can read and sends it by email as Halo does for any agent reply, then returns its action ID. The reply cannot be recalled once sent. By default you confirm each call; you can switch that off for this tool.
MCP callhalopsa_write → reply_to_user
REST endpointPOST https://cotlet.dev/api/v1/halopsa/tickets/{ticket_id}/user/replies
| Name | Type | Description |
|---|---|---|
| ticket_id integer required | integer | Ticket ID from list_tickets. |
| message string required | string | Text of the reply. |
{
"ticket_id": 1,
"message": "message"
} {
"ticket_id": 4821,
"action_id": 3,
"kind": "reply",
"sent_to": "dana@example.com",
"created_at": "2026-11-05T08:45:00Z"
} Search with the ticket summary or the user's own words to find steps for a reply.
Searches the Halo knowledge base and returns each match with its ID, title and the article text. Pass a ticket summary or the user's own words as the query. Use it to find steps for a reply or to link an article in a note.
MCP callhalopsa_read → search_knowledge_base
REST endpointGET https://cotlet.dev/api/v1/halopsa/knowledge-bases/search
| Name | Type | Description |
|---|---|---|
| query string required | string | Words to search for. |
| limit integer | integer | How many articles to return. |
{
"query": "query"
} {
"articles": [
{
"article_id": 311,
"title": "Reconnect a network printer",
"text": "1. Open Settings > Printers. 2. Remove the printer. 3. Add it again by its IP address."
}
]
} Look up the client ID before you filter or create tickets.
Lists the clients in your Halo, filtered by part of the name if you pass one. Use the client_id with list_tickets, create_ticket and list_assets. Counts are of tickets open now.
MCP callhalopsa_read → list_clients
REST endpointGET https://cotlet.dev/api/v1/halopsa/clients
| Name | Type | Description |
|---|---|---|
| query string | string | Only clients whose name contains this text. |
| limit integer | integer | How many clients to return. |
{
"clients": [
{
"client_id": 12,
"name": "Northwind Logistics",
"open_tickets": 3
},
{
"client_id": 15,
"name": "Brightside Dental",
"open_tickets": 1
}
]
} Returns the client's details, its sites and its users, with the email of each user. Use it to pick the right user before create_ticket or reply_to_user.
MCP callhalopsa_read → get_client
REST endpointGET https://cotlet.dev/api/v1/halopsa/clients/{client_id}
| Name | Type | Description |
|---|---|---|
| client_id integer required | integer | Client ID from list_clients. |
{
"client_id": 1
} {
"client_id": 12,
"name": "Northwind Logistics",
"sites": [
"Head office"
],
"users": [
{
"name": "Dana Whitfield",
"email": "dana@example.com"
},
{
"name": "Jon Reyes",
"email": "jon@example.com"
}
]
} Returns assets with ID, name, type, client and the user it is assigned to. Use it to name the right device in a ticket note.
MCP callhalopsa_read → list_assets
REST endpointGET https://cotlet.dev/api/v1/halopsa/assets
| Name | Type | Description |
|---|---|---|
| query string | string | Only assets whose name contains this text. |
| client_id integer | integer | Client ID from list_clients. |
| limit integer | integer | How many assets to return. |
{
"assets": [
{
"asset_id": 903,
"name": "PRN-FLOOR2",
"type": "Printer",
"client": "Northwind Logistics",
"user": "Dana Whitfield"
}
]
} Time can feed billing, so read the timesheet first and check the minutes. Reports are the saved ones you built in Halo.
Returns each action the agent logged that day, with the ticket, the time spent and whether it is billable, as the Time Tracking timesheet shows it. Without an agent it reads your own timesheet. Use it before log_time so time is not logged twice.
MCP callhalopsa_read → get_timesheet
REST endpointGET https://cotlet.dev/api/v1/halopsa/timesheet
| Name | Type | Description |
|---|---|---|
| date string required | string | Day as YYYY-MM-DD. |
| agent string | string | Agent name. Default: you. |
{
"date": "date"
} {
"date": "2026-11-05",
"entries": [
{
"ticket_id": 4822,
"note": "Checked VPN logs",
"minutes": 20,
"billable": true
}
],
"total_minutes": 20
} Adds a log time action to the ticket and to your timesheet, with the minutes and the note you give, and returns the action ID. The time can feed billing, so check the amount. To remove it, delete the action in Halo. By default you confirm each call; you can switch that off for this tool.
MCP callhalopsa_write → log_time
REST endpointPOST https://cotlet.dev/api/v1/halopsa/tickets/{ticket_id}/times
| Name | Type | Description |
|---|---|---|
| ticket_id integer required | integer | Ticket ID from list_tickets. |
| minutes integer required | integer | Time spent, in minutes. |
| note string | string | What was done. |
| billable boolean | boolean | true if the time is billable. Default: your Halo's default for the ticket. |
{
"ticket_id": 4821,
"minutes": 30,
"note": "Re-added the printer by IP address",
"billable": true
} {
"ticket_id": 4821,
"action_id": 4,
"minutes": 30,
"billable": true,
"created_at": "2026-11-05T09:10:00Z"
} Runs one saved report from the Reports area and returns its columns and rows. The report decides what is counted, so build the report in Halo first, then ask for it by name. Pass next_page back as page for more rows.
MCP callhalopsa_read → get_report_data
REST endpointGET https://cotlet.dev/api/v1/halopsa/report-data
| Name | Type | Description |
|---|---|---|
| report string required | string | Report name exactly as your Halo shows it. |
| page integer | integer | Page number from next_page. |
{
"report": "report"
} {
"report": "Weekly tickets",
"columns": [
"Client",
"Opened",
"Closed"
],
"rows": [
[
"Northwind Logistics",
9,
7
],
[
"Brightside Dental",
4,
4
]
],
"next_page": null
} Your logged-in HaloPSA profile, encrypted with AES-256-GCM, in Finland. Not the password.
The 14 HaloPSA tools. Never the cookie or your login.
What your agent login sees: tickets, notes, clients, assets, time.
Billing, contracts, agent accounts, configuration and deleting.
You sign in again in your own browser, with your own second step if you use one. We never type it.
Disable for agents, reset the browser, or end the session in Halo.
Our site scores A+ on Qualys SSL Labs, securityheaders.com and Mozilla Observatory (live results).
You sign in with your own agent login, so the agent sees and changes only what that login can. If you cannot open a ticket type, a client or a report in Halo, your agent cannot either.
Replies are the only text a user receives, so they wait for your OK. Private notes stay with your team.
When a Halo screen moves or a field is renamed, the fix happens on our side and your prompts keep working. status.cotlet.dev watches the site, console and API every 3 minutes.
| Action | Undo |
|---|---|
| Create a ticket | Close or edit it in Halo |
| Update status, priority, team or agent | Set the old value again, if the workflow allows it |
| Add a private note | No tool removes it, an admin can in Halo |
| Reply to the user | No, the email is out |
| Log time | Delete the action in Halo before it is billed |
All 5 write tools ask first: create_ticket, update_ticket, add_note, reply_to_user, log_time. Reads reach nobody and run at once. Switch the wait off per tool for a scheduled run.
A status change moves the ticket on in its workflow, and Halo may notify the user or the agent, so check your notification settings before you switch the wait off.
{
"name": "log_time",
"arguments": {
"ticket_id": 4821,
"minutes": 30,
"note": "Re-added the printer by IP address",
"billable": true
}
} curl -X POST https://cotlet.dev/api/v1/halopsa/tickets/4821/times \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"minutes":30,"note":"Re-added the printer by IP address","billable":true}' {
"ticket_id": 4821,
"action_id": 4,
"minutes": 30,
"billable": true,
"created_at": "2026-11-05T09:10:00Z"
} Scripts and cron jobs reach the same tools over REST at /api/v1/halopsa, with the same key and price. A write over REST waits for your OK too and answers 202 until you approve it. A failed call costs nothing. The tools table lists the REST path of each tool.
About $56 a monthfor one service desk agent at a small MSP, 9,580 credits. Your HaloPSA licence is billed by Halo as before.
| Job | Calls | Credits |
|---|---|---|
| Triage new tickets, daily | 13 × 22 | 2,860 |
| Watch tickets near their target, daily | 7 × 22 | 1,540 |
| Draft first replies, daily | 10 × 22 | 2,200 |
| Log time from your day, daily | 6 × 22 | 1,320 |
| Weekly report per client | 4 × 4 | 160 |
| Cloud Browser, 30 days | 1,500 | |
| Total | 9,580 |
The month is our example: 22 working days and about 160 tickets on one agent's desk. Published benchmarks run from 50 to 250 tickets per technician a month (Rewired MSP and Rallied, 2026). Dollars at the $29 pack rate. Halo's pricing page lists £66 per agent per month, billed annually (6 Nov 2026), and a 30-day free trial.
| Credits | Price, one time | Calls at 10 credits | Per 1,000 credits |
|---|---|---|---|
| 5,000 | $29 | 500 | $5.80 |
| 15,000 | $79 | 1,500 | $5.27 |
| 32,000 | $149 | 3,200 | $4.66 |
| 60,000 | $249 | 6,000 | $4.15 |
Only successful calls use credits; failed calls and timeouts cost nothing. At a balance of 0 calls pause, never a surprise charge. Authenticate with the Authorization: Bearer header.
| Option | What it does | Where it stops |
|---|---|---|
| Halo MCP endpoint | Official. Tickets, private notes, knowledge base, users, assets, time, plus custom tools for logging tickets, reports and runbooks. | A Halo admin sets it up first. No tool for clients or timesheets in the guide. |
| WYRE-AI/halopsa-mcp | Apache-2.0, TypeScript. Tickets, clients, assets, contracts and reporting. 3 stars, last commit 29 Oct 2026. | You host it and give it a Halo API application. |
| redanthrax/halopsa-mcp | MIT, .NET. Tickets, agents, clients and reporting data, stdio or Streamable HTTP. 1 star, last commit 5 Nov 2026. | You run it in Docker or Helm with your own credentials. |
| DTC-Inc/halopsa-mcp | Rust. Ticket management, workflow actions and semantic search, sign-in passed through to Halo. 1 star, last commit 30 Oct 2026. | No license listed, and you host it. |
| ethergrade/ChatPSA | MIT. MCP server and agent desk for HaloPSA and Domotz troubleshooting. 1 star, last commit 21 Oct 2026. | Built for troubleshooting, and you host it. |
| n8n HaloPSA node | Official node with ready actions and HTTP Request for custom calls. | A workflow, not a chat agent. You build each flow on a Halo API application. |
Halo's own MCP endpoint is the right first look if your admin is happy to turn it on and its tools cover your job. The community servers suit a team that runs its own. Cotlet is for the service desk agent who wants the same jobs inside ChatGPT or Claude, plus clients and timesheets, with one sign-in and nothing to host.
Take Group sp. z o.o. runs Cotlet. It is a software company registered in Poland, EU (VAT PL6342984273), working since 2019, founded by Bart Krawczyk (Co-founder, CTO) and Jake Slugocki (Co-founder, SEO, sales and marketing). Write to contact@cotlet.dev with questions about the HaloPSA tools.
Sign up at cotlet.dev, log in to HaloPSA once in its Cloud Browser and add Cotlet to ChatGPT or Claude, following the steps in your console. No API key is needed. ChatGPT and Claude then work in your HaloPSA account through Cotlet, in their phone apps too.
With Cotlet, ChatGPT, Claude and other AI agents handle jobs like these in HaloPSA: triage new tickets; watch tickets close to their SLA target; draft a first reply from the knowledge base. You ask in plain words, and anything that reaches other people waits for your OK first.
Create a free account at https://cotlet.dev, open HaloPSA under Integrations in the console and log in to Halo in its Cloud Browser. The trial starts with your first app, no card asked.
It can, if a Halo admin turns it on and its tools cover your job. Halo's guide lists tools for tickets, the knowledge base, users, assets, reports and runbooks, set up under Configuration > AI > MCP Server with a Default AI Connection. Cotlet needs none of that setup and also reads clients and timesheets. Halo's guide says the MCP tools can run regardless of the agent's permissions when "Include all system tools" is on.
Cotlet works in your own agent login, so what your agent sees and changes follows the permissions Halo gives that login. If you cannot open a ticket type, a client or a report in Halo, your agent cannot either.
Yes. Cotlet is hosted, so the chat apps reach it by the shared address. Nothing runs on your computer.
Yes. Call Cotlet's REST API from a script or an HTTP step in n8n or Make with your Cotlet key. The same tools, inputs and price as MCP.
No. Cotlet is independent and not affiliated with Halo.
Free 7-day trial with 2,000 credits, no card needed.
May we use Google Analytics to see which pages help people? It sets cookies only if you accept. No ads, and we never sell data. Cookie policy