Hail
Phone, SMS and email for AI agents. One remote MCP endpoint, OAuth login, zero install.
Should I use this
Quality & Safety
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"hail-mcp": {
"url": "https://mcp.hail.so"
}
}
}Remote endpoints
https://mcp.hail.sostreamable-httpWhat it can do
Tool inventory
Tools (36)
π‘place_call(to, recipient_consent, system_prompt, llm, from_, ...)
Originate an outbound phone call. Provide ``system_prompt`` (mode A β Hail's bundled fallback LLM uses this prompt) or ``llm`` (mode B β bring your own OpenAI-compatible endpoint as ``{"base_url": ..., "api_key": ..., "model": ...}``), or both, or ``agent_id`` (a saved agent from ``list_agents`` supplies the prompt, first message, AI line, voice and tools; fields you pass here win). At least one is required. Passing both runs your prompt on your own endpoint: it receives Hail's voice preamble plus your prompt as the leading system message. ``to`` must be E.164 (e.g. ``+14155551234``). ``from_`` is optional and defaults to the first active number on your org. ``first_message`` is spoken verbatim on pickup; omit it to let the agent open the conversation itself β it reacts to how the call was answered, or introduces itself after silence. ``language`` sets the call's spoken language for speech-to-text, text-to-speech, and turn detection, as a lowercase ISO 639-1 code (e.g. ``"da"``); 39 languages are supported (server rejects others with 422); omit for English. STT provider selection is console-BYO-only (no per-call override); configure it on the organization to pin a provider. ``ai_disclosure=False`` skips the spoken "this is an AI assistant" line at the start of the call. Leave enabled unless the user has verified it is not required for this call β US artificial-voice calls (47 CFR 64.1200(b)(1)) and several AI bot-disclosure laws require it, and Hail does not verify this. The agent still identifies itself as an AI if asked. ``metadata`` is free-form JSON attached to the call record. ``tools`` are the agent tools to allow on this call. Omit for all available; pass ``[]`` to disable. ``recipient_consent`` is required and must be the JSON boolean ``true`` (strings and numbers are refused): attest that you (the caller triggering this request) have obtained the lawful consent needed to contact this recipient. The API rejects the request (422) if this is not ``true`` β Hail does not verify consent for you, you are responsible for having a lawful basis (TCPA / ePrivacy / GDPR as applicable). Set ``message_type="marketing"`` for promotional calls (this additionally requires a non-empty ``consent_source`` describing how/where consent was obtained) β leave as the default ``"informational"`` for transactional/service calls. ``idempotency_key`` defaults to a fresh UUID per invocation and is returned in the response under ``idempotency_key`` β to retry *this* exact request (rather than dispatch a second call), pass the value back on the retry. A new key is a new call. Example: place_call(to="+14155551234", recipient_consent=True, system_prompt="You are scheduling a haircut.", first_message="Hi, I'm calling on behalf of Alex.") Returns the API's ``CallResponse`` as a dict (id, status, from_e164, to_e164, ...). On failure returns ``{"error": "<message>"}`` instead.
Input Schema
{
"type": "object",
"properties": {
"to": {
"title": "To",
"type": "string"
},
"recipient_consent": {
"title": "Recipient Consent",
"type": "boolean"
},
"system_prompt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "System Prompt"
},
"llm": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Llm"
},
"from_": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "From"
},
"first_message": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "First Message"
},
"language": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Language"
},
"ai_disclosure": {
"default": true,
"title": "Ai Disclosure",
"type": "boolean"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Metadata"
},
"tools": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Tools"
},
"idempotency_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Idempotency Key"
},
"consent_source": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Consent Source"
},
"consent_obtained_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Consent Obtained At"
},
"message_type": {
"default": "informational",
"title": "Message Type",
"type": "string"
},
"agent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent Id"
}
},
"required": [
"to",
"recipient_consent"
],
"title": "place_call_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "place_call_toolDictOutput"
}π‘send_email(to, subject, recipient_consent, body_text, body_html, ...)
Send an outbound email through your configured SES sender. ``to`` is a non-empty list of RFC-style email addresses. At least one of ``body_text`` / ``body_html`` is required (both is fine β multipart-alternative). Prefer including ``body_html``: open and click tracking only works for emails with an HTML body. A plain-text-only email still gets sent, delivered, and bounce events, but opens and clicks are never tracked. ``cc``, ``bcc``, and ``reply_to`` are optional and follow the usual mail conventions. Hail sets no ``reply_to`` of its own β to have replies reach the human running this session, call ``whoami`` and pass their ``email``. ``recipient_consent`` is required and must be the JSON boolean ``true`` (strings and numbers are refused): attest that you (the caller triggering this request) have obtained the lawful consent needed to email this recipient. The API rejects the request (422) if this is not ``true`` β Hail does not verify consent for you. Set ``message_type="marketing"`` for promotional email (this additionally requires a non-empty ``consent_source`` describing how/where consent was obtained) β leave as the default ``"informational"`` for transactional/service email. ``from_`` is optional only while the workspace has one verified sender identity. With several, omitting it returns 422 listing them β call ``list_email_domains`` and pass one. With none, the server auto-mints a per-org hail-mail address of the form ``<user>+<org>@<base>`` if the operator configured ``HAIL_MAIL_BASE_DOMAIN`` (the ``<org>`` part is derived from your organization id; the ``<user>`` part comes from ``HAIL_MAIL_FROM`` / ``HAIL_MAIL_DEFAULT_USER_PREFIX``, or an explicit row created via ``POST /email-domains``). When supplied, ``from_`` must match a verified row already in ``email_domains`` (register one with the website console or ``POST /email-domains``). ``from_name`` is an optional display name rendered on the From: header ("Acme Billing <[email protected]>"). Control characters are rejected. ``metadata`` is free-form JSON attached to the email record. ``idempotency_key`` defaults to a fresh UUID and is returned in the response under ``idempotency_key`` β pass the same value on a retry to replay rather than re-send. A new key is a new message. ``attachment_ids`` are ids returned by ``upload_email_attachment`` β upload a file first, then pass its id(s) here to attach it. Example: send_email(to=["[email protected]"], subject="Welcome", recipient_consent=True, body_text="Thanks for signing up.") Returns the ``EmailResponse`` dict (id, status, from_address, to_addresses, sent_at, provider_message_id, ...). On failure returns ``{"error": "<message>"}`` instead.
Input Schema
{
"type": "object",
"properties": {
"to": {
"items": {
"type": "string"
},
"title": "To",
"type": "array"
},
"subject": {
"title": "Subject",
"type": "string"
},
"recipient_consent": {
"title": "Recipient Consent",
"type": "boolean"
},
"body_text": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Body Text"
},
"body_html": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Body Html"
},
"from_": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "From"
},
"from_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "From Name"
},
"cc": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Cc"
},
"bcc": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Bcc"
},
"reply_to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Reply To"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Metadata"
},
"idempotency_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Idempotency Key"
},
"consent_source": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Consent Source"
},
"consent_obtained_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Consent Obtained At"
},
"message_type": {
"default": "informational",
"title": "Message Type",
"type": "string"
},
"attachment_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Attachment Ids"
}
},
"required": [
"to",
"subject",
"recipient_consent"
],
"title": "send_email_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "send_email_toolDictOutput"
}π‘upload_email_attachment(content_base64, filename, content_type)
Upload a file to attach to a future outbound email. ``content_base64`` is the file's raw bytes, base64-encoded. Returns ``{"id": ..., "filename": ..., "content_type": ..., "size_bytes": ...}`` β pass ``id`` in ``send_email``'s ``attachment_ids`` list. The id is reusable across many sends and expires in 24h if never used. Files over 25MB (combined with the message body and any other attachments, per send) are rejected β host large files externally and link to them in the body instead.
Input Schema
{
"type": "object",
"properties": {
"content_base64": {
"title": "Content Base64",
"type": "string"
},
"filename": {
"title": "Filename",
"type": "string"
},
"content_type": {
"title": "Content Type",
"type": "string"
}
},
"required": [
"content_base64",
"filename",
"content_type"
],
"title": "upload_email_attachment_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "upload_email_attachment_toolDictOutput"
}π’get_call(call_id)
Fetch the current state of one call by id. Use this after ``place_call`` (or to check on any prior call) to read the call's latest ``status`` and timing fields. Returns the API's ``CallResponse`` as a dict, or ``{"error": "call not found"}`` for an unknown id.
Input Schema
{
"type": "object",
"properties": {
"call_id": {
"title": "Call Id",
"type": "string"
}
},
"required": [
"call_id"
],
"title": "get_call_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_call_toolDictOutput"
}π’list_calls(cursor, limit, status, to)
List recent calls in your organization, newest first. Cursor-paginated: pass the previous response's ``next_cursor`` to fetch the next page. ``status`` (one of queued, dialing, ringing, in_progress, completed, failed, busy, no_answer, canceled) and ``to`` (E.164) are optional server-side filters. Returns a dict ``{"items": [...], "next_cursor": <str|None>}``.
Input Schema
{
"type": "object",
"properties": {
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
},
"limit": {
"default": 50,
"title": "Limit",
"type": "integer"
},
"status": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Status"
},
"to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "To"
}
},
"title": "list_calls_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_calls_toolDictOutput"
}π‘send_sms(to, body, recipient_consent, from_, metadata, ...)
Send an outbound SMS. ``to`` must be E.164 (e.g. ``+14155551234``). ``body`` is the message text. With no ``from_``: UK (+44) and Germany (+49) destinations use your organization's sender ID (or ``HAIL``, the platform default); Australia (+61) always uses ``HAIL``; every other destination uses your organization's oldest active SMS-capable number and the API returns 422 when there is none. SMS never uses the shared voice-call pool. ``recipient_consent`` is required and must be the JSON boolean ``true`` (strings and numbers are refused): attest that you (the caller triggering this request) have obtained the lawful consent needed to text this recipient. The API rejects the request (422) if this is not ``true`` β Hail does not verify consent for you. Set ``message_type="marketing"`` for promotional texts (this additionally requires a non-empty ``consent_source``) β leave as the default ``"informational"`` for transactional/service texts. ``idempotency_key`` defaults to a fresh UUID and is returned in the response under ``idempotency_key`` β pass the same value on a retry to replay rather than re-send. Example: send_sms(to="+14155551234", body="Your order shipped!", recipient_consent=True) Returns the ``SmsResponse`` dict (id, status, from_e164, to_e164, segment_count, ...). On failure returns ``{"error": "<message>"}`` instead.
Input Schema
{
"type": "object",
"properties": {
"to": {
"title": "To",
"type": "string"
},
"body": {
"title": "Body",
"type": "string"
},
"recipient_consent": {
"title": "Recipient Consent",
"type": "boolean"
},
"from_": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "From"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Metadata"
},
"idempotency_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Idempotency Key"
},
"consent_source": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Consent Source"
},
"consent_obtained_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Consent Obtained At"
},
"message_type": {
"default": "informational",
"title": "Message Type",
"type": "string"
}
},
"required": [
"to",
"body",
"recipient_consent"
],
"title": "send_sms_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "send_sms_toolDictOutput"
}π’get_sms(sms_id)
Fetch the current state of one SMS by id. Use this after ``send_sms`` to check delivery status. Example: get_sms(sms_id="...")
Input Schema
{
"type": "object",
"properties": {
"sms_id": {
"title": "Sms Id",
"type": "string"
}
},
"required": [
"sms_id"
],
"title": "get_sms_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_sms_toolDictOutput"
}π’list_sms(cursor, limit, status, to)
Page through recent SMS messages for your organization. ``status`` filters to one of: queued, sent, delivered, failed, undelivered, received. ``to`` filters to messages sent to a specific E.164 number. Paginate with the returned ``next_cursor``.
Input Schema
{
"type": "object",
"properties": {
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
},
"limit": {
"default": 50,
"title": "Limit",
"type": "integer"
},
"status": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Status"
},
"to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "To"
}
},
"title": "list_sms_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_sms_toolDictOutput"
}π’get_email(email_id)
Fetch the full record of one email by id. Returns the complete row β including ``body_text`` / ``body_html`` and (for inbound mail) the ``in_reply_to`` / ``message_id`` headers and ``spam``/``virus``/``spf``/``dkim``/``dmarc`` verdicts. Use this after ``list_emails`` to read a received reply's body. Returns the API's ``EmailResponse`` as a dict, or ``{"error": "resource not found"}`` for an unknown id.
Input Schema
{
"type": "object",
"properties": {
"email_id": {
"title": "Email Id",
"type": "string"
}
},
"required": [
"email_id"
],
"title": "get_email_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_email_toolDictOutput"
}π’list_emails(cursor, limit, status, direction)
List emails in your organization, newest first. Cursor-paginated: pass the previous response's ``next_cursor`` to fetch the next page. Two optional server-side filters: * ``direction`` β ``outbound`` or ``inbound``. Pass ``direction="inbound"`` to read replies and other received mail. * ``status`` β one of ``queued``, ``sent``, ``failed``, ``bounced``, ``complained``, ``received``. Items are trimmed summaries (no message body). Call ``get_email`` with an item's ``id`` to read the full body. Example: list_emails(direction="inbound") Returns ``{"items": [...], "next_cursor": <str|None>}`` on success, or ``{"error": "<message>"}`` instead.
Input Schema
{
"type": "object",
"properties": {
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
},
"limit": {
"default": 50,
"title": "Limit",
"type": "integer"
},
"status": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Status"
},
"direction": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Direction"
}
},
"title": "list_emails_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_emails_toolDictOutput"
}π’get_email_raw(email_id)
Get a fetchable URL for an email's original MIME source. Returns ``{"url": "<presigned-s3-url>"}`` β a short-lived (~5 minute) link to the full raw RFC822 message. Fetch the URL directly to read the complete original; it needs no auth header. Raw source exists for **inbound** mail only β outbound ids return ``{"error": "resource not found"}``.
Input Schema
{
"type": "object",
"properties": {
"email_id": {
"title": "Email Id",
"type": "string"
}
},
"required": [
"email_id"
],
"title": "get_email_raw_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_email_raw_toolDictOutput"
}π’get_email_attachment(email_id, attachment_id)
Get a fetchable URL for one inbound email attachment. ``attachment_id`` comes from an item in ``get_email``'s ``attachments`` list. Returns ``{"url": "<presigned-s3-url>"}`` β a short-lived (~5 minute) link to the attachment bytes, fetchable directly with no auth header. Unknown ids return ``{"error": "resource not found"}``.
Input Schema
{
"type": "object",
"properties": {
"email_id": {
"title": "Email Id",
"type": "string"
},
"attachment_id": {
"title": "Attachment Id",
"type": "string"
}
},
"required": [
"email_id",
"attachment_id"
],
"title": "get_email_attachment_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_email_attachment_toolDictOutput"
}π’get_email_events(email_id, cursor, limit)
Delivery/engagement timeline (sentβdeliveredβopenedβ¦) for one email. Chronological lifecycle events for a single email β use this to see exactly what happened to one message (bounced? opened? clicked?) rather than the account-wide aggregates ``get_email_stats`` returns. Returns ``{"items": [...], "next_cursor": ...}`` where each item has ``kind`` (one of sent, delivered, delivery_delayed, bounced, complained, rejected, opened, clicked), ``payload``, and ``occurred_at``. ``opened`` and ``clicked`` only occur for emails sent with an HTML body. A plain-text-only email still gets sent, delivered, and bounce events, but opens and clicks are never tracked. Pass ``cursor`` from a previous ``next_cursor`` to page (``limit`` 1..1000, default 100). On failure returns ``{"error": "resource not found"}`` for an unknown id.
Input Schema
{
"type": "object",
"properties": {
"email_id": {
"title": "Email Id",
"type": "string"
},
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Limit"
}
},
"required": [
"email_id"
],
"title": "get_email_events_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_email_events_toolDictOutput"
}π’get_email_stats(from_, to, bucket)
Account-level email deliverability stats (counts, rates, time series). Aggregates across your whole organization's outbound mail over a window β use this for "how's deliverability doing" rather than one message's history (``get_email_events`` covers that). ``from_`` / ``to`` are ISO 8601 timestamps (defaults: last 7 days ending now). ``bucket`` is ``"day"`` (default) or ``"hour"`` β ``"hour"`` is limited to an 8-day span; any range is capped at 92 days. Returns ``{"from": ..., "to": ..., "bucket": ..., "totals": {...}, "rates": {...}, "series": [...]}`` β ``totals``/each ``series`` bucket carry counts (sent, delivered, bounced, opened, ...) and ``rates`` carries derived ratios (delivery, bounce, open, click), each ``None`` when ``totals.sent`` is 0. Open and click numbers only count HTML emails. Plain-text-only emails are never tracked for opens or clicks, so they lower those rates. On failure returns ``{"error": "<message>"}`` instead.
Input Schema
{
"type": "object",
"properties": {
"from_": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "From"
},
"to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "To"
},
"bucket": {
"default": "day",
"title": "Bucket",
"type": "string"
}
},
"title": "get_email_stats_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_email_stats_toolDictOutput"
}π’get_events(id, kind, cursor, limit)
Page through events from across the org or one resource. Pass ``id="<type>:<uuid>"`` to narrow to a single resource β supported types are ``call``, ``email``, and ``sms`` (e.g. ``id="sms:<uuid>"`` after ``send_sms``). When narrowed to a call, the response includes a ``call_status`` field reflecting the call's current state. Without ``id``, returns events from across the whole org. ``kind`` filters server-side by event kind (``state_change``, ``agent_turn``, ``user_turn``, ``tool_call``, ``error``, ...). This is **not** a streaming subscription β the call returns whatever events exist now plus a ``next_cursor`` if more pages remain. To follow a call to completion, loop: pass the previous response's ``next_cursor`` until ``next_cursor`` is null and, when narrowed to a call, ``call_status`` is one of ``completed``, ``failed``, ``busy``, ``no_answer``, ``canceled`` (the terminal set). Example: get_events(id="call:0c2f...-...", limit=200) Returns ``{"items": [...], "next_cursor": <str|None>, "call_status": <str|None>}`` on success, or ``{"error": ...}`` on a malformed ``id`` or upstream failure.
Input Schema
{
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Id"
},
"kind": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Kind"
},
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
},
"limit": {
"default": 100,
"title": "Limit",
"type": "integer"
}
},
"title": "get_events_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_events_toolDictOutput"
}π’list_agents
List the workspace's saved agents: the brains that answer calls and texts on its numbers, and that ``place_call`` can use via ``agent_id``. Returns ``{"items": [{"id", "name", "system_prompt", "first_message", "ai_disclosure", "ai_disclosure_line", "voice_config", "tools", "max_duration_seconds", "handover_max_duration_seconds", "voice_enabled", "sms_enabled", "status", "handover_contacts"}, ...]}``.
Input Schema
{
"type": "object",
"properties": {},
"title": "list_agents_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_agents_toolDictOutput"
}π‘create_agent(name, system_prompt, first_message, ai_disclosure, ai_disclosure_line, ...)
Save an agent. Then call ``route_number`` so a number answers with it, or pass its id as ``agent_id`` to ``place_call``. ``system_prompt`` is what the agent follows. ``first_message`` is spoken after the AI line; omit it to let the caller speak first. ``ai_disclosure_line`` replaces the workspace AI line for this agent; ``{org}`` becomes the organization name. ``language`` is a lowercase ISO 639-1 code. ``max_duration_seconds`` is 60..3600. ``handover_max_duration_seconds`` (60..3600, default 1800) is the call limit once a handover contact answers. ``handover_contacts``: People the agent may hand a live call to: ``[{contact_id, note}]`` (max 10; ``note`` 1-200 chars says when to hand over). ``contact_id`` is an id from ``list_contacts``: a contact's uuid, or ``member:<user id>`` for a team member. The person needs a phone number. The agent never sees it. Returns the API's ``AgentResponse`` as a dict, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"system_prompt": {
"title": "System Prompt",
"type": "string"
},
"first_message": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "First Message"
},
"ai_disclosure": {
"default": true,
"title": "Ai Disclosure",
"type": "boolean"
},
"ai_disclosure_line": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Ai Disclosure Line"
},
"language": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Language"
},
"voice_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Voice Id"
},
"tools": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Tools"
},
"max_duration_seconds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Max Duration Seconds"
},
"handover_max_duration_seconds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Handover Max Duration Seconds"
},
"voice_enabled": {
"default": true,
"title": "Voice Enabled",
"type": "boolean"
},
"sms_enabled": {
"default": true,
"title": "Sms Enabled",
"type": "boolean"
},
"handover_contacts": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Handover Contacts"
}
},
"required": [
"name",
"system_prompt"
],
"title": "create_agent_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "create_agent_toolDictOutput"
}π’route_number(number_id, voice_agent_id, sms_agent_id, clear_voice, clear_sms)
Choose which agent answers a number's calls and texts. ``voice_agent_id`` makes the number answer calls with that agent (Hail registers it for inbound at the carrier and LiveKit); ``clear_voice=True`` stops answering calls. ``sms_agent_id`` makes the agent reply to texts; ``clear_sms=True`` stops that. A field left out keeps its value. ``number_id`` comes from GET /numbers. Returns the updated ``PhoneNumberResponse`` as a dict, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"number_id": {
"title": "Number Id",
"type": "string"
},
"voice_agent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Voice Agent Id"
},
"sms_agent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Sms Agent Id"
},
"clear_voice": {
"default": false,
"title": "Clear Voice",
"type": "boolean"
},
"clear_sms": {
"default": false,
"title": "Clear Sms",
"type": "boolean"
}
},
"required": [
"number_id"
],
"title": "route_number_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "route_number_toolDictOutput"
}π’quote_numbers(country_code, capabilities, number_type, provider)
Compare live phone-number offers from the carriers. Read-only: it buys nothing and charges nothing. ``country_code`` is an ISO alpha-2 code such as ``"US"``. ``capabilities`` is ``["voice"]``, ``["sms"]`` or both (default). ``number_type`` is ``local``, ``mobile``, ``national`` or ``toll_free``; omit it to compare all types. ``provider`` is ``auto`` (compare all carriers), ``twilio``, ``telnyx`` or ``didww``. Returns ``{"offers": [...], "recommended_quote_id", "unavailable_providers", "expires_at"}``. Each offer has ``e164``, ``provider``, ``number_type``, ``capabilities``, ``monthly_cents``, ``setup_cents``, ``readiness``, ``requirements`` and ``quote_id``. Money fields are cents (USD). Quotes expire in 10 minutes (``expires_at``); quote again after that. An offer with ``readiness == "verification_required"`` cannot be bought until the organization is verified. Call get_verification_requirements, ask the user for the details, then submit_verification and poll get_verification (review takes business days). ``requirements`` lists what the carrier needs. Prefer an offer whose ``readiness`` is ``"ready"``; ``recommended_quote_id`` points at the best one, or is null if none is ready. Errors come back as ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"country_code": {
"title": "Country Code",
"type": "string"
},
"capabilities": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Capabilities"
},
"number_type": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Number Type"
},
"provider": {
"default": "auto",
"title": "Provider",
"type": "string"
}
},
"required": [
"country_code"
],
"title": "quote_numbers_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "quote_numbers_toolDictOutput"
}π΄acquire_number(quote_id, country_code, number_type, confirm_total_cents, provider, ...)
Buys a real phone number. It charges the setup fee and the first month now and renews monthly. Call quote_numbers first. Pass the offer's quote_id, country_code, number_type, and confirm_total_cents = monthly_cents + setup_cents from that offer. If the quote expired or the price changed (409) you get an error: quote again. Only buy when your user asked for this number. After buying, call route_number to point it at an agent. A quote buys at most one number. After a timeout, retry with the same quote_id and idempotency_key, or check list_numbers. Never request a new quote after a timeout. ``provider`` is ``auto`` (the quoted carrier) or the quoted carrier's name. ``idempotency_key`` is optional; to retry after a timeout or a 5xx, pass the ``idempotency_key`` that result returned, so the number is bought once. A 4xx error returns no key: the API remembers that failure under it, so drop it and quote again. Returns the number (``id``, ``e164``, ``provisioning_state``, ...) plus ``idempotency_key``, or ``{"error": "<message>", "idempotency_key": ...}``.
Input Schema
{
"type": "object",
"properties": {
"quote_id": {
"title": "Quote Id",
"type": "string"
},
"country_code": {
"title": "Country Code",
"type": "string"
},
"number_type": {
"title": "Number Type",
"type": "string"
},
"confirm_total_cents": {
"title": "Confirm Total Cents",
"type": "integer"
},
"provider": {
"default": "auto",
"title": "Provider",
"type": "string"
},
"idempotency_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Idempotency Key"
}
},
"required": [
"quote_id",
"country_code",
"number_type",
"confirm_total_cents"
],
"title": "acquire_number_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "acquire_number_toolDictOutput"
}π’list_numbers(limit, cursor)
List the workspace's dedicated phone numbers, newest first. ``limit`` is 1..200 (default 50). Pass the returned ``next_cursor`` as ``cursor`` for the next page. Returns ``{"items": [{"id", "e164", "provider", "country_code", "number_type", "capabilities", "provisioning_state", "voice_agent_id", "sms_agent_id", ...}], "next_cursor"}``, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"limit": {
"default": 50,
"title": "Limit",
"type": "integer"
},
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
}
},
"title": "list_numbers_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_numbers_toolDictOutput"
}π’get_number(number_id)
Fetch one dedicated number by id: its state, capabilities and which agents answer its calls and texts. ``number_id`` comes from ``list_numbers``. Returns the ``PhoneNumberResponse`` as a dict, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"number_id": {
"title": "Number Id",
"type": "string"
}
},
"required": [
"number_id"
],
"title": "get_number_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_number_toolDictOutput"
}π΄release_number(number_id, confirm_e164)
Release a phone number. DESTRUCTIVE and permanent. Calls and texts to the number stop. This month's fee and any earlier months are still billed. There is no refund. The number may not be recoverable. Ask the user before calling this. ``confirm_e164`` must equal the number's ``e164`` (for example ``"+14155550100"``). The tool reads the number first and refuses with ``{"error": ...}`` on a mismatch, without releasing anything. A number whose order is still pending cannot be released (409). A number whose order failed was never bought: the call only hides it from the list and returns ``{"dismissed": true, "number_id", "e164"}``. Returns ``{"released": true, "number_id", "e164"}``, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"number_id": {
"title": "Number Id",
"type": "string"
},
"confirm_e164": {
"title": "Confirm E164",
"type": "string"
}
},
"required": [
"number_id",
"confirm_e164"
],
"title": "release_number_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "release_number_toolDictOutput"
}π’get_verification_requirements(country_code, number_type, subject_type, provider)
Read what the carrier needs to verify the organization before it can buy a number. Call this when quote_numbers shows an offer with ``readiness == "verification_required"``. Read-only. ``country_code`` is ISO alpha-2 (for example ``"GB"``). ``number_type`` is ``local``, ``mobile``, ``national`` or ``toll_free``. ``subject_type`` is ``person`` (default) or ``business``; the result's ``subject_types`` lists what the carrier accepts. ``provider`` is optional. Returns ``required`` (false means no verification is needed and submit_verification would fail), ``fields`` (values to collect), ``documents`` (slots, each with ``options``), ``address_required``. Skip any document slot whose ``needs_input`` is false: do not send it. Ask the USER for every value and every file. Never invent, guess or infer personal or company data. Never reuse data from another task. Errors come back as ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"country_code": {
"title": "Country Code",
"type": "string"
},
"number_type": {
"title": "Number Type",
"type": "string"
},
"subject_type": {
"default": "person",
"title": "Subject Type",
"type": "string"
},
"provider": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Provider"
}
},
"required": [
"country_code",
"number_type"
],
"title": "get_verification_requirements_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_verification_requirements_toolDictOutput"
}π΄submit_verification(country_code, number_type, fields, documents, files, ...)
Send the user's personal or company details and identity documents to the carrier for verification. IRREVERSIBLE: once submitted it cannot be cancelled, and the carrier keeps the documents. ``attest_authorized``: pass true only if the person or company named in these details and documents asked for this submission and gave you the details and files in this conversation. Never invent, guess, infer or reuse personal data or documents. Anything else: pass false (the call then sends nothing). Steps: 1) call get_verification_requirements. 2) Ask the user for each field and file. 3) Call this once. Do not submit twice: a 409 means one already exists (see list_verifications). Arguments, as listed by get_verification_requirements: ``fields`` is ``{field name: value}``. ``address`` is ``{"customer_name", "street", "city", "region", "postal_code", "country_code"}`` (all required when ``address_required``). ``documents`` is ``{slot: {"option": <option key>, "fields": {...}}}`` for each slot with ``needs_input``. ``files`` is a list of ``{"slot", "content_type", "content_base64"}``, one per slot that needs a file; ``slot`` must be a key in ``documents`` and match letters, digits, - and _ (at most 64). ``content_type`` is ``image/jpeg``, ``image/png`` or ``application/pdf``. Limits: 10 MiB per file, 29 MiB in total, at most 20 files and 20 fields. Compress images to JPG or PNG under about 7 MiB so the call stays small. Returns the verification: ``id`` and ``state`` (no personal data). Review takes business days and nothing notifies you: poll get_verification. If the carrier finds a problem you get ``{"error", "problems": [{"loc", "msg"}]}`` and nothing is stored: ask the user to fix it, then submit again. After a timeout call list_verifications before trying again.
Input Schema
{
"type": "object",
"properties": {
"country_code": {
"title": "Country Code",
"type": "string"
},
"number_type": {
"title": "Number Type",
"type": "string"
},
"fields": {
"title": "Fields"
},
"documents": {
"title": "Documents"
},
"files": {
"title": "Files"
},
"attest_authorized": {
"title": "Attest Authorized",
"type": "boolean"
},
"subject_type": {
"default": "person",
"title": "Subject Type",
"type": "string"
},
"address": {
"default": null,
"title": "Address"
},
"provider": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Provider"
}
},
"required": [
"country_code",
"number_type",
"fields",
"documents",
"files",
"attest_authorized"
],
"title": "submit_verification_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "submit_verification_toolDictOutput"
}π’list_verifications
List the organization's carrier verifications, newest first. Returns ``{"items": [{"id", "provider", "country_code", "number_type", "subject_type", "state", "rejection_reason", "created_at", "updated_at", "submitted_at", "approved_at"}]}``. ``state`` is ``awaiting_review``, ``submitting``, ``submitted``, ``approved``, ``rejected`` or ``cancelled``. Use it to check whether a submission already exists before submitting again. Errors come back as ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {},
"title": "list_verifications_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_verifications_toolDictOutput"
}π’get_verification(verification_id)
Fetch one verification and its state. Use it to poll. There is no notification, and review takes business days. Poll every few minutes to hours, not every few seconds; the state refreshes from the carrier at most once a minute. On ``approved``: call quote_numbers again. The offer is now ``ready``; then acquire_number. On ``rejected``: read ``rejection_reason``, ask the user, dismiss it with cancel_verification, then submit a new one. ``verification_id`` comes from submit_verification or list_verifications. Returns ``{"id", "state", "rejection_reason", ...}`` or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"verification_id": {
"title": "Verification Id",
"type": "string"
}
},
"required": [
"verification_id"
],
"title": "get_verification_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_verification_toolDictOutput"
}π΄cancel_verification(verification_id)
Cancel a verification that has not been sent for review, or dismiss a rejected one (needed before submitting a new one for the same country and number type). The draft is discarded. Works only in state ``awaiting_review`` or ``rejected``. A ``submitting`` or ``submitted`` verification is under review and cannot be cancelled (409): wait for the result with get_verification. Returns the verification with ``state: "cancelled"``, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"verification_id": {
"title": "Verification Id",
"type": "string"
}
},
"required": [
"verification_id"
],
"title": "cancel_verification_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "cancel_verification_toolDictOutput"
}π’get_agent(agent_id)
Fetch one saved agent by id. ``agent_id`` comes from ``list_agents`` or ``create_agent``. Returns the ``AgentResponse`` as a dict (``name``, ``system_prompt``, ``first_message``, ``ai_disclosure``, ``voice_config``, ``tools``, ``voice_enabled``, ``sms_enabled``, ``status``, ...), or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"agent_id": {
"title": "Agent Id",
"type": "string"
}
},
"required": [
"agent_id"
],
"title": "get_agent_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "get_agent_toolDictOutput"
}π΄update_agent(agent_id, name, system_prompt, first_message, ai_disclosure, ...)
Change a saved agent. Safe to repeat: the same call gives the same result. Only the fields you pass change; a field left out keeps its value. ``status`` is ``"live"`` or ``"paused"``; a paused agent does not answer. ``language`` is a lowercase ISO 639-1 code. Pass ``language`` or ``voice_id`` alone: the other value is kept. ``max_duration_seconds`` and ``handover_max_duration_seconds`` are 60..3600. ``handover_contacts`` replaces the whole list: ``[{contact_id, note}]`` (max 10) as in ``create_agent``; ``[]`` removes every contact. To remove a value, list its name in ``clear_fields``. Allowed: ``first_message`` (the agent waits for the caller), ``ai_disclosure_line`` (back to the workspace line), ``tools`` (back to all tools), ``max_duration_seconds`` (back to the workspace limit), ``handover_max_duration_seconds`` (back to 1800). Any other name is refused. Do not set and clear one field. Live calls keep the settings they started with. The change applies to the next call or text. Returns the updated ``AgentResponse`` as a dict, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"agent_id": {
"title": "Agent Id",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Name"
},
"system_prompt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "System Prompt"
},
"first_message": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "First Message"
},
"ai_disclosure": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Ai Disclosure"
},
"ai_disclosure_line": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Ai Disclosure Line"
},
"language": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Language"
},
"voice_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Voice Id"
},
"tools": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Tools"
},
"max_duration_seconds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Max Duration Seconds"
},
"handover_max_duration_seconds": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Handover Max Duration Seconds"
},
"voice_enabled": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Voice Enabled"
},
"sms_enabled": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Sms Enabled"
},
"status": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Status"
},
"handover_contacts": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Handover Contacts"
},
"clear_fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Clear Fields"
}
},
"required": [
"agent_id"
],
"title": "update_agent_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "update_agent_toolDictOutput"
}π΄delete_agent(agent_id, confirm_name)
Delete a saved agent. DESTRUCTIVE. Ask the user before calling this. Numbers that used the agent stop answering with it: calls ring out and texts reach webhooks only. Reroute them first with ``route_number`` if that matters. ``confirm_name`` must equal the agent's ``name``. The tool reads the agent first and refuses with ``{"error": ...}`` on a mismatch, without deleting anything. To stop an agent without deleting it, use ``update_agent`` with ``status="paused"``. Returns ``{"deleted": true, "agent_id", "name"}``, or ``{"error": "<message>"}``.
Input Schema
{
"type": "object",
"properties": {
"agent_id": {
"title": "Agent Id",
"type": "string"
},
"confirm_name": {
"title": "Confirm Name",
"type": "string"
}
},
"required": [
"agent_id",
"confirm_name"
],
"title": "delete_agent_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "delete_agent_toolDictOutput"
}π’list_contacts(q, limit)
List the workspace's contacts: org members (with their phone/email) plus manually saved contacts. Use ``lookup_contact`` for name searches. ``q`` optionally filters server-side (matches name/email/phone). ``limit`` caps the page (server default 100, max 500). Returns ``{"items": [{"id", "kind", "name", "phone_e164", "email", "role"}, ...]}`` β ``kind`` is ``"member"`` (id ``member:<user_id>``, ``role`` set) or ``"manual"`` (id is the contact's UUID, ``role`` null).
Input Schema
{
"type": "object",
"properties": {
"q": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Q"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Limit"
}
},
"title": "list_contacts_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_contacts_toolDictOutput"
}π’lookup_contact(query)
Find a contact by name, email, or phone fragment. Resolve a person to their ``phone_e164``/``email`` BEFORE calling ``place_call``, ``send_sms``, or ``send_email`` β do not guess a contact's number. Returns up to 10 matches, same item shape as ``list_contacts``. Example: lookup_contact(query="maya")
Input Schema
{
"type": "object",
"properties": {
"query": {
"title": "Query",
"type": "string"
}
},
"required": [
"query"
],
"title": "lookup_contact_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "lookup_contact_toolDictOutput"
}π’list_email_domains(cursor, limit)
List the addresses this workspace can send email from. Call this BEFORE ``send_email`` when you do not already know the ``from_`` address β do not guess a domain. Returns ``{"items": [...], "next_cursor": ..., "default_from": ...}``. Each item carries ``domain``, ``kind`` (``"custom"`` or ``"hail_mail"``) and ``verification_status``; only ``"verified"`` rows can send. A ``custom`` item's ``domain`` is a bare DNS name that accepts any local-part (``[email protected]``); a ``hail_mail`` item's ``domain`` is already a full address. ``default_from`` is the address a ``send_email`` with no ``from_`` goes out as. It is null when the workspace has several verified identities β then ``send_email`` rejects a missing ``from_`` and you must pass one from ``items``. Example: list_email_domains()
Input Schema
{
"type": "object",
"properties": {
"cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cursor"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Limit"
}
},
"title": "list_email_domains_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "list_email_domains_toolDictOutput"
}π’whoami
Identify the human whose credentials this session runs under. Use it to sign or route mail as that person: pass their address as ``send_email(reply_to=...)`` so replies reach them rather than the sending domain, which is often an unattended ``noreply@``. Returns ``{"auth_kind", "organization_id", "user_id", "email", "name"}``. ``user_id``/``email``/``name`` are null when the server runs on a shared operator key (``auth_kind="shared"``) β there is no human behind it, so send without a ``reply_to``. Example: whoami()
Input Schema
{
"type": "object",
"properties": {},
"title": "whoami_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "whoami_toolDictOutput"
}π‘create_contact(name, phone_e164, email)
Save a new contact for the workspace. Provide at least one of ``phone_e164`` (E.164, e.g. ``+14155551234``) or ``email`` β the API rejects (422) a contact with neither. A duplicate phone or email on an existing contact returns 409. Example: create_contact(name="Maya Chen", phone_e164="+14155551234") Returns the created contact entry as a dict. On failure returns ``{"error": "<message>"}`` instead.
Input Schema
{
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"phone_e164": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Phone E164"
},
"email": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Email"
}
},
"required": [
"name"
],
"title": "create_contact_toolArguments"
}Output Schema
{
"type": "object",
"additionalProperties": true,
"title": "create_contact_toolDictOutput"
}Community
Evidence