# HAL (remote · api.chatwithhal.com)

Customer conversations, help center, CRM, deals and email campaigns on HAL (chatwithhal.com).

- Trust score: 76/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

## Components

- remote · `api.chatwithhal.com`: 76/100 (this document), [markdown](https://verifymcp.io/servers/com-chatwithhal-mcp/api.md), [page](https://verifymcp.io/servers/com-chatwithhal-mcp/api)

## Channel facts

- Endpoint: `https://api.chatwithhal.com/mcp`
- Transports: `streamable-http`
- Auth: `required (not validated)`
- Version: `1.0.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-11-05.

- **Endpoint Security**: 89/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, but the challenge carries no valid RFC 9728 metadata, so a client cannot discover where to get a token.
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 63/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 15389 tokens (~113/item across 136 items; 136 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 20/100
  - Stability observed for 6 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 92/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 77% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 21 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "reply_to_conversation" implies "send" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 137 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the HAL MCP server?

HAL is a hosted endpoint at https://api.chatwithhal.com/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add --transport http com-chatwithhal-mcp 'https://api.chatwithhal.com/mcp'
```

### Cursor

```json
{
  "mcpServers": {
    "com-chatwithhal-mcp": {
      "url": "https://api.chatwithhal.com/mcp"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "com-chatwithhal-mcp": {
      "type": "http",
      "url": "https://api.chatwithhal.com/mcp"
    }
  }
}
```

### Codex

```toml
[mcp_servers.com-chatwithhal-mcp]
url = "https://api.chatwithhal.com/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "com-chatwithhal-mcp": {
      "type": "remote",
      "url": "https://api.chatwithhal.com/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add com-chatwithhal-mcp --url 'https://api.chatwithhal.com/mcp' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  com-chatwithhal-mcp:
    url: "https://api.chatwithhal.com/mcp"
```

### Netclaw

```json
{
  "McpServers": {
    "com-chatwithhal-mcp": {
      "Transport": "http",
      "Url": "https://api.chatwithhal.com/mcp"
    }
  }
}
```

### Vellum

```bash
assistant mcp add com-chatwithhal-mcp -t streamable-http -u 'https://api.chatwithhal.com/mcp'
```

### Other

```json
{
  "mcpServers": {
    "com-chatwithhal-mcp": {
      "type": "http",
      "url": "https://api.chatwithhal.com/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-11-05 (score 76, +1)

- [functional] New tool “delete_company”
- [functional] New tool “delete_contact”

### 2026-11-04 (score 75, +1)

No change was recorded against any check on this day. Stability & Change Management went from 13 to 17. That category is still filling its 30-day observation window: 4 days of observed history at the previous scan, 5 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-11-01 (score 74, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-31 (score 73, 0)

- [functional improvement] Stability: unverified → 0.03

### 2026-10-30 (score 73)

First indexed and scored.

## MCP tools (136)

### `list_projects` (~31 tokens)

List projects available to this MCP key. Call this first, then get_email_capabilities_overview for email features.

### `list_conversations` (~115 tokens)

List conversations with filters (status, spam, limit, offset). Each result says whether it is marked as spam.

Input parameters:

- `limit` (number): Max results to return
- `offset` (number): Offset for pagination
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `spam` (string): Spam filter: "exclude" hides spam like the inbox, "only" lists spam to review
- `status` (string): Filter by status

### `get_conversation` (~139 tokens)

Get a conversation with its messages and attachment metadata. agents_typing lists teammates drafting a reply right now; if someone is, let them answer instead of replying over them. replied_to_email is set when the conversation started as a reply to a campaign, workflow or broadcast email. Call get_conversation_image with an image attachment ID to inspect its visual content. To incorporate HAL's own evidence-backed AI draft into your final answer, call generate_ai_response_suggestion next.

Input parameters:

- `conversation_id` (string, required): The conversation ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_conversation_image` (~95 tokens)

Get an image attached to a conversation message as MCP image content so the AI client can inspect it. Images over 2 MB are resized and compressed before delivery. Use an attachment ID returned by get_conversation.

Input parameters:

- `attachment_id` (string, required): The image attachment ID returned by get_conversation
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `set_typing` (~172 tokens)

Show the visitor and your teammates in the dashboard that a reply is being written. Call it right before you draft a reply the visitor will read, so a live agent sees the conversation is being handled. Do not call it for internal notes, for reading or summarizing, or when you are not going to reply. reply_to_conversation clears it; call again with is_typing false if you decide not to reply.

Input parameters:

- `conversation_id` (string, required): The conversation ID
- `duration_seconds` (integer): Clear the indicator after this many seconds if no reply is sent
- `is_typing` (boolean): true while you draft the reply, false to clear it without replying
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `reply_to_conversation` (~409 tokens)

Send an agent message to a conversation. To show a help article to the visitor, write `[label](hal-article:<article id or slug>)` into the `content` of reply_to_conversation. The widget renders it as a clickable card at that spot, on its own line (it is not an inline link inside a sentence), so put it between sentences or paragraphs, e.g. "Refunds take 5 days.\n[Refund policy](hal-article:refund-policy)\nAnything else?". The label is the card title, so use the article title. Several cards in one reply are fine. Only published articles the visitor may see are accepted; each reference is checked and rewritten to the slug for the visitor's language. Find the right article with find_relevant_articles (matched to the conversation, or to your own query), or list_articles with published_only. To walk the visitor through a flow, pass `offer_guide_id` instead of writing guide markup. To send files, pass `attachments`; they are delivered with the message in the widget and in email replies.

Input parameters:

- `attachments` (array): Files to attach to the message (max 5)
- `content` (string): The message content. May contain article cards as `[label](hal-article:<article id or slug>)`, each on its own line where it belongs in the reply. May be empty when sending attachments.
- `conversation_id` (string, required): The conversation ID
- `is_internal` (boolean): Whether this is an internal note (not visible to visitor)
- `offer_guide_id` (string): Offer a guide below the message. The visitor gets a button that walks them through it on the page. Use a manual, enabled guide with a title (see list_guides). Do not write the guide markup into `cont…
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `update_conversation` (~214 tokens)

Update conversation status, assignment, snooze state, or spam. is_spam true does what "Mark as spam" does in the inbox: the conversation leaves the inbox, is marked read, and the same sender's next conversations in this project go straight to spam; is_spam false undoes it and lets the sender back in. The change is recorded in the conversation's activity as done via MCP. Use list_conversations with spam "only" to review spam.

Input parameters:

- `assigned_user_id` (string|null): User ID to assign (null to unassign)
- `conversation_id` (string, required): The conversation ID
- `is_spam` (boolean): true to mark the conversation as spam, false to unmark it
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `snoozed_until`: ISO 8601 time to snooze until (null to unsnooze)
- `status` (string): New status

### `generate_ai_response_suggestion` (~111 tokens)

Generate an advisory-only HAL AI reply suggestion for the latest visitor message. Call this after get_conversation, then combine HAL's draft, evidence, and confidence with the conversation messages when composing your final answer. This tool never sends a message to the visitor, even when project auto-send or AI deflection is enabled.

Input parameters:

- `conversation_id` (string, required): The conversation ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_article_groups` (~40 tokens)

List all article groups

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_article_group` (~92 tokens)

Create a new article group

Input parameters:

- `description` (string): Group description
- `name` (string, required): Group name
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `show_in_helpdesk` (boolean): Whether to show this group in the helpdesk (defaults to true)
- `slug` (string, required): URL-friendly slug

### `update_article_group` (~109 tokens)

Update an article group

Input parameters:

- `description` (string|null): New description
- `group_id` (string, required): The group ID
- `name` (string): New name
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `show_in_helpdesk` (boolean): Whether to show this group in the helpdesk
- `slug` (string): New slug
- `sort_order` (integer): New display order

### `list_articles` (~249 tokens)

List articles, optionally filtered by group or to published ones. To show a help article to the visitor, write `[label](hal-article:<article id or slug>)` into the `content` of reply_to_conversation. The widget renders it as a clickable card at that spot, on its own line (it is not an inline link inside a sentence), so put it between sentences or paragraphs, e.g. "Refunds take 5 days.\n[Refund policy](hal-article:refund-policy)\nAnything else?". The label is the card title, so use the article title. Several cards in one reply are fine. Only published articles the visitor may see are accepted; each reference is checked and rewritten to the slug for the visitor's language. Find the right article with find_relevant_articles (matched to the conversation, or to your own query), or list_articles with published_only.

Input parameters:

- `group_id` (string): Filter by group ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `published_only` (boolean): Only published articles, the ones that can be shared with a visitor

### `find_relevant_articles` (~334 tokens)

Find published help articles that fit a conversation, in the visitor's language and limited to ones this visitor may see. Matches the visitor's latest message, or `query` when given. Returns up to 6, best match first; weaker results can be only loosely related, so check the title and excerpt before sharing one. Read-only; uses no AI quota. Each result has `insert`, the exact markup to put in the reply. To show a help article to the visitor, write `[label](hal-article:<article id or slug>)` into the `content` of reply_to_conversation. The widget renders it as a clickable card at that spot, on its own line (it is not an inline link inside a sentence), so put it between sentences or paragraphs, e.g. "Refunds take 5 days.\n[Refund policy](hal-article:refund-policy)\nAnything else?". The label is the card title, so use the article title. Several cards in one reply are fine. Only published articles the visitor may see are accepted; each reference is checked and rewritten to the slug for the visitor's language. Find the right article with find_relevant_articles (matched to the conversation, or to your own query), or list_articles with published_only.

Input parameters:

- `conversation_id` (string, required): The conversation to find articles for
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `query` (string): What to look for, e.g. 'refund policy'. Defaults to the visitor's latest message.

### `get_article` (~51 tokens)

Get an article with translations

Input parameters:

- `article_id` (string, required): The article ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_article` (~124 tokens)

Create an article with an initial translation

Input parameters:

- `content` (string, required): Article content (Markdown)
- `group_id` (string|null): Group ID (null for ungrouped)
- `locale` (string): Locale for the initial translation
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `show_in_helpdesk` (boolean): Whether to show this article in the helpdesk (defaults to true)
- `slug` (string, required): URL-friendly slug
- `title` (string, required): Article title

### `update_article` (~160 tokens)

Update article properties or upsert a translation

Input parameters:

- `article_id` (string, required): The article ID
- `content` (string): Translation content in Markdown (requires locale)
- `group_id` (string|null): New group ID (null for ungrouped)
- `is_published` (boolean): Publish/unpublish
- `locale` (string): Locale to upsert translation for
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `show_in_helpdesk` (boolean): Whether to show in the helpdesk
- `slug` (string): New slug
- `sort_order` (integer): New display order
- `title` (string): Translation title (requires locale)

### `delete_contact` (~115 tokens)

Permanently delete a contact. Without confirm: true it only returns a preview of what would be removed. Deletes the contact with its deal links, company links and tracked email threads; its conversations stay, with their visitors made anonymous. Cannot be undone.

Input parameters:

- `confirm` (boolean): true to delete. Omit to get a preview and change nothing.
- `contact_id` (string, required): The contact ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_contacts` (~71 tokens)

List contacts with optional search

Input parameters:

- `limit` (number): Max results
- `offset` (number): Offset for pagination
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `search` (string): Search by name or email

### `get_contact` (~61 tokens)

Get a contact with full details, recent activity and the deals they are on

Input parameters:

- `contact_id` (string, required): The contact ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_contact` (~119 tokens)

Create a new contact

Input parameters:

- `email` (string): Contact email
- `metadata` (object): Flat custom metadata (max 50 keys, 10KB). Values: string, number, boolean, or null. Replaces entire object on write.
- `name` (string): Contact name
- `notes` (string): Notes
- `phone` (string): Contact phone
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `tags` (array): Tags

### `update_contact` (~136 tokens)

Update a contact

Input parameters:

- `contact_id` (string, required): The contact ID
- `email` (string): New email
- `metadata`: Flat custom metadata (max 50 keys, 10KB). Values: string, number, boolean, or null. Replaces entire object when set. Pass null or {} to clear.
- `name` (string): New name
- `notes` (string): New notes
- `phone` (string): New phone
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `tags` (array): New tags

### `delete_company` (~104 tokens)

Permanently delete a company. Without confirm: true it only returns a preview of what would be removed. Deletes the company with its deals and contact links; its contacts stay. Cannot be undone.

Input parameters:

- `company_id` (string, required): The company ID
- `confirm` (boolean): true to delete. Omit to get a preview and change nothing.
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_crm_stages` (~42 tokens)

List CRM pipeline stages

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_companies` (~107 tokens)

List companies with optional search and stage filter. Includes companies with no linked contacts. Paginated.

Input parameters:

- `limit` (number): Max results
- `offset` (number): Offset for pagination
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `search` (string): Search by name or notes
- `stage_id` (string|null): Filter by CRM stage ID. Pass null for unstaged companies only.

### `list_companies_by_stage` (~192 tokens)

Read-only CRM board: list ALL companies grouped by pipeline stage, including companies with no linked contacts and unstaged companies. Returns per-stage deal totals so agents can reconcile Won totals with company rows. Company stage and deal value mirror the company primary deal; use list_deals to see every deal, including expansions and renewals.

Input parameters:

- `include_unstaged` (boolean): Include companies with no stage. Default true. Ignored when stage_id or stage_name is set.
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `stage_id` (string): Optional: only include companies in this stage. Omits unstaged when set.
- `stage_name` (string): Optional: filter by stage name (case-insensitive, e.g. "Won"). Omits unstaged when set. Do not combine with stage_id.

### `get_company` (~67 tokens)

Get a company with contacts, details and its deals. The company stage and deal_value mirror its primary deal.

Input parameters:

- `company_id` (string, required): The company ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `link_contact_to_company` (~83 tokens)

Link an existing contact to an existing company. The operation is idempotent and both records must belong to the selected project.

Input parameters:

- `company_id` (string, required): The company ID
- `contact_id` (string, required): The contact ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_company` (~131 tokens)

Create a new company

Input parameters:

- `deal_value` (number): Deal value
- `domain` (string): Company domain
- `industry` (string): Industry
- `metadata` (object): Flat custom metadata (max 50 keys, 10KB). Values: string, number, boolean, or null. Replaces entire object on write.
- `name` (string, required): Company name
- `notes` (string): Notes
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `stage_id` (string): CRM stage ID

### `update_company` (~153 tokens)

Update a company

Input parameters:

- `company_id` (string, required): The company ID
- `deal_value` (number|null): New deal value
- `domain` (string|null): New domain
- `industry` (string|null): New industry
- `metadata`: Flat custom metadata (max 50 keys, 10KB). Values: string, number, boolean, or null. Replaces entire object when set. Pass null or {} to clear.
- `name` (string): New name
- `notes` (string): New notes
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `stage_id` (string|null): New stage ID

### `merge_companies` (~137 tokens)

Merge a duplicate company into a keeper. Contacts, tracked events, and CRM timeline move to the keeper; the source company is deleted. Use when the same org has a HAL-generated row and a later source-system (e.g. Apollo) id row. Refuses to merge companies that already have different external ids.

Input parameters:

- `keeper_company_id` (string, required): Company to keep. Prefer the older row when hydrating a source-system id.
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `source_company_id` (string, required): Duplicate company to absorb and delete

### `list_deals` (~166 tokens)

List deals (sales opportunities). A company can have several deals: new business, expansion, renewal. Each deal has a stage, amount, expected close date, owner, next step and contacts. Filter by company, contact, stage, owner or status.

Input parameters:

- `company_id` (string)
- `contact_id` (string): Deals this contact takes part in
- `limit` (number)
- `offset` (number)
- `owner_user_id` (string)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `search` (string): Search deal and company names
- `stage_id` (string|null): Pass null for deals with no stage
- `status` (string)

### `get_deal_pipeline` (~86 tokens)

Summarize the sales pipeline: per stage the number of deals, total and probability-weighted amount, plus open/won/lost totals, win rate and open deals whose expected close date has passed. Use list_deals for the deals themselves.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_deal` (~59 tokens)

Get a deal with its company, stage, contacts and stage/amount history

Input parameters:

- `deal_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_deal` (~307 tokens)

Create a deal for a company. The company's own stage and value follow its primary deal (its newest open new-business deal).

Input parameters:

- `amount`: Deal amount in the project's sales currency and value unit
- `company_id` (string, required)
- `contacts` (array): People involved in the deal
- `deal_type` (string): new_business, expansion or renewal
- `expected_close_date` (string|null): ISO 8601 date, e.g. 2026-12-31. Pass null to clear.
- `lost_reason` (string|null): Why the deal was lost. Kept only while the deal is in a lost stage.
- `name` (string): Deal name. Defaults to the company name.
- `next_step` (string|null): The next action to move the deal
- `next_step_due_at` (string|null): ISO 8601 date, e.g. 2026-12-31. Pass null to clear.
- `notes` (string|null)
- `owner_user_id` (string|null): User who owns the deal
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `source` (string|null): Where the deal came from, e.g. inbound, outbound, referral
- `stage_id` (string|null): CRM stage ID (see list_crm_stages). A 100% stage means won, 0% means lost.

### `update_deal` (~310 tokens)

Update a deal. Moving it to a 100% stage marks it won and a 0% stage marks it lost (pass lost_reason); moving it back to an open stage reopens it.

Input parameters:

- `amount`: Deal amount in the project's sales currency and value unit
- `deal_id` (string, required)
- `deal_type` (string): new_business, expansion or renewal
- `expected_close_date` (string|null): ISO 8601 date, e.g. 2026-12-31. Pass null to clear.
- `lost_reason` (string|null): Why the deal was lost. Kept only while the deal is in a lost stage.
- `name` (string): Deal name. Defaults to the company name.
- `next_step` (string|null): The next action to move the deal
- `next_step_due_at` (string|null): ISO 8601 date, e.g. 2026-12-31. Pass null to clear.
- `notes` (string|null)
- `owner_user_id` (string|null): User who owns the deal
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `source` (string|null): Where the deal came from, e.g. inbound, outbound, referral
- `stage_id` (string|null): CRM stage ID (see list_crm_stages). A 100% stage means won, 0% means lost.

### `set_deal_contact` (~71 tokens)

Add a contact to a deal, or change their role on it

Input parameters:

- `contact_id` (string, required)
- `deal_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `role`

### `remove_deal_contact` (~59 tokens)

Remove a contact from a deal

Input parameters:

- `contact_id` (string, required)
- `deal_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `delete_deal` (~59 tokens)

Delete a deal. A company with no deals left drops out of the pipeline.

Input parameters:

- `deal_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_email_capabilities_overview` (~63 tokens)

Orientation for HAL email features: campaigns vs workflows vs broadcasts, templates vs project defaults vs inline design, sender domains, images, test sending, track_event, and unsubscribe/suppression. Call this before creating any campaign, workflow, broadcast, or template.

### `list_email_templates` (~44 tokens)

List reusable workflow email templates for a project.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_email_template` (~50 tokens)

Get a reusable workflow email template.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `template_id` (string, required)

### `create_email_template` (~113 tokens)

New to HAL email? Call get_email_capabilities_overview first. Create a reusable workflow email template.

Input parameters:

- `blocks` (array): Shortcut for template_document.blocks
- `name` (string, required)
- `preheader` (string): Email preheader
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `subject` (string, required): Email subject
- `template_document` (object): Structured email document
- `theme` (object)

### `update_email_template` (~94 tokens)

Update a reusable workflow email template.

Input parameters:

- `blocks` (array)
- `name` (string)
- `preheader` (string)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `subject` (string)
- `template_document` (object)
- `template_id` (string, required)
- `theme` (object)

### `delete_email_template` (~57 tokens)

Delete a reusable workflow email template. Existing campaigns keep their embedded copy.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `template_id` (string, required)

### `preview_email_template` (~126 tokens)

Render an email template preview as subject, preheader, HTML, and plain text.

Input parameters:

- `blocks` (array): Shortcut for template_document.blocks
- `preheader` (string): Email preheader
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `sample_context` (object)
- `subject` (string): Email subject
- `template_document` (object): Structured email document
- `template_id` (string)
- `theme` (object)
- `workflow_name` (string)

### `validate_email_template` (~104 tokens)

Validate an email template and return AI-client-friendly errors.

Input parameters:

- `blocks` (array): Shortcut for template_document.blocks
- `preheader` (string): Email preheader
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `subject` (string): Email subject
- `template_document` (object): Structured email document
- `template_id` (string)
- `theme` (object)

### `send_test_email_template` (~143 tokens)

Send a workflow email template test to an account user email address only.

Input parameters:

- `blocks` (array): Shortcut for template_document.blocks
- `preheader` (string): Email preheader
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `sample_context` (object)
- `subject` (string): Email subject
- `template_document` (object): Structured email document
- `template_id` (string)
- `theme` (object)
- `to_email` (string, required): Recipient email. Must belong to a user on this account.
- `workflow_name` (string)

### `send_test_email_campaign` (~88 tokens)

Send a test email for an existing email campaign to an account user email address only.

Input parameters:

- `campaign_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `sample_context` (object)
- `to_email` (string, required): Recipient email. Must belong to a user on this account.

### `list_email_suppressions` (~70 tokens)

List email addresses suppressed for lifecycle email campaigns in a project.

Input parameters:

- `cursor` (string)
- `limit` (number)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `reason` (string)

### `suppress_email_recipient` (~119 tokens)

Suppress an email address so lifecycle email campaigns skip it. Defaults to category "all" (blocks everything); pass a specific category key (see list_email_categories) to block only that category.

Input parameters:

- `category` (string): EmailCategory key (see list_email_categories), or "all" for every category
- `email` (string, required)
- `note` (string)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `reason` (string)

### `unsuppress_email_recipient` (~106 tokens)

Remove an email address from the lifecycle email suppression list. Omit category to lift every suppression on the address (bounce/complaint rows are never removed); pass category to lift only that one.

Input parameters:

- `category` (string): EmailCategory key (see list_email_categories), or "all" for every category
- `email` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_email_unsubscribe_status` (~89 tokens)

Check whether an email address is currently suppressed for lifecycle email campaigns, for a given category (default "all").

Input parameters:

- `category` (string): EmailCategory key (see list_email_categories), or "all" for every category
- `email` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_email_campaigns` (~44 tokens)

List email campaigns backed by visitor workflows.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_email_campaign` (~48 tokens)

Get email campaign details.

Input parameters:

- `campaign_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_event_names` (~52 tokens)

List tracked lifecycle event names seen in a project.

Input parameters:

- `limit` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_custom_properties` (~59 tokens)

List visitor custom properties and sampled metadata keys available for campaign predicates and conditions.

Input parameters:

- `company_sample_limit` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_email_campaign` (~235 tokens)

New to HAL email? Call get_email_capabilities_overview first. Create an email campaign using campaign language instead of workflow graph internals.

Input parameters:

- `conditions` (array)
- `custom_frequency_key` (string)
- `delay_seconds` (number)
- `email_category` (string): Defaults to "marketing" if omitted
- `email_design` (object)
- `enabled` (boolean)
- `frequency` (string)
- `frequency_scope` (string)
- `name` (string, required)
- `next_campaign_id` (string): Optional campaign id to trigger after this campaign email is sent
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `reevaluate_conditions_at_send` (boolean)
- `skip_unengaged` (boolean): Skip contacts who received 5+ emails in the last 180 days without opening, clicking or replying to any (the sunset rule broadcasts use). Ignored for categories people cannot unsubscribe from. Default…
- `template_id` (string)
- `trigger` (object, required)

### `update_email_campaign` (~234 tokens)

Update an email campaign.

Input parameters:

- `campaign_id` (string, required)
- `conditions` (array)
- `custom_frequency_key` (string)
- `delay_seconds` (number)
- `email_category` (string): EmailCategory key (see list_email_categories), or "all" for every category
- `email_design` (object)
- `enabled` (boolean)
- `frequency` (string)
- `frequency_scope` (string)
- `name` (string)
- `next_campaign_id` (string|null): Campaign id to trigger after this campaign email is sent, or null to clear
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `reevaluate_conditions_at_send` (boolean)
- `skip_unengaged` (boolean): Skip contacts who received 5+ emails in the last 180 days without opening, clicking or replying to any (the sunset rule broadcasts use). Ignored for categories people cannot unsubscribe from. Default…
- `template_id` (string)
- `trigger` (object)

### `enable_email_campaign` (~48 tokens)

Enable an email campaign.

Input parameters:

- `campaign_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `disable_email_campaign` (~48 tokens)

Disable an email campaign.

Input parameters:

- `campaign_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `delete_email_campaign` (~68 tokens)

Delete an email campaign. Refuses if another workflow in the project still chains into it via trigger_campaign or next_campaign_id.

Input parameters:

- `campaign_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_email_campaign_runs` (~71 tokens)

List email campaign runs with delivery, open, and click data.

Input parameters:

- `campaign_id` (string, required)
- `cursor` (string)
- `limit` (number)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_email_campaign_run` (~61 tokens)

Get one email campaign run with clicked URLs.

Input parameters:

- `campaign_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `run_id` (string, required)

### `list_email_categories` (~68 tokens)

List a project's email categories used for per-category unsubscribe/preferences (marketing, product updates, transactional, ...). A project with no customized categories returns the built-in defaults.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `update_email_categories` (~86 tokens)

Replace the full set of email categories for a project (upserts by key, removes any key not included). Refused with the referencing suppressions/broadcasts/workflows if a key still in use would be removed.

Input parameters:

- `categories` (array, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_email_images` (~74 tokens)

List images in a project’s email image library, newest first. Use these for lifecycle/workflow email `image` blocks.

Input parameters:

- `cursor` (string)
- `limit` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `upload_email_image` (~206 tokens)

Upload an image to a project's email image library so it can be used in lifecycle/workflow email `image` blocks (email_block_types.image.url must be an absolute URL — external hosting is no longer required). Provide exactly one of data_base64 (with mime_type) or source_url. Use email_url in email image blocks (image.url).

Input parameters:

- `alt` (string): Alt text for the image
- `data_base64` (string): Base64-encoded image bytes, max 5MB decoded
- `filename` (string): Original filename for the data_base64 path, used to derive alt text when alt is omitted
- `mime_type` (string): Required with data_base64: image/jpeg, image/png, image/gif, or image/webp
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `source_url` (string): https/http URL to fetch the image from

### `delete_email_image` (~73 tokens)

Delete an image from a project’s email image library. Remove it from any email templates first, or the image block will break.

Input parameters:

- `image_id` (string, required): The email image ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_broadcasts` (~66 tokens)

List one-off email broadcasts for a project.

Input parameters:

- `cursor` (string)
- `limit` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `status` (string)

### `get_broadcast` (~123 tokens)

Get a single email broadcast, including delivery/open/click counts. With an A/B test, `ab_test` has its settings, `phase` (testing, waiting, winner_sending, done, skipped, cancelled), `ends_at` (automatic winner pick), the `winner`, and `results` (test-group sent/opens/clicks/rates per variant plus a confidence score).

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_broadcast` (~338 tokens)

New to HAL email? Call get_email_capabilities_overview first. Create a draft (or scheduled, if scheduled_at is set) one-off email broadcast. Does not send anything.

Input parameters:

- `ab_test` (object): Optional automatic A/B test: a random test group gets variant A (the main email) or B; after duration_hours the variant with the better winner_metric is sent to everyone else. Needs track_engagement…
- `audience` (object): Defaults to all contacts with an email
- `blocks` (array): Shortcut for template_document.blocks
- `category` (string): EmailCategory key (see list_email_categories); defaults to "marketing"
- `name` (string, required)
- `preheader` (string): Email preheader
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `scheduled_at` (string): ISO datetime to schedule the send
- `skip_recently_emailed` (boolean): Frequency cap: leave out contacts who got a broadcast in the last 24h (default true)
- `skip_role_addresses` (boolean): Leave out shared role mailboxes like info@ or admin@ (default false)
- `skip_unengaged` (boolean): Leave out contacts who got 5+ emails in the last 180 days without opening or clicking any (default true)
- `subject` (string, required): Email subject
- `template_document` (object): Structured email document
- `theme` (object)
- `track_engagement` (boolean): Open pixel + click tracking (default true)

### `update_broadcast` (~320 tokens)

Update a draft or scheduled broadcast (name, email content, audience, schedule, list-hygiene or tracking options, A/B test).

Input parameters:

- `ab_test` (object): Optional automatic A/B test: a random test group gets variant A (the main email) or B; after duration_hours the variant with the better winner_metric is sent to everyone else. Needs track_engagement…
- `audience` (object)
- `blocks` (array)
- `broadcast_id` (string, required)
- `category` (string): EmailCategory key (see list_email_categories); defaults to "marketing"
- `name` (string)
- `preheader` (string)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `scheduled_at` (string|null): ISO datetime, or null to unschedule
- `skip_recently_emailed` (boolean): Frequency cap: leave out contacts who got a broadcast in the last 24h (default true)
- `skip_role_addresses` (boolean): Leave out shared role mailboxes like info@ or admin@ (default false)
- `skip_unengaged` (boolean): Leave out contacts who got 5+ emails in the last 180 days without opening or clicking any (default true)
- `subject` (string)
- `template_document` (object)
- `theme` (object)
- `track_engagement` (boolean): Open pixel + click tracking (default true)

### `delete_broadcast` (~55 tokens)

Delete a broadcast. Refused while it is actively sending.

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `preview_broadcast_audience` (~221 tokens)

Preview who a broadcast (or a candidate audience) would reach: match count, suppressed count, contacts left out by list hygiene (invalid/disposable/role addresses, unengaged, recently emailed) per reason, and a sample.

Input parameters:

- `audience` (object): Override audience to preview before saving
- `broadcast_id` (string): Preview the audience already saved on this broadcast
- `category` (string): Only used with audience (no broadcast_id); defaults to "marketing"
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `skip_recently_emailed` (boolean): Frequency cap: leave out contacts who got a broadcast in the last 24h (default true)
- `skip_role_addresses` (boolean): Leave out shared role mailboxes like info@ or admin@ (default false)
- `skip_unengaged` (boolean): Leave out contacts who got 5+ emails in the last 180 days without opening or clicking any (default true)

### `get_broadcast_audience_fields` (~62 tokens)

List the fields available for building a broadcast audience (contact/company builtins, sampled metadata keys, valid operators per type).

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `send_test_broadcast_email` (~120 tokens)

Send a test of a broadcast email to an account user email address only (never to real contacts).

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `sample_contact_id` (string): Contact to source sample merge fields from
- `to_email` (string, required): Recipient email. Must belong to a user on this account.
- `variant` (string): A/B test variant to send (default a, the main email)

### `schedule_broadcast` (~69 tokens)

Schedule a draft (or reschedule a scheduled) broadcast to send at a future time.

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `scheduled_at` (string, required)

### `send_broadcast_now` (~158 tokens)

IMMEDIATELY sends this broadcast to its whole live audience - a real, irreversible email blast to real contacts, not a test. You MUST call preview_broadcast_audience first and pass its exact `count` as confirm_recipient_count; a mismatch is refused. Call get_broadcast_readiness first too: sends with blocking deliverability checks are refused. Only call this after the user has explicitly confirmed they want to send to that many recipients right now.

Input parameters:

- `broadcast_id` (string, required)
- `confirm_recipient_count` (integer, required): Must exactly equal the current preview_broadcast_audience count
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `cancel_broadcast` (~64 tokens)

Cancel a scheduled, in-progress, or paused broadcast. Recipients not yet sent to are marked cancelled.

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_broadcast_recipients` (~78 tokens)

List the per-recipient delivery status for a broadcast.

Input parameters:

- `broadcast_id` (string, required)
- `cursor` (string)
- `limit` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `status` (string)

### `get_broadcast_readiness` (~123 tokens)

Deliverability checklist for a broadcast before sending: sender authentication (custom domain, DMARC, MAIL FROM/SPF), postal address, project bounce/complaint health, warm-up capacity (how many days the send will be spread over), and content lint (size, image-heavy, subject, spam phrases, link shorteners). `error` checks block sending; share warnings with the user.

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `resume_broadcast` (~121 tokens)

Resume a paused broadcast. Broadcasts auto-pause when their bounce or spam-complaint rate is too high, or when a scheduled send hits a blocking deliverability check; `pause_reason` says why. Only resume after the user understands the reason and has addressed it (e.g. removed bad addresses). The remaining recipients are sent to, and it pauses again if rates stay high.

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `select_broadcast_ab_winner` (~130 tokens)

End a broadcast's A/B test early and send the winner to the rest of the audience now, instead of waiting for the automatic pick. `ab_test.results` on get_broadcast shows each variant's open/click rates. Pass `variant` to choose it; omit it to send the current leader. This sends real email to the remaining recipients: confirm with the user first.

Input parameters:

- `broadcast_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `variant` (string)

### `get_email_deliverability` (~275 tokens)

Project email reporting. Always returns: health (last 30 days across every campaign, workflow and broadcast: sent, sent_last_24h, delivered, hard bounces (bounced), soft bounces, complaints and their rates, plus the status that blocks broadcasts, and reset_at when a list-cleanup reset restarted the window), sources (the same window broken down per workflow/broadcast with delivered, hard/soft bounces, unique opens, clicks and replies), warm-up progress (only broadcasts count toward it), and the footer postal address. Pass workflow_id or broadcast_id (optionally with days; omitted = all time) to also get stats for that one campaign. Opens and clicks exclude automatic ones from security scanners and Apple Mail Privacy Protection, which are reported as automatic_opens/automatic_clicks. Replies count recipients who answered the email (auto-replies are ignored). Delivered counts only cover emails sent after delivery tracking was enabled.

Input parameters:

- `broadcast_id` (string): Broadcast to report on
- `days` (integer): Trailing window for the workflow_id/broadcast_id stats; omitted = all time
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_id` (string): Campaign/workflow to report on

### `update_email_postal_address` (~84 tokens)

Set the physical mailing address shown in the footer of every marketing/lifecycle email (required by CAN-SPAM). Pass null or an empty string to remove it. Confirm the exact address with the user first.

Input parameters:

- `postal_address` (required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `reset_email_deliverability_health` (~309 tokens)

Start a fresh 30-day health window for a project that is blocked from sending broadcasts by old bounces or complaints. ONLY use this after the bounced and complained addresses have been suppressed (list_email_suppressions / suppress_email_recipient) so the same list cannot bounce again. HAL enforces this: the reset is refused, and nothing changes, if any recipient that bounced or complained in the current window is not suppressed (by a project-wide or platform-wide suppression), and a project can be reset at most once per 30 days. Once it succeeds, sends before the reset stop counting toward the project's bounce and complaint rate, and any new bounces after it count normally and can block the project again. This only resets HAL's own project health window; it does not change the Amazon SES account reputation or review status. Per-broadcast auto-pause is not affected. Cannot be undone and is logged: get explicit user confirmation, then pass confirm: true and a reason describing the cleanup (3-500 characters). Returns the updated health (including reset_at).

Input parameters:

- `confirm` (boolean, required): Must be true: confirms the bounced/complained addresses were suppressed
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `reason` (string, required): What was cleaned up, e.g. "Suppressed all 312 hard-bounced addresses from the March 2026 import" (3-500 characters)

### `get_workflow_builder_reference` (~65 tokens)

New to HAL email? Call get_email_capabilities_overview first. Static reference for building visitor workflows through create_workflow/update_workflow/validate_workflow: trigger shapes, node types, graph rules, condition/predicate operators, email block types, and variable syntax.

### `list_workflows` (~68 tokens)

List visitor workflows for a project (trigger + branching graph automations), ordered by priority.

Input parameters:

- `enabled` (boolean)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `trigger_type` (string)

### `get_workflow` (~56 tokens)

Get a visitor workflow including its full node/edge graph definition.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_id` (string, required)

### `validate_workflow` (~123 tokens)

Validate a visitor workflow definition without saving it. Same input as create_workflow.

Input parameters:

- `definition` (object, required)
- `enabled` (boolean)
- `frequency` (string)
- `name` (string, required)
- `priority` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `trigger_config` (object): Shape depends on trigger_type; call get_workflow_builder_reference first.
- `trigger_mode` (string)
- `trigger_type` (string, required)

### `create_workflow` (~153 tokens)

New to HAL email? Call get_email_capabilities_overview first. Create a visitor workflow: a trigger plus a branching graph of condition/send_widget_message/send_email/trigger_campaign/end nodes. Call get_workflow_builder_reference first.

Input parameters:

- `definition` (object, required)
- `enabled` (boolean)
- `frequency` (string)
- `name` (string, required)
- `priority` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `trigger_config` (object): Shape depends on trigger_type; call get_workflow_builder_reference first.
- `trigger_mode` (string)
- `trigger_type` (string, required)

### `update_workflow` (~132 tokens)

Update a visitor workflow. Partial: only provided fields change. If trigger fields change without a new definition, the existing trigger node is synced in place.

Input parameters:

- `definition` (object)
- `enabled` (boolean)
- `frequency` (string)
- `name` (string)
- `priority` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `trigger_config` (object)
- `trigger_mode` (string)
- `trigger_type` (string)
- `workflow_id` (string, required)

### `delete_workflow` (~68 tokens)

Delete a visitor workflow. Refuses if another workflow in the project still chains into it via trigger_campaign or next_campaign_id.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_id` (string, required)

### `set_workflow_enabled` (~58 tokens)

Enable or disable a visitor workflow.

Input parameters:

- `enabled` (boolean, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_id` (string, required)

### `reorder_workflows` (~61 tokens)

Reorder visitor workflows by priority; the first id in the list gets the highest priority.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_ids` (array, required)

### `list_workflow_executions` (~68 tokens)

List execution history for a visitor workflow.

Input parameters:

- `cursor` (string)
- `limit` (integer)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_id` (string, required)

### `get_workflow_execution` (~58 tokens)

Get one visitor workflow execution.

Input parameters:

- `execution_id` (string, required)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `workflow_id` (string, required)

### `get_workflow_email_defaults` (~51 tokens)

Get the project default email design used to seed new send_email nodes.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `update_workflow_email_defaults` (~112 tokens)

Update the project default email design (subject/preheader/theme/template_document) used to seed new send_email nodes. Merges into the project config without touching other settings.

Input parameters:

- `blocks` (array): Shortcut for template_document.blocks
- `preheader` (string)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `subject` (string)
- `template_document` (object)
- `theme` (object)

### `send_test_workflow_email` (~112 tokens)

Send a real test email for one send_email node in a workflow to an account user email address only.

Input parameters:

- `node_id` (string): Required if the workflow has more than one send_email node
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `sample_context` (object)
- `to_email` (string, required): Recipient email. Must belong to a user on this account.
- `workflow_id` (string, required)

### `list_test_email_recipients` (~23 tokens)

List account user emails allowed as workflow/email test recipients.

### `track_event` (~271 tokens)

Track a lifecycle event exactly like the public track-event API. THIS CAN SEND REAL EMAILS: matching enabled api_trigger workflows fire immediately for real contacts. Use dry_run to preview matches without tracking or sending anything. Workflows only fire for events that resolve to a visitor (via user_id or email); company-only events never trigger workflows.

Input parameters:

- `company_id` (string)
- `contact_name` (string)
- `dry_run` (boolean): If true, does not track anything or send emails; only reports which enabled api_trigger workflows would match
- `email` (string)
- `entity` (string)
- `event_key` (string): Idempotency key; a repeat call with the same key returns the original event
- `metadata` (object): Contact properties. Only fills properties the contact does not have yet (missing, null or empty), unless overwrite_metadata is true.
- `name` (string, required)
- `occurred_at` (string): ISO timestamp; defaults to now
- `overwrite_metadata` (boolean): Replace existing contact properties with the metadata values
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `user_id` (string)
- `value` (string|number|boolean|null)

### `list_automations` (~44 tokens)

List all automations for this project

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_automation` (~50 tokens)

Get automation details

Input parameters:

- `automation_id` (string, required): The automation ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_automation` (~120 tokens)

Create a new automation

Input parameters:

- `delay_seconds` (number): Delay before showing
- `enabled` (boolean): Whether enabled
- `frequency` (string): How often to fire
- `messages` (object, required): Messages by locale (e.g. {"en": "Hello!"})
- `name` (string, required): Automation name
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `trigger_config` (object): Trigger configuration
- `trigger_type` (string, required): Trigger type

### `update_automation` (~121 tokens)

Update an automation

Input parameters:

- `automation_id` (string, required): The automation ID
- `delay_seconds` (number): New delay
- `enabled` (boolean): Enable/disable
- `frequency` (string): New frequency
- `messages` (object): New messages by locale
- `name` (string): New name
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `trigger_config` (object): New trigger configuration
- `trigger_type` (string): New trigger type

### `toggle_automation` (~64 tokens)

Enable or disable an automation

Input parameters:

- `automation_id` (string, required): The automation ID
- `enabled` (boolean, required): Whether to enable or disable
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_guides` (~42 tokens)

List all guides for this project

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_guide` (~50 tokens)

Get guide details

Input parameters:

- `guide_id` (string, required): The guide ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_guide` (~345 tokens)

Create a new guide

Input parameters:

- `conditions` (object): Audience conditions, evaluated server-side: an ineligible visitor receives nothing at all. guide.completed:<id> and event.count:<name> enable completion-style targeting (e.g. not_exists on guide.comp…
- `delay_seconds` (number): Delay before showing
- `description` (object): One-line description by locale. Shown under the title.
- `enabled` (boolean): Whether enabled
- `frequency` (string): How often to show
- `name` (string, required): Guide name (internal label, not shown to visitors). A slug for host-page calls is generated from it and returned.
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `show_in_suggestions` (boolean): Offer this guide to a visitor typing a matching question. Requires `title`. Independent of trigger_type: a route guide may fire on arrival and still be offered in chat.
- `start_url` (string): Where this guide runs, as a same-origin path template against the visitor's stored properties, e.g. "{{app_base_path}}/documents/add/invoice". When a visitor starts the guide from elsewhere, the widg…
- `steps` (array, required): Guide steps
- `title` (object): Guide title by locale, e.g. {"en":"Change your plan"}. Shown to visitors.
- `trigger_config` (object): Trigger configuration
- `trigger_type` (string, required): Trigger type

### `update_guide` (~249 tokens)

Update a guide

Input parameters:

- `conditions` (object): Audience conditions, evaluated server-side before the guide is sent. Pass an empty rules array to clear.
- `delay_seconds` (number): New delay
- `description` (object): One-line description by locale.
- `enabled` (boolean): Enable/disable
- `frequency` (string): New frequency
- `guide_id` (string, required): The guide ID
- `name` (string): New name. The slug does NOT change — host-page calls keep working across renames.
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `show_in_suggestions` (boolean): Offer this guide to a visitor typing a matching question. Independent of trigger_type.
- `start_url` (string): Where this guide runs — same-origin path template, e.g. "{{app_base_path}}/documents/add/invoice". Empty string clears it.
- `steps` (array): New steps
- `title` (object): Guide title by locale. Shown to visitors.
- `trigger_config` (object): New trigger config
- `trigger_type` (string): New trigger type

### `toggle_guide` (~64 tokens)

Enable or disable a guide

Input parameters:

- `enabled` (boolean, required): Whether to enable or disable
- `guide_id` (string, required): The guide ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `delete_guide` (~56 tokens)

Permanently delete a guide and its execution history

Input parameters:

- `guide_id` (string, required): The guide ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_guide_stats` (~89 tokens)

Per-guide analytics: triggers, completions, completion rate, per-step drop-off, selector misses

Input parameters:

- `guide_id` (string, required): The guide ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `since_days` (number): Count only executions from the last N days. Omit for all time.

### `get_guide_health` (~78 tokens)

Which guides had steps fail to anchor recently — the signal that a selector rotted in the target app

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `since_days` (number): Look at misses from the last N days. Default: 7.

### `validate_guide` (~110 tokens)

Validate a guide's start location and step selectors against the live pages the developer is logged into. Results are recorded by the widget's authoring mode (?hal_guide_debug=1 on any page where the widget runs); this tool returns the newest snapshot per page, so a guide that spans pages reports each of them.

Input parameters:

- `guide_id` (string, required): The guide ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `tag_message` (~99 tokens)

Add tags to a message. Merges with existing tags (deduplicates). If Damper integration is enabled and a tag matches tags_to_sync, pushes the conversation to Damper as feedback.

Input parameters:

- `message_id` (string, required): The message ID to tag
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `tags` (array, required): Tags to add to the message

### `untag_message` (~63 tokens)

Remove specific tags from a message

Input parameters:

- `message_id` (string, required): The message ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `tags` (array, required): Tags to remove

### `list_message_tags` (~43 tokens)

List all tags defined for this project

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_message_tags_stats` (~45 tokens)

Get all project tags with their usage counts

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_teams` (~47 tokens)

List all teams for this project with member and conversation counts

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_team` (~52 tokens)

Get a team with its members

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `team_id` (string, required): The team ID

### `list_macros` (~45 tokens)

List shared macros (available to all team members)

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `get_macro` (~53 tokens)

Get a single shared macro by ID

Input parameters:

- `macro_id` (string, required): The macro ID
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `list_webhooks` (~43 tokens)

List all webhooks for this project

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `create_webhook` (~88 tokens)

Create a new webhook

Input parameters:

- `events` (array, required): Event types to subscribe to (e.g. conversation.created, message.created)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `secret` (string): Optional HMAC secret for signature verification
- `url` (string, required): The webhook URL to receive events

### `update_webhook` (~97 tokens)

Update an existing webhook

Input parameters:

- `enabled` (boolean): Enable or disable the webhook
- `events` (array): New event types
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `secret` (string|null): New secret (null to remove)
- `url` (string): New webhook URL
- `webhook_id` (string, required): The webhook ID

### `delete_webhook` (~50 tokens)

Delete a webhook

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `webhook_id` (string, required): The webhook ID

### `get_statistics` (~107 tokens)

Get project statistics including responsiveness, conversation volume, and per-agent metrics. Defaults to last 30 days.

Input parameters:

- `end_date` (string): End date (ISO 8601, e.g. 2025-01-31)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `start_date` (string): Start date (ISO 8601, e.g. 2025-01-01)

### `get_sender_domain` (~83 tokens)

Get the custom sender domain (Starter plan and above) configured for this project, including DNS records, verification status, and any Reply-To override (`sender_domain.reply_to`, alongside the top-level `reply_to` this project's emails actually use).

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `configure_sender_domain` (~204 tokens)

Configure a custom sender domain for visitor-facing email on this project (Starter plan and above). Returns DNS records (DKIM CNAMEs, and MX/TXT if a mail-from subdomain is set) that the user must add themselves at their DNS provider before the domain can verify. Reply-To stays on the HAL inbound address so inbound routing keeps working, unless a Reply-To override is set afterwards with update_sender_identity.

Input parameters:

- `domain` (string, required): The domain to send from, e.g. mail.yourcompany.com
- `local_part` (string, required): The local part of the From address, e.g. "support"
- `mail_from_subdomain` (string): Optional custom MAIL FROM subdomain label, e.g. "bounce"
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `sender_name` (string): Display name to use in From. Defaults to the project name.

### `check_sender_domain` (~48 tokens)

Re-check the project's custom sender domain verification status against Amazon SES.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `update_sender_identity` (~212 tokens)

Update the local part, display sender name, and/or Reply-To override of the configured sender domain, without changing the domain itself. By default, Reply-To stays on the HAL inbound address so inbound routing/threading keep working. Setting `reply_to` overrides that with the given address - it must already forward into the project's HAL inbound address, or replies will be lost. Pass an empty string or omit `reply_to` as `null` to clear an existing override and revert to the HAL address.

Input parameters:

- `local_part` (string): New local part of the From address
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `reply_to` (string|null): Reply-To override, a single bare email address (e.g. support@yourcompany.com) that already forwards into the HAL inbound address. Pass an empty string or null to clear the override.
- `sender_name` (string): New display name to use in From

### `remove_sender_domain` (~53 tokens)

Remove the project's custom sender domain. Visitor-facing email reverts to the default Hal address.

Input parameters:

- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

### `import_conversation` (~117 tokens)

Import a single historical conversation silently (no webhooks, no notifications). Use for migrating data from other chat platforms.

Input parameters:

- `conversation` (object): Conversation metadata (defaults to resolved status)
- `messages` (array, required): Messages to import (1-1000, ordered chronologically)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)
- `visitor` (object, required): Visitor info — matched by email first, then user_id, then external_id, or creates new

### `import_conversations` (~82 tokens)

Import multiple historical conversations in batch (max 100). Each conversation is imported independently — one failure does not affect others. Silent: no webhooks, no notifications.

Input parameters:

- `conversations` (array, required): Conversations to import (1-100)
- `project_id` (string): Target project ID
- `project_slug` (string): Target project slug (helpdesk slug)

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/com-chatwithhal-mcp/api#diagnostics

## Score history

- 2026-11-05: 76
- 2026-11-04: 75
- 2026-11-03: 74
- 2026-11-02: 74
- 2026-11-01: 74
- 2026-10-31: 73
- 2026-10-30: 73

## Common questions

### What is the HAL MCP server?

HAL is an MCP server listed in the public MCP registry as com.chatwithhal/mcp. Customer conversations, help center, CRM, deals and email campaigns on HAL (chatwithhal.com). This page covers its hosted endpoint (https://api.chatwithhal.com/mcp).

### Is the HAL MCP server safe to use?

HAL scores 76 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the HAL MCP server expose?

HAL exposes 136 tools: list_projects, list_conversations, get_conversation, get_conversation_image, set_typing, and 131 more. Their descriptions and schemas cost roughly 15,129 tokens of context every time the server is loaded.

### Does the HAL MCP server require authentication?

Yes. HAL asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.

### Is the HAL MCP server still maintained?

HAL is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- Remote endpoint: https://api.chatwithhal.com/mcp
- Authorisation metadata: https://api.chatwithhal.com/.well-known/oauth-protected-resource/mcp
- Website: https://chatwithhal.com/docs/mcp
- Changelog RSS feed: https://verifymcp.io/servers/com-chatwithhal-mcp/api.xml
- Changelog JSON feed: https://verifymcp.io/servers/com-chatwithhal-mcp/api.json
- HTML version of this page: https://verifymcp.io/servers/com-chatwithhal-mcp/api
