MCP App Store
by KeenEthics

Overview

Connect iZap to manage your WhatsApp customer conversations without leaving the chat. Check how your day is going at a glance — message volume, how much your AI assistant is handling versus your team, and how long conversations are taking. Search and read your chat history, look up contacts, and send WhatsApp messages or approved templates on the spot. Launch broadcast campaigns with a preview step before anything goes out, and track their delivery. You can also set up and fine-tune the AI assistants that reply to your customers — create a new one or update its instructions in seconds. Everything runs against your own authenticated iZap business, so you see your real numbers and your real conversations.

Tools

add_contact_filter_entries

ChatGPT
Put contacts on an assistant's allowlist or blocklist. Adding to the list only changes who the assistant answers once the matching mode is on — call `set_contact_filter_mode as well, or the list sits unused. To silence the assistant for one customer: add them to "block" and set the mode to "blocklist". To let it answer only a few people: add those to "allow" and set the mode to "allowlist". Idempotent: a contact already on the list is reported back rather than duplicated. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the assistant. list_type: "allow" or "block" — which list to add to. contacts: WhatsApp numbers in international format ("+5562000000000"; spaces, dashes and parentheses are ignored), or a WhatsApp business-scoped user ID for a contact whose number is hidden. Stored in canonical form, so the same contact typed two ways is one entry. label: Optional note stored with each contact, e.g. "founder". business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with added (the new entries), already_listed (canonical contacts that were on the list already) and invalid` (inputs that are not a usable contact, echoed as sent).

cancel_queued_sends

