Read projects and conversations
List projects, inspect conversations, and use customer context without rebuilding the model outside HAL.
Use MCP when Claude, Cursor, or another compatible client should work with HAL project data through tools. HAL does not provide a local stdio server.
POST https://api.chatwithhal.com/mcpUse an account-scoped MCP key from Settings → API. Clients should call list_projects first, then include project_id or project_slug for project-scoped tools.
{
"mcpServers": {
"hal": {
"type": "streamable-http",
"url": "https://api.chatwithhal.com/mcp",
"headers": {
"X-API-Key": "YOUR_HAL_ACCOUNT_MCP_KEY"
}
}
}
}List projects, inspect conversations, and use customer context without rebuilding the model outside HAL.
Read or update company records, articles, groups, and other structured project data through tools.
MCP gives AI clients access to HAL. It does not turn HAL into an unsupervised external execution layer.
Design reusable branded email templates, create delayed onboarding campaigns, enable them, and inspect delivery, open, and click history.
Use the email campaign tools when an AI client should configure onboarding or lifecycle email without asking an operator to build the workflow graph manually. Campaigns are project-scoped, so use separate HAL projects or explicit project_id/project_slug selection for brands such as Space Invoices and Apollo white-label.
list_email_templates, get_email_template, create_email_template, update_email_template, delete_email_template, preview_email_template, validate_email_template, and send_test_email_templatelist_email_campaigns, get_email_campaign, create_email_campaign, update_email_campaign, enable_email_campaign, disable_email_campaign, delete_email_campaign, send_test_email_campaign, list_email_campaign_runs, and get_email_campaign_runlist_email_suppressions, suppress_email_recipient, unsuppress_email_recipient, and get_email_unsubscribe_statuslist_event_names and list_custom_properties help AI clients choose valid event names, visitor properties, campaign condition fields, and sampled visitor, contact, and company metadata keys.visitor, contact, company, or a stable custom_key.next_campaign_id can chain another campaign after the current email sends successfully.For the full trigger, frequency, predicate, delayed send, and troubleshooting reference, see Lifecycle email campaigns.
This sequence creates a branded welcome email, previews it, schedules it one day after a visitor is first seen, enables it, then checks delivery history.
// 1. Create a reusable template
create_email_template({
project_slug: "space-invoices",
name: "Welcome onboarding",
subject: "Welcome to {{project_name}}",
preheader: "A quick setup path for {{visitor_name}}",
theme: {
primary_color: "#2563eb",
content_width: "regular",
corner_radius: "md"
},
blocks: [
{ "id": "h1", "type": "heading", "level": 1, "text": "Welcome, {{visitor_name}}" },
{ "id": "p1", "type": "paragraph", "text": "Here are the first steps to get value from {{project_name}}." },
{ "id": "cta", "type": "button", "text": "Open setup", "url": "https://example.com/setup" },
{ "id": "footer", "type": "footer_note", "text": "Sent to {{visitor_email}}" }
]
})
// 2. Preview or validate before enabling
preview_email_template({
project_slug: "space-invoices",
template_id: "workflow-email-template-..."
})
// 3. Send a test email to an account user before scheduling
send_test_email_template({
project_slug: "space-invoices",
template_id: "workflow-email-template-...",
to_email: "founder@example.com"
})
// 4. Create the delayed campaign, disabled by default unless enabled is true
create_email_campaign({
project_slug: "space-invoices",
name: "Welcome one day after first seen",
template_id: "workflow-email-template-...",
trigger: { "type": "first_seen" },
next_campaign_id: "optional-followup-campaign-id",
delay_seconds: 86400,
reevaluate_conditions_at_send: true,
frequency: "once_ever"
})
// 5. Enable when ready
enable_email_campaign({
project_slug: "space-invoices",
campaign_id: "..."
})
// 6. Inspect runs
list_email_campaign_runs({
project_slug: "space-invoices",
campaign_id: "..."
})Lifecycle campaigns can use normal campaign conditions, property-match predicates, and account-scoped frequency when onboarding should happen once per workspace instead of once per teammate.
// Discover event names, condition fields, visitor/contact metadata, and company metadata first
list_event_names({ project_slug: "space-invoices" })
list_custom_properties({ project_slug: "space-invoices" })
// Send once per company if no invoice is issued within 24 hours, only for Slovene recipients
create_email_campaign({
project_slug: "space-invoices",
name: "No first invoice after account creation",
template_id: "workflow-email-template-...",
trigger: {
type: "no_event_after",
anchor_event: "account.created",
missing_event: "invoice.issued",
within_seconds: 86400,
scope: "company"
},
frequency: "once_ever",
frequency_scope: "company",
conditions: [
{ field: "visitor_metadata.locale", operator: "equals", value: "sl" },
{ field: "contact_metadata.locale", operator: "equals", value: "sl" },
{ field: "company_metadata.plan", operator: "equals", value: "trialing" },
{ field: "company_metadata.first_invoice_sent", operator: "is_false" }
]
})list_custom_properties returns condition_fields for normal event, no-event, page-visit, and first-seen campaign conditions. It always includes built-in fields such as browser_language, visitor_metadata.locale, and contact_metadata.locale, then adds sampled metadata keys such as company_metadata.plan. Use browser_language for the browser locale and metadata fields when your product stores a user-selected locale on the visitor or contact.
Template subjects, preheaders, and body blocks can render built-in values, visitor custom properties, and prefixed metadata fields. Use fallback syntax for optional fields so emails stay readable when data is missing.
create_email_template({
project_slug: "space-invoices",
name: "Personalized activation",
subject: "Welcome {{visitor_name | \"there\"}}",
blocks: [
{
id: "p1",
type: "paragraph",
text: "Your {{company_metadata.plan | \"trial\"}} workspace is ready."
},
{
id: "p2",
type: "paragraph",
text: "We will use {{visitor_metadata.locale | \"en\"}} for product tips."
}
]
})
validate_email_template({
project_slug: "space-invoices",
template_id: "workflow-email-template-..."
})validate_email_template returns warnings for likely typo variables such as {{pla}}. Prefixed metadata variables remain allowed even when the project has not sampled that key yet.
Every lifecycle email includes a signed unsubscribe URL and one-click unsubscribe headers. Unsubscribed or manually suppressed recipients are skipped before provider delivery. Use suppression tools to inspect or manage the project suppression list from MCP.
suppress_email_recipient({
project_slug: "space-invoices",
email: "customer@example.com",
reason: "manual"
})
get_email_unsubscribe_status({
project_slug: "space-invoices",
email: "customer@example.com"
})Use next_campaign_id when a campaign should start another campaign after a successful send. Skipped and failed sends do not trigger the next campaign. Run responses include triggered_by_campaign with source workflow, source execution, chain id, and chain depth when a campaign was started by another campaign.
Accept headers are normalized for plain HTTP clients.reevaluate_conditions_at_send is enabled, HAL also re-runs the workflow path and skips with conditions_no_longer_match if the visitor or company no longer qualifies.scope: "custom_key" support visitor_id, contact_id, or company_id; use company metadata predicates for account-specific attributes such as plan or workspace state.event_key values from your backend so retries do not duplicate campaign triggers.