ChatGPT
Stop the assistant's replies that are still waiting to go out in one conversation. An assistant's reply is written down first and dispatched a moment later, often split into several messages sent a few seconds apart. This calls off every piece that has not left yet, so use it the instant someone says "stop it" or "don't send that" about a live conversation — editing the instructions cannot recall a message already queued. Only the assistant's own messages are cancelled. Anything a human sent by hand, in the inbox or from the business's phone, goes out as normal, and the business can keep replying manually in this conversation afterwards. This is a one-shot stop, not a mute: a new customer message starts a new reply. To keep the assistant quiet in this conversation from now on, add the contact to the blocklist (`add_contact_filter_entries + set_contact_filter_mode). Cancelling cannot be undone, and it cannot recall what already left. Args: ctx: MCP request context (injected automatically). chat_id: UUID of the conversation, from list_chats or search_messages. The whole conversation is covered, including the older chats it rolled over from. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with chat_id, cancelled (messages stopped before dispatch), already_sent (pieces of the same reply that had already gone to the customer and cannot be taken back) and business_id`.

confirm_transmission

ChatGPT
Confirm a DRAFT transmission to send or schedule it. Dispatches real WhatsApp messages. If the draft has no `scheduled_at (or it is in the past) sending starts immediately; otherwise it is scheduled. Idempotent: confirming an already scheduled/sending/completed transmission returns its status without re-sending. Args: ctx: MCP request context (injected automatically). transmission_id: The DRAFT transmission id returned by create_transmission_preview`. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: The transmission status with counts and progress.

connect_whatsapp_number

ChatGPT
Generate a secure link to connect a WhatsApp Business number to the business. Returns a URL, valid for one hour, that the user opens in a browser to complete Meta's official WhatsApp Business Embedded Signup. The link opens iZap's dashboard, which asks the user to log in if they are not already — as the same user this tool is acting for, since the link only works for them — before continuing into the connect flow. Share the `connect_url and ask the user to open it and follow the steps; the connection is active once they finish. Args: ctx: MCP request context (injected automatically). business_id: Optional UUID of the business to connect the number to. Defaults to the user's first business. Returns: A dict with connect_url (open in a browser within expires_in_seconds), business_id, and expires_in_seconds` (3600).

create_ai_assistant

ChatGPT
Create a new AI assistant (chatbot) for the user's business. Args: ctx: MCP request context (injected automatically). name: Assistant display name (1 to 100 characters). objective: Brief description of the assistant's role (optional). ai_model_name: OpenAI or LiteLLM model identifier (default `"gpt-4.1-nano"). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with chatbot_id, name, business_id, ai_model_name`.

create_ai_assistant

ChatGPT
Create a new AI assistant (chatbot) for the user's business. Do not use this to replace or fix an existing assistant — most plans allow only one. Call `list_connected_assistants, then update_ai_assistant_instructions (behavior, language) or update_assistant_settings (name, locale). Args: ctx: MCP request context (injected automatically). name: Assistant display name (1 to 100 characters). objective: Brief description of the assistant's role (optional). ai_model_name: Optional iZap brand tier to power the assistant — one of "iZ Lite", "iZ Pro", "iZ Max" or "iZ Core", each optionally suffixed with the provider code the other tools return (e.g. "iZ Pro · A"). Omit to use iZap's default model. The returned ai_model_name is the same brand, never the underlying provider model. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with chatbot_id, name, business_id, ai_model_name`.

create_transmission_preview

ChatGPT
Validate a CSV recipient list against a WhatsApp template and create a DRAFT transmission. No messages are sent. This validates each row's phone number and maps CSV columns to the template's variables, then persists a DRAFT you can review and send with `confirm_transmission. Upload the CSV and pass its rows as recipients. Args: ctx: MCP request context (injected automatically). name: A label for the transmission, e.g. "June promo". template_name: Name of the pre-approved WhatsApp template to send. recipients: Parsed CSV rows; each row is a map of string column header -> string cell value. Must include the phone column and the columns that fill the template's variables. Max 5000 rows. phone_column: Name of the CSV column holding the recipient phone number (default "phone"). transmission_type: Only "whatsapp_template" is supported (enforced). max_messages_per_minute: Sending pace, between 1 and 200 (default 60). template_language: Template language/locale code as registered with Meta (default "pt_BR"). variable_columns: For positional templates ({{1}}, {{2}}, ...), the ordered CSV header names mapping to {{1}}, {{2}}, ... Omit to use the first non-phone columns in order. scheduled_at: ISO-8601 datetime to send at, e.g. "2026-06-20T09:00:00". Omit to send immediately on confirm. Interpreted in timezone when it has no offset. timezone: IANA timezone for a naive scheduled_at (default "America/Sao_Paulo"). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A preview with transmission_id` (the DRAFT), recipient/valid/invalid/duplicate counts, the column mapping, sample validation errors, estimated duration, and warnings.

create_whatsapp_template

ChatGPT
Create a WhatsApp message template and submit it to Meta for approval. Templates are what let a business start a conversation outside WhatsApp's 24-hour customer-service window, so this is the tool to reach for when `send_whatsapp_template_message or a transmission needs a template that does not exist yet. Approval is Meta's, is asynchronous, and usually takes a few minutes. This tool returns as soon as the template is accepted for review with status "pending"; poll get_whatsapp_template_status with the returned template_id for the verdict. A newly created template will NOT appear in list_whatsapp_templates until Meta has it — that tool reads Meta's catalog, not local drafts. Retrying is how you fix a template: calling this again with the same name and language rewrites a template that is still a draft or was rejected, and resubmits it. A template Meta already holds (pending, approved, paused, disabled) is never rewritten — pick a different name for those. Args: ctx: MCP request context (injected automatically). name: Template name in lowercase_snake_case (e.g. "order_update"). This is Meta's natural key and must be unique per language for the business. body_text: The message body (1 to 1024 characters). Use positional placeholders {{1}}, {{2}}, ... for the parts that vary per recipient; they must start at {{1}} with no gaps. language: Template language/locale code as registered with Meta (default "pt_BR"). category: Meta's approval category — "utility" for transactional follow-ups, "marketing" for promotions, "authentication" for one-time codes. Picking the wrong one is the most common rejection reason. header_text: Optional single-line text header (up to 60 characters). footer_text: Optional small-print footer (up to 60 characters). buttons: Up to 3 buttons, each {"type": "QUICK_REPLY"|"URL"|"PHONE_NUMBER", "text": ...} plus url or phone_number for those types. example_variables: One realistic sample value per body placeholder, in order (e.g. ["Maria"] for a body with {{1}}). Meta needs these to review a template that has placeholders. Omit them and language-appropriate samples are filled in automatically. submit_for_approval: Submit to Meta straight away (default true). Pass false to keep it a local draft for a human to review — a draft cannot be used for sending. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with template_id, name, language, category, status ("draft" or "pending"), submitted, submit_error, body_variable_count and business_id. When submitted is false and submit_error` is set, the template was created but Meta refused the submission — call this tool again with the same name and the fix applied, rather than inventing a second name.

delete_library_document

ChatGPT
Permanently remove one document or video from the business's media library. This deletes the stored file as well as its library entry and cannot be undone — confirm with the user before calling it. Messages already sent that carried the file are unaffected. Get `document_id from list_library_documents. An id belonging to another business, already deleted, or naming an image rather than a document, raises "Error 404: Document not found" — images are removed with delete_library_image. Args: ctx: MCP request context (injected automatically). document_id: UUID of the library document to delete. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with document_id, deleted (True), and business_id`.

delete_library_image

ChatGPT
Permanently remove one image from the business's media library. This deletes the stored file as well as its library entry and cannot be undone — confirm with the user before calling it. Messages already sent that carried the image are unaffected. Get `image_id from list_library_images. An id belonging to another business, already deleted, or naming a document rather than an image, raises "Error 404: Image not found" — documents are removed with delete_library_document. Args: ctx: MCP request context (injected automatically). image_id: UUID of the library image to delete (from list_library_images). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with image_id, deleted (True), and business_id`.

download_media

ChatGPT
Download the actual file behind a media message so its contents can be read. `get_chat_messages reports that a message carries a document, image, audio or video and keeps the storage locator. This returns a download URL when the file is in storage. Pass inline=true to include the bytes when the file is at most 8 MB. Legacy media without a storage URL is fetched only then. Use it whenever the answer depends on what is *inside* the file — reading a PDF a customer sent, looking at a photo of a damaged product, checking a receipt. Get message_id from get_chat_messages (its message_id field). Only pass a message whose media_url is not null — a text list that *mentions* a file is not itself the attachment; the file is a neighboring document, image, audio or video message. Only messages of the caller's own business resolve; anything else raises "Error 404: Message not found". A text message with no nearby media raises "Error 400: This message is text and carries no media" and names any neighboring media message_id values to retry with. A unique neighboring media message in the same conversation (within about 30 minutes) is downloaded automatically. Args: ctx: MCP request context (injected automatically). message_id: UUID of the message whose media to download (from get_chat_messages). inline: Include file bytes when at most 8 MB (default false). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A text block of JSON metadata ({message_id, filename, mime_type, size_bytes, download_url, inline}). With inline=true, this is followed by the file itself: an image block for images, an audio block for audio, and an embedded binary resource for documents and video. download_url is an HTTPS link valid for one hour. Files larger than 8 MB are not inlined — inline is false and only download_url` can fetch them. Media older than roughly 7 days that predates re-hosting is gone from Meta and raises "Error 410".

get_assistant_instructions

ChatGPT
Get the AI instructions configured for a specific assistant. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the chatbot/assistant to retrieve instructions for. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with `chatbot_id, name, system_prompt, base_instructions (list), custom_instructions` (list).

get_assistant_instructions

ChatGPT
Get the AI instructions configured for a specific assistant. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the chatbot/assistant to retrieve instructions for. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with `chatbot_id, name, system_prompt, base_instructions (list), custom_instructions` (list).

get_assistant_ratio

ChatGPT
Get the AI-vs-human assistant message ratio for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". Defaults to today in timezone when omitted. end_date: ISO-8601 date string; inclusive end of the range. Omit for a single day. For a period, pass end_date in ONE call instead of one call per day (at most 92 days). timezone: IANA timezone name (default "UTC"). business_id: Optional UUID of the business. Returns: A dict with ai_assistant_messages, human_assistant_messages, ratio_ai_to_human` (0.0 to 1.0).

get_chat_messages

ChatGPT
Read the most recent messages of one WhatsApp conversation, newest first. Copy the exact `chat_id returned by list_chats for this business; do not invent or reuse an id from another business. A limit above 100 is read as 100. The chat is verified to belong to the business before any message is returned, so an unknown or other-business chat_id raises "Error 404: Chat not found". Returns the whole conversation, including what the customer said on earlier days — the thread is not cut off at the point their last session ended. Args: ctx: MCP request context (injected automatically). chat_id: UUID of the conversation to read (from list_chats). limit: Maximum number of messages to return (1 to 100, default 50). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with chat_id, messages (newest first: {message_id, sender, sender_type, content, transcription, message_type, media_url, timestamp, status, message_sid, receiver, error_code, error_reason, updated_at, business_number}), total, and business_id. business_number is the business's own number the message's conversation ran on, so a thread that moved between lines shows it. When total equals limit the history is truncated — raise limit (max 100); messages older than that are not reachable yet. sender_type is "agent"/"bot" for outbound messages and null for inbound consumer messages. On failed outbound rows status is failed (distinct from a successful customer reply), error_code/error_reason carry the Meta failure, message_sid is the wamid, receiver is the destination, and updated_at is when the failure status landed. For audio messages content is an [Audio url=...] token and transcription holds the transcript when one exists (null otherwise). A text that mentions an attachment is not the attachment — pick a neighboring message whose media_url is not null and pass that message_id to download_media. Rehosted media_url values remain storage keys on this read; call download_media with one message_id` to open that file.

get_contact_filter

ChatGPT
Read which contacts an assistant is allowed to answer: its mode and both lists. The contact filter is the control that decides who the assistant replies to. It is the right thing to read before changing anything when the user wants the assistant to stop answering someone — writing "do not reply to X" into the instructions is not a reliable substitute, because the model still sees and can answer the message. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the assistant whose filter to read. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with `mode ("off", "allowlist" or "blocklist"), allowlist and blocklist. Each list entry carries id, phone_number (canonical form), label and created`. Both lists are kept whichever mode is active, so switching modes never discards the other one.

get_conversation_breakdown

ChatGPT
Break a day's conversations down by who handled them and which await a reply. Answers "how many conversations were handled exclusively by the AI, how many had a human step in, and how many are waiting on a reply?" for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". Defaults to today in timezone when omitted. end_date: ISO-8601 date string; inclusive end of the range. Omit for a single day. For a period, pass end_date in ONE call instead of one call per day (at most 92 days). timezone: IANA timezone name (default "UTC"). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with total_conversations and its partition into ai_only, human_assisted, and unanswered, plus awaiting_response` (an orthogonal count of conversations whose latest message is from the customer).

get_conversation_duration

ChatGPT
Get conversation duration statistics (avg, min, max) for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". timezone: IANA timezone name (default "UTC"). business_id: Optional UUID of the business. Returns: A dict with avg_duration_seconds, min_duration_seconds, max_duration_seconds, sessions_counted`.

get_conversation_duration

ChatGPT
Get conversation duration statistics (avg, min, max) for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". Defaults to today in timezone when omitted. end_date: ISO-8601 date string; inclusive end of the range. Omit for a single day. For a period, pass end_date in ONE call instead of one call per day (at most 92 days). timezone: IANA timezone name (default "UTC"). business_id: Optional UUID of the business. Returns: A dict with avg_duration_seconds, min_duration_seconds, max_duration_seconds, sessions_counted`.

get_message_stats

ChatGPT
Get chat, message, and unique-people counts for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". Defaults to today in timezone when omitted. end_date: ISO-8601 date string; inclusive end of the range. Omit for a single day. For a period, pass end_date in ONE call instead of one call per day (at most 92 days). timezone: IANA timezone name (default "UTC"), e.g. "America/Sao_Paulo". business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with date, timezone, chats_count, messages_count, people_count. With end_date the counts cover the whole range (distinct over the range, not the sum of days) and days lists {date, chats_count, messages_count, people_count}` per local day.

get_plan_usage

ChatGPT
Show the business's plan, add-ons, limits, how much of each is used and when each resets. Reads only; changes nothing and spends no budget. Call it when the user asks about their plan, their allowance or when it resets, when a tool was refused for a plan limit or a daily budget, and before a large batch of sends to check there is room for it. Limits run on two clocks. `monthly holds the plan allowances — ai_contacts_per_month (contacts served) and template_sends_per_month — counted from period_start until resets_at, a monthly window anchored on the billing anniversary rather than the 1st. daily holds the per-day budgets on these tools (messages, broadcasts, reads, ...), which reset together at resets_at (midnight UTC). Every timestamp is UTC: convert it to the user's timezone before quoting it. Each limit says whether it is enforced and whether it is blocking_now — the next new contact, send or call would be refused. A limit with enforced: false is only measured: going over it blocks nothing. Read ai_contacts_definition out to the user when they ask what counts as a contact served. Args: ctx: MCP request context (injected automatically). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with plan (plan_code, tier, status, current_period_end, cancel_at_period_end); trial (ends_at and has_payment_method) while a free trial runs, otherwise null; addons (addon_code, quantity, status, and the amount of unit it adds); monthly (period_start, resets_at and limits); capacity (assistants, WhatsApp numbers and team members against their caps); daily (resets_at and budgets, each with budget, unit, used, limit, enforced, blocking_now); credits (purchased usage_credits and message_credits, spent once a daily budget is used up instead of refusing the call); and ai_contacts_definition. Each limit carries key, used, limit (null when the plan sets none), enforced and blocking_now; ai_contacts_per_month adds overage_policy (pause stops the AI for new contacts, billed charges overage_unit_price in currency` per extra contact).

get_today_assistant_ratio

ChatGPT
Get the AI-vs-human assistant message ratio for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". timezone: IANA timezone name (default "UTC"). business_id: Optional UUID of the business. Returns: A dict with ai_assistant_messages, human_assistant_messages, ratio_ai_to_human` (0.0 to 1.0).

get_today_message_stats

ChatGPT
Get chat, message, and unique-people counts for a specific date. Args: ctx: MCP request context (injected automatically). date: ISO-8601 date string, e.g. `"2026-04-15". timezone: IANA timezone name (default "UTC"), e.g. "America/Sao_Paulo". business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with date, timezone, chats_count, messages_count, people_count`.

get_transmission_status

ChatGPT
Get the status and delivery progress of a single transmission. Args: ctx: MCP request context (injected automatically). transmission_id: The transmission id. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: The transmission status with sent/failed/pending counts and progress percentage.

get_whatsapp_connection_status

ChatGPT
Diagnose the business's WhatsApp Business connection. Reads only; changes nothing. Diagnosis is cached per business for up to 30 seconds; `checked_at identifies when its evidence was read. Call this first whenever sending or receiving looks broken, or before a send when the connection is in doubt. Unlike the send tools, this never errors on a missing connection — it reports connected: false and the step that fixes it. Meta's own status stays "CONNECTED" through a webhook blackout and through a WABA migration, so each signal here is backed by evidence we hold rather than by that badge: whether live inbound is actually arriving, whether an outbound has actually reached Meta, and whether the Coexistence history backfill is landing. Args: ctx: MCP request context (injected automatically). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with connected, a one-line summary and the single next_step that unblocks the user; number (phone_number, phone_number_id, waba_id, verified_name, quality_rating); registration (ready/incomplete/disconnected plus Meta's raw meta_status); webhooks (ok/silent/never/not_subscribed, whether Meta confirms the subscription, and last_live_inbound_at); history_sync (received/never and last_received_at); sending (ok/failing/never); and last_error — the most recent message Meta refused, explained in plain language. A business can hold several numbers: the fields above describe the main one, and numbers lists every number with its own connected, summary, next_step, number, registration, webhooks, sending and last_error — report each of them to the user. Every detail` field is written to be read out to the user as-is.

get_whatsapp_message_status

ChatGPT
Check the delivery status of a WhatsApp message sent earlier. `status: "sent" from a send tool only means Meta accepted the request — it does NOT mean the message was delivered. Meta reports the real outcome asynchronously; call this tool with the message_id returned by send_whatsapp_message or send_whatsapp_template_message to confirm delivery or diagnose a failure. Args: ctx: MCP request context (injected automatically). message_id: The message_id (wamid) returned by a send tool. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with status ("accepted", "sent", "delivered", "read", "failed", "cancelled", or "unknown"), is_final, error_code/error_message/ reason when the send failed (e.g. code 131047 means the 24h window is closed and an approved template is required), and a hint` when polling again or switching to a template is advisable.

get_whatsapp_template_status

ChatGPT
Check where a template created here stands in Meta's approval review. Call this after `create_whatsapp_template to find out whether the template is usable yet, and — when Meta refused it — why. A submission Meta rejected outright never reaches Meta's catalog, so list_whatsapp_templates cannot show it; this tool can. Args: ctx: MCP request context (injected automatically). template_id: The template_id returned by create_whatsapp_template. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with template_id, name, language, category, status (draft | pending | approved | rejected | paused | disabled), is_final, rejection_reason, provider_template_id, body_text, body_variable_count, last_synced_at, hint (what to do next) and business_id`. Only an "approved" template can be sent.

list_chats

ChatGPT
List the business's WhatsApp conversations, most-recently-active first. Shows real customer conversations only (AI-trainer chats and deleted chats are excluded). Use it to find a conversation, then pass its `chat_id to get_chat_messages to read the thread, or reply with send_whatsapp_message to the consumer's phone number. One row per conversation, not per session: a customer who has written in over several days appears once, and last_message_at covers the whole thread. Message counts are computed only when include_message_count is true. **This is where you start when asked about one specific person.** Pass phone or name_contains to go straight to their conversations instead of raising limit or paging through the inbox. Do not try to locate someone with search_messages alone: that searches what was *said*, so it finds a person only when their name or number appears in the text of a message. Args: ctx: MCP request context (injected automatically). limit: Maximum number of chats to return (1 to 100, default 30). phone: Return only conversations with this number. Any format works — spaces, dashes, with or without + or the country code, and Brazil's optional 9th digit are all matched against the stored value. Separate up to 20 numbers with commas to get the conversations of any of them in one call. name_contains: Return only conversations whose consumer name contains this text (case-insensitive, matched literally). business_number: Return only conversations held on this one of the business's own WhatsApp numbers, in any format. For businesses that run several lines. include_message_count: Compute message counts for the returned page (default false). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with chats (list of {chat_id, consumer_id, consumer_name, consumer_phone, last_message_at, message_count, business_number}), total (chats in this response, capped by limit), has_more (another matching conversation exists), and business_id. message_count is null unless requested; total_count is null on this MCP path. If has_more is true, narrow with phone or name_contains to find the person instead of raising limit or paging. consumer_id is the person's stable id, the same across all their chats. business_number` is the business's own number the conversation runs on (null for older chats recorded before lines were tracked).

list_connected_assistants

ChatGPT
List all AI assistants (chatbots) connected to the authenticated user's iZap account. Args: ctx: MCP request context (injected automatically). business_id: Optional UUID of the business to query. If omitted, the user's first business is used automatically. Returns: A dict with `assistants (list of assistant objects) and total` (int).

list_connected_assistants

ChatGPT
List all AI assistants (chatbots) connected to the authenticated user's iZap account. Args: ctx: MCP request context (injected automatically). business_id: Optional UUID of the business to query. If omitted, the user's first business is used automatically. Returns: A dict with `assistants (list of assistant objects) and total` (int).

list_contacts

ChatGPT
List contacts (people who have chatted with the business) with names and phone numbers. Args: ctx: MCP request context (injected automatically). limit: Maximum number of contacts to return (1 to 200, default 50). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with `contacts (list of {name, phone_number}), total, business_id`.

list_contacts

ChatGPT
List contacts (people who have chatted with the business) with names and phone numbers. Ordered by who wrote most recently. To find one specific person, pass `phone or name_contains. To read the whole list, page with offset one call after another (offset += limit while has_next is true) — the order is stable, so pages never overlap. Do not fan out many parallel calls with different filters to cover it. Args: ctx: MCP request context (injected automatically). limit: Maximum number of contacts to return (1 to 200, default 50). offset: How many contacts to skip, for paging past the first page (default 0). phone: Return only the contact with this number. Any format works — spaces, dashes, with or without + or the country code, and Brazil's optional 9th digit are all matched against the stored value. Separate up to 20 numbers with commas to get the contacts of any of them in one call. name_contains: Return only contacts whose name contains this text (case-insensitive, matched literally). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with contacts (list of {name, phone_number, consumer_id}), total (number of contacts in this response, capped by limit), total_count (contacts matching the filters, ignoring limit/offset), limit, offset, has_next (whether another page follows), and business_id. When has_next is true the list is truncated — fetch the next page with offset, narrow with phone/name_contains, or report total_count as the real total. consumer_id` is the person's stable id, for reporting a specific customer unambiguously.

list_library_documents

ChatGPT
List the documents and videos in the business's media library, newest first. The companion to `list_library_images for everything that is not an image: price lists, invoices, catalogues, promo videos. Call it to find a file's document_id for send_whatsapp_template_message's header_media_document_id or for delete_library_document. Args: ctx: MCP request context (injected automatically). limit: Maximum number of documents to return (1 to 100, default 50). offset: How many to skip, for paging past the first page (default 0). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with documents (list of {document_id, filename, content_type, header_kind, size_bytes, url, title, description, tags, created}), total, total_count, limit, offset, has_next, and business_id. header_kind is "document" for a PDF or DOCX and "video" for an MP4 — it says which template header format the file fits, since a template's header format is fixed when Meta approves it. Each url` is a signed HTTPS link valid for one hour.

list_library_images

ChatGPT
List the images in the business's own media library, newest first. The library holds curated business assets — logos, product photos, menus — that the team uploaded through the dashboard, not media customers sent in a chat (that is `download_media). Call this to see what artwork already exists before uploading a duplicate, and to get an image's image_id — which delete_library_image takes, and which send_whatsapp_template_message accepts as header_media_image_id to put the image in a template's header. Args: ctx: MCP request context (injected automatically). limit: Maximum number of images to return (1 to 100, default 50). offset: How many images to skip, for paging past the first page (default 0). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with images (list of {image_id, filename, content_type, usable_as_template_header, size_bytes, url, title, description, tags, created}), total (images in this response), total_count (images in the whole library), limit, offset, has_next, and business_id. Each url is a signed HTTPS link valid for one hour — call this tool again for a fresh one rather than storing it. usable_as_template_header` is false for a GIF or WebP, which the library stores but WhatsApp will not accept as a template header image.

list_paused_conversations

ChatGPT
List the conversations where the assistant is paused, and since when. Covers every pause that lasts until someone resumes it: those set with `pause_conversation_ai and those set from the inbox. The short automatic pause that follows a human's manual reply is not listed — it ends on its own after the assistant's configured ai_pause_minutes. Args: ctx: MCP request context (injected automatically). limit: Maximum number of conversations to return (1 to 200, default 50). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with conversations (list of {consumer_id, consumer_name, consumer_phone, paused_since, origin, paused_by_user_id}, longest-paused first), total (conversations in this response, capped by limit), total_count (all paused conversations, ignoring limit) and business_id. origin says where the pause came from: "mcp" (this tool set), "operator" (the inbox) or another source. Pass a consumer_id to resume_conversation_ai` to end that pause.

list_transmissions

ChatGPT
List the business's transmissions (newest first), optionally filtered by status. Args: ctx: MCP request context (injected automatically). limit: Maximum number to return (1-200, default 50). status: Optional filter: `draft, scheduled, sending, completed, failed or cancelled. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with transmissions (each with status and progress counts) and total`.

list_whatsapp_templates

ChatGPT
List the business's Meta-approved WhatsApp message templates. Call this before `send_whatsapp_template_message to discover which templates exist, their exact name and language (locale), and which body variables each needs — instead of guessing. Sending a template name/locale/variable-count that Meta does not recognise is rejected with "(#100) Invalid parameter". Reads the locally synced template catalog. Stale rows refresh in the background, at most about every five minutes per business; this tool does not wait for Meta. This is **not** a connection check. It needs a connected WhatsApp number and errors without one, so to find out whether the connection is live — for instance while the user is finishing Embedded Signup — call get_whatsapp_connection_status, which reports connected: false instead of erroring. Re-calling this tool against an unconnected account only repeats the same error. Args: ctx: MCP request context (injected automatically). limit: Maximum number of templates to return (1 to 200, default 50). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with templates (list of {name, language, status, category, body_variable_count, uses_named_variables, body_variable_names, body_text}), total, and business_id. body_variable_names are the placeholder keys a send must fill, in order: pass them as named_variables when uses_named_variables is true, and as positional body_variables otherwise. Only templates whose status` is "APPROVED" can be sent successfully.

remove_contact_filter_entries

ChatGPT
Take contacts off an assistant's allowlist or blocklist. The mirror of `add_contact_filter_entries, and how a containment is lifted for one contact: removing them from the blocklist lets the assistant answer them again, and removing them from the allowlist stops it. The mode itself is untouched — use set_contact_filter_mode with "off" to lift the containment for everyone. Idempotent: a contact that was not on the list is reported, not an error. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the assistant. list_type: "allow" or "block" — which list to remove from. contacts: WhatsApp numbers in international format ("+5562000000000"; spaces, dashes and parentheses are ignored), or a WhatsApp business-scoped user ID for a contact whose number is hidden. Stored in canonical form, so the same contact typed two ways is one entry. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with removed and not_listed (both in canonical form) and invalid` (inputs that are not a usable contact, echoed as sent).

report_missing_capability

ChatGPT
Tell the iZap product team about an iZap task that none of these tools can do. Use it when the user asks for something on their iZap account (WhatsApp messages, chats, contacts, templates, transmissions or AI assistants) that no tool here supports. It only stores the request for the iZap team: it changes nothing on the business and gives access to no other tools. Do not include customer names, phone numbers or message text. Args: ctx: MCP request context (injected automatically). capability: One sentence naming the iZap task that could not be done. details: Optional context: what was tried and any workaround used. task_completed: Optional, whether the task was still completed another way. Returns: A dict with `recorded (bool) and message` (str).

resume_conversation_ai

ChatGPT
Hand a paused conversation back to the assistant. Ends the pause set by `pause_conversation_ai (or by the inbox's pause button), and also the short automatic pause that starts when a human replies by hand. From the contact's next message on, the assistant answers again. Messages that arrived during the pause are not answered retroactively; the assistant sees them as history. Resuming a conversation that was not paused changes nothing. Other conversations are not affected. Pass exactly one of chat_id or consumer_id. Args: ctx: MCP request context (injected automatically). chat_id: UUID of a conversation, from list_chats or list_paused_conversations. consumer_id: UUID of the contact, from list_paused_conversations or list_contacts. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with consumer_id, consumer_name, consumer_phone, paused (false), paused_since (null), already_in_state (true when it was not paused), incoming_messages (what happens to the contact's messages now) and business_id`.

search_messages

ChatGPT
Search messages over a date or date range using a keyword query. Rate-limited per business by plan tier (higher tiers get more headroom); an over-limit call returns an error naming the current limit. Applies ILIKE substring matching over message bodies and audio transcripts; a transcript-only hit returns the transcript as its `snippet. The consumer's name and phone number are matched too, so a nickname or a number finds that person's messages in the range. Searches one day unless end_date is given. To find a person's conversation without knowing when they wrote, prefer list_chats with phone or name_contains — it spans their whole history rather than a date window. Args: ctx: MCP request context (injected automatically). query: Search term (up to 200 characters). Matched against message text, audio transcripts, and the consumer's name and phone number. Empty or omitted returns all of the range's messages (newest first, capped by limit); the name/phone match applies only to a non-empty query. date: ISO-8601 date string; start of the range. Defaults to today in timezone when omitted. end_date: ISO-8601 date string; inclusive end of the range. Omit to search date alone. A range given in reverse order is put in order. timezone: IANA timezone name (default "UTC"). limit: Maximum number of results to return (1 to 100, default 20). business_id: Optional UUID of the business. Returns: A dict with results (list of {chat_id, message_id, sender, snippet, timestamp, consumer_id, consumer_nickname, message_type, has_media}), total (int), query, date, and end_date (null for a single-day search). Pass a hit's chat_id to get_chat_messages to read the surrounding thread. Only a hit with has_media true can go straight to download_media; never call it on a hit whose has_media is false. An attachment that accompanies a matching list is usually a neighboring document or image — read the thread with get_chat_messages and pick a message with a non-null media_url`.

search_today_messages

ChatGPT
Search through messages on a specific date using a keyword query. Rate-limited to 60 calls per user per day. Applies ILIKE substring matching. Args: ctx: MCP request context (injected automatically). query: Search term (1 to 200 characters). date: ISO-8601 date string. timezone: IANA timezone name (default `"UTC"). limit: Maximum number of results to return (1 to 100, default 20). business_id: Optional UUID of the business. Returns: A dict with results (list), total (int), query, date`.

send_whatsapp_message

ChatGPT
Send an outbound WhatsApp text message via the business's connected Cloud API number. This dispatches a real message through Meta's WhatsApp Business Cloud API and cannot be undone. Rate-limited to 50 messages per user per day. Args: ctx: MCP request context (injected automatically). to: Recipient phone number in international format, e.g. `"+5562000000000". body: Message text (1 to 4096 characters). preview_url: Whether to render link previews for URLs in the body (default False). business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with to, message_id (None on failure), status ("sent" or "failed"), business_id, and error` (None unless the send failed).

send_whatsapp_message

ChatGPT
Send an outbound WhatsApp text message via the business's connected Cloud API number. This dispatches a real message through Meta's WhatsApp Business Cloud API and cannot be undone. Rate-limited per business by plan tier (higher tiers get more headroom); an over-limit call returns an error naming the current limit. Args: ctx: MCP request context (injected automatically). to: Recipient phone number in international format, e.g. `"+5562000000000". body: Message text (1 to 4096 characters). preview_url: Whether to render link previews for URLs in the body (default False). from_number: Which of the business's own WhatsApp numbers to send from, in any format. Omit it to reply from the number this contact last talked to. The numbers are listed by get_whatsapp_connection_status. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with to, message_id (None on failure), status ("sent" or "failed"), business_id, from_number (the business number used), and error (None unless the send failed). status: "sent" means Meta accepted the request, not that it was delivered — call get_whatsapp_message_status with the returned message_id to confirm delivery. Free-form texts to contacts outside the 24-hour service window are accepted and then silently dropped by Meta; use send_whatsapp_template_message` for those.

send_whatsapp_template_message

ChatGPT
Send an outbound WhatsApp template message via the business's connected Cloud API number. Template messages use a pre-approved template (registered in Meta's WhatsApp Manager) and are the only way to start or re-open a conversation outside the 24-hour customer-service window. This dispatches a real message and cannot be undone. Rate-limited per business by plan tier (higher tiers get more headroom); an over-limit call returns an error naming the current limit. A template approved with a media header (document, image or video) carries a file alongside its text. Name that file exactly one of four ways, whichever fits: - `header_media_image_id — an image already in the business's media library, from upload_library_image or list_library_images. Pass the image_id UUID or the filename (e.g. logo.png). Preferred for anything reused: iZap reads it straight from storage, so nothing expires and no URL is needed. - header_media_document_id — the same, for a document or video from upload_library_document or list_library_documents. Its header_kind says whether it fits a document header or a video header. - header_media_url — a publicly reachable https:// link iZap fetches. - header_media_base64 — the bytes themselves, for a one-off file that is neither in the library nor hosted anywhere. It is NOT saved to the library; call upload_library_image first if it should be reusable. The file can differ on every send — only the header format is fixed by the approved template. Call list_whatsapp_templates first to see which templates have one. WhatsApp accepts only JPEG and PNG as a header image, so a GIF or WebP in the library cannot be used: list_library_images reports usable_as_template_header per image. Args: ctx: MCP request context (injected automatically). to: Recipient phone number in international format, e.g. "+5562000000000". template_name: Name of the approved template, e.g. "order_confirmation". language_code: Template language/locale code as registered with Meta (default "pt_BR"). body_variables: Ordered values for positional template body placeholders ({{1}}, {{2}}, ...). Omit or pass an empty list for templates without variables. named_variables: A map of string keys to string values for named template body placeholders ({{customer_name}}, ...), keyed by parameter name (lowercase letters, digits, underscores). Use for templates registered with named parameters; mutually exclusive with body_variables. header_media_url: Publicly reachable https:// URL of the file for a media-header template, e.g. a PDF for a document header. Documents accept PDF, plain text, Word, Excel and PowerPoint up to 100 MB. header_media_image_id: UUID or filename of a library image to use as the header, from list_library_images or upload_library_image. A filename such as logo.png is resolved in the library; prefer the image_id UUID when several files share a name. Must be a JPEG or PNG. Do not pass a URL here — use header_media_url. header_media_document_id: UUID or filename of a library document or video to use as the header, from list_library_documents or upload_library_document. A filename such as precos.pdf is resolved in the library; prefer the document_id UUID when several files share a name. Do not pass a URL here — use header_media_url. header_media_base64: The header file's bytes, base64-encoded, for a one-shot send. No data: prefix. JPEG, PNG, PDF, MP4 and 3GPP are recognised from their content; for a text or Office document use header_media_url. header_media_filename: Display name the recipient sees for a document header before opening it, e.g. "Fatura-Setembro.pdf". Defaults to the file name in header_media_url` or the library image's own name; ignored for image and video headers. from_number: Which of the business's own WhatsApp numbers to send from, in any format. Omit it to send from the number this contact last talked to. The template must be approved on that number's WhatsApp Business Account. business_id:…

set_contact_filter_mode

ChatGPT
Choose how strictly an assistant is contained: off, allowlist or blocklist. This is the containment switch. Use it — not `update_ai_assistant_instructions — when the user wants the assistant to stay quiet for some or all contacts. The filter runs *before* the model is called, so a filtered conversation costs nothing and cannot be answered by accident; an instruction telling the model to keep quiet can be argued with, this cannot. - "off": every contact can trigger the assistant. - "allowlist": only contacts on the allowlist can — the way to take the assistant off the air for everyone except a few testers (an empty allowlist silences it completely). - "blocklist": every contact can except those on the blocklist — the way to silence the assistant for one person while it keeps working for everyone else. The assistant stays connected and the number keeps receiving messages either way, and the business can still reply by hand in any conversation the filter holds back. To take the assistant off the air entirely, including for the lists, use update_assistant_settings with is_active=false instead. Switching modes never discards the list the new mode does not use, so a blocklist survives a trip through allowlist and back. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the assistant to contain. mode: "off", "allowlist" or "blocklist". business_id: Optional UUID of the business. Defaults to the user's first business. Returns: The assistant's whole filter after the change: mode, allowlist, blocklist`.

update_ai_assistant_instructions

ChatGPT
Update the AI instructions for an existing assistant. At least one of `system_prompt, base_instructions, or custom_instructions must be provided. Omitted fields are left unchanged. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the chatbot to update. system_prompt: New system prompt text (replaces existing). base_instructions: List of instruction dicts for the base behavior layer. custom_instructions: List of instruction dicts for business-specific context. business_id: Optional UUID of the business. Returns: A dict with chatbot_id and updated_fields` (list of field names that changed).

update_ai_assistant_instructions

ChatGPT
Update the AI instructions for an existing assistant. At least one of `system_prompt, base_instructions, or custom_instructions must be provided. Omitted fields are left unchanged. base_instructions and custom_instructions merge by instruction id rather than replacing the whole list: - Pass an item with an existing id to patch that instruction in place — only the fields you set are overlaid, so untouched instructions and metadata survive. Send a field explicitly (e.g. title=None) to clear it. - Pass an item without an id to append a new instruction (a UUID is generated for it). - If *no* item in the list carries an id, the whole layer is replaced with what you send. Passing an empty list clears the layer. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the chatbot to update. system_prompt: New system prompt text (replaces existing). base_instructions: Instructions for the base behavior layer; merged by id as described above. custom_instructions: Instructions for business-specific context; merged by id as described above. business_id: Optional UUID of the business. Returns: A dict with chatbot_id and updated_fields` (list of field names that changed).

update_assistant_settings

ChatGPT
Change an existing assistant's settings, but not its instructions. Covers everything the assistant's settings page holds; the instructions themselves belong to `update_ai_assistant_instructions. At least one setting must be provided. Every setting you omit is left unchanged, so a call only ever moves what it names. To *clear* a setting, send the empty string (objective, locale, off_hours_message) or ai_pause_minutes=0. Args: ctx: MCP request context (injected automatically). chatbot_id: UUID of the assistant to update. name: Assistant display name (1 to 100 characters). is_active: Whether the assistant answers incoming messages. false takes it off the air without deleting it or releasing its WhatsApp number. objective: Brief description of the assistant's role. Empty string clears it. ai_model_name: iZap brand tier powering the assistant — one of "iZ Lite", "iZ Pro", "iZ Max" or "iZ Core", each optionally suffixed with the provider code the other tools return (e.g. "iZ Pro · A"). timezone: IANA timezone name, e.g. "America/Sao_Paulo". Business hours and the time-based greetings are evaluated in it. locale: Language the assistant writes in, e.g. "pt-BR" or "en-GB". Empty string clears it, falling back to the number's inferred language. communication_style: One of "friendly", "fun", "direct", "warm", "professional". detect_client_language: When true, the assistant answers in the language the customer wrote in rather than in locale. use_emojis: Whether the assistant may use emojis. greetings: Opening messages. Either {"mode": "sequence", "messages": [...]} (up to 10, all sent in order) or {"mode": "time_based", "morning": ..., "afternoon": ..., "night": ...} (only the entry matching the time of day is sent). off_hours_message: Reply sent outside business hours. Empty string clears it. ai_pause_minutes: How long the AI stays paused after a human takes a conversation over, 1 to 1440. Send 0 to fall back to the system default. hold_ai_after_manual_reply: When true, a reply sent from the WhatsApp Business app keeps the AI off for that contact until someone resumes it. Send false to go back to the timed pause. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: The assistant's full settings after the write, plus updated_fields` (the list of settings this call changed).

upload_library_document

ChatGPT
Add a document or video to the business's media library so it can be reused. Use this for a file that will be sent more than once — a price list attached to a template header every month, say. For a genuinely one-off file, pass `header_media_base64 to send_whatsapp_template_message instead and skip storing it at all. PDF, DOCX and MP4 are accepted, and the type is read from the bytes rather than the name: a .pdf name over something that is not a PDF is rejected. Plain text and the legacy Office formats carry no signature to identify them by, so they cannot be stored here — attach those with header_media_url. Args: ctx: MCP request context (injected automatically). filename: File name including its extension, e.g. "tabela-precos.pdf". content_base64: The file's bytes, base64-encoded. A data: URI prefix is stripped if present. title: Optional short label shown in the dashboard. description: Optional longer note about what the file is for. tags: Optional list of keywords (up to 20). Blank entries are dropped. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with document ({document_id, filename, content_type, header_kind, size_bytes, url, title, description, tags, created}) and business_id. Pass the returned document_id to send_whatsapp_template_message as header_media_document_id`. A rejected upload raises "Error 400" naming what failed — the size limit, the extension, or the content check.

upload_library_image

ChatGPT
Add an image to the business's media library so it can be reused later. Send the file's raw bytes base64-encoded — there is no multipart upload over MCP. Only JPEG, PNG, GIF and WebP are accepted, and the bytes are sniffed rather than trusted: a `.png name over a payload that is not a PNG is rejected, as is anything above the server's upload size limit. Do not invent placeholder bytes, and do not send SVG, a URL, or a file path — those decode but fail the content check. Rasterize SVG to PNG first. A PDF, DOCX or MP4 belongs on upload_library_document. title, description and tags are how the image is found again — the dashboard shows the title, and list_library_images returns all three. Args: ctx: MCP request context (injected automatically). filename: File name including an image extension, e.g. "logo.png". It is sanitized before storage and only its extension has to match the content. content_base64: The file's bytes, base64-encoded. A data: URI prefix is stripped if present. title: Optional short label shown in the dashboard's media library. description: Optional longer note about what the image is for. tags: Optional list of keywords (up to 20). Blank entries are dropped. business_id: Optional UUID of the business. Defaults to the user's first business. Returns: A dict with image ({image_id, filename, content_type, usable_as_template_header, size_bytes, url, title, description, tags, created}) and business_id. Pass the returned image_id to send_whatsapp_template_message as header_media_image_id` to use it in a template header. A rejected upload raises "Error 400" naming what the bytes actually were (SVG, a URL, a PDF, placeholder text) so the next call can send a real JPEG, PNG, GIF or WebP.

confirm_transmission

Claude

connect_whatsapp_number

Claude

create_ai_assistant

Claude

create_transmission_preview

Claude

get_assistant_instructions

Claude

get_chat_messages

Claude

get_conversation_breakdown

Claude

get_conversation_duration

Claude

get_more_tools

Claude

get_today_assistant_ratio

Claude

get_today_message_stats

Claude

get_transmission_status

Claude

list_chats

Claude

list_connected_assistants

Claude

list_contacts

Claude

list_transmissions

Claude

list_whatsapp_templates

Claude

search_today_messages

Claude

send_whatsapp_message

Claude

send_whatsapp_template_message

Claude

update_ai_assistant_instructions

Claude

Capabilities

Writes

App Stats

72

Tools

ChatGPT, Claude

Platforms

Works with

ChatGPT
Claude

Data refreshed daily