Turbo Notify: WhatsApp for AI agents

com.turbonotify/turbo-notify · v0.2.1 · communication

Turbo Notify: WhatsApp for AI agents is healthy: it completed an MCP handshake in 1268 ms and exposes 36 tools.

Send and receive WhatsApp messages from your AI agent, on your own number.

Endpoint: https://mcp.turbonotify.com (streamable-http)

Repository · Website · JSON · Add to my inventory

Facts

Users (last 30 days)0
HandshakeHealthy
Auth neededNone
Tool count36
Latency1268 ms
Last checked (UTC)2026-11-06T15:20:48.693Z

Health history

Checked (UTC)StatusLatencyError
2026-11-06T15:20:48.693ZHealthy1268

Tools (36)

send_textSend a WhatsApp text message. Set exactly one recipient: `number`, `group_id`, or `contact_id`. Writing `@<number>` in the text mentions that person, for example `@5511999999999`. The platform detects it automatically; there is no separate mentions argument. This is also how to answer the message
send_mediaSend media by URL: an image, video, audio clip, document or sticker. Set exactly one recipient: `number`, `group_id`, or `contact_id`. `url` must still be reachable when the send happens: Turbo Notify fetches the bytes from it. A copy is kept in the organization's own object storage afterwards whe
send_locationSend a location pin. Set exactly one recipient: `number`, `group_id`, or `contact_id`. `latitude` is between -90 and 90, `longitude` between -180 and 180. `name` and `address` label the pin; `url` adds a link beside it. A location cannot be edited after it is sent: `delete_message` is the only ch
send_contact_cardSend a contact card the recipient can save to their phone. Set exactly one recipient: `number`, `group_id`, or `contact_id`. `phones` takes plain E.164 numbers, 1 to 10 of them. `emails`, `organization`, `title` and `address` are optional extra fields on the card; `emails` allows up to 10 as well.
send_calendar_eventSend a calendar event invitation. Set exactly one recipient: `number`, `group_id`, or `contact_id`. `start_at` and `end_at` are ISO 8601 **with an offset**, for example `2026-09-10T14:00:00Z`. A timestamp without one is rejected: the recipient's phone renders the event in their own timezone, so an
send_cta_buttonSend an interactive message carrying one link button. Set exactly one recipient: `number`, `group_id`, or `contact_id`. A link button is the only interactive type WhatsApp accepts on this kind of connection. Reply buttons and list pickers are not available and will not become available, so do not
reply_to_messageReply to an EARLIER message, quoting it, without naming a recipient. Use it to bring context into the conversation: when the conversation has moved on and your answer depends on something said a while ago (by the contact, by you or, in a group, by any participant). To answer the message you just re
edit_text_messageReplace the text of a text message this number already sent. The recipient sees the new text marked as edited. The message keeps its id and its place in the conversation; only the text changes. Only a text message can be edited here. For the caption of an image, video or document use `edit_media_c
edit_media_captionReplace the caption of an image, video or document this number already sent. The recipient sees the new caption marked as edited. The file itself stays exactly as it was and the message keeps its id: only the caption changes. There is no way to replace the file; to send a different one, send a new
edit_calendar_eventCorrect a calendar event this number already sent. `name` and `start_at` are always required, plus whatever else the event has: `description`, `end_at`, `join_link`, `location`, `has_reminder` with `reminder_offset_sec`, and `extra_guests_allowed`. This REPLACES the whole event: anything you leave
cancel_calendar_eventCancel a calendar event this number already sent. The event stays in the chat marked as canceled, and WhatsApp tells the guests. Send the same `name` and `start_at` the event has, plus the details you want the canceled card to still show (`description`, `end_at`, `join_link`, `location`, `has_remin
delete_messageRevoke a message for everyone in the conversation. This is WhatsApp's "delete for everyone". It is not reversible, and recipients see a tombstone where the message was, so they can tell something was deleted. Confirm with a human before using it on anything a person has plausibly already read. The
react_to_messageAttach an emoji reaction to a message, or remove one. Pass a single emoji character, e.g. `👍`. Passing an empty string removes the reaction this number previously left. A new emoji replaces this number's previous reaction rather than adding beside it; to bring the earlier one back, react with it a
send_typing_indicatorShow "typing…" to a recipient while you prepare an answer. Set exactly one recipient: `number`, `group_id`, or `contact_id`. Useful before a reply that takes a few seconds to compose, so the person on the other end sees something is happening. It expires on its own, so clearing it is optional: pas
mark_as_readMark a conversation's unread messages as read, without sending anything. Set exactly one recipient: `number`, `group_id`, or `contact_id`. This is independent of the automatic mark-as-read that already happens when you send, reply, react, edit, delete or start typing (the number also appears onlin
list_messagesList messages for one number, newest first, received and sent. Each item says who it is from and to, which number it belongs to, its `direction`, `content_type`, `origin`, a short `preview`, `at`, `status` and `content_expired`. Mentions, transcription and full media detail are only on `get_message
get_messageFetch one message with its full content, parties and mentions. The answer includes the number's stable `number_id` (`num_…`) next to `number_alias`. `at` is when the message actually happened on WhatsApp; `status.at` is when it reached its current delivery status and keeps moving as receipts arriv
get_message_statusCheck where a message got to: queued, sent, delivered, read, failed. Status only moves forward. A failed status always carries an error code, and for a few media and reaction problems it also carries a hint naming the field to change; most failures give the code alone. Read the code before retrying
get_message_receiptsSee who received and who read a message. Most useful for group messages, where the single status on the message cannot express that some members read it and others have not. Requires a plan that includes read receipts; on plans without it the call is refused with `feature_not_available`, which no
get_message_reactionsList the emoji reactions on a message, and who left each one. Each entry names the reactor and the emoji. Reactions are replaced rather than accumulated per person: someone who reacts twice leaves one entry showing their latest emoji, so this is a current snapshot and not a history. An empty list
get_message_responsesSee how the guests answered a calendar event: going, not going or maybe. Only works on a calendar event; any other message answers `invalid_request: message_not_calendar`. The answer has `counts` (how many guests are going, not going or maybe, and how many extra guests those who are going or maybe
get_message_quotaCheck how much of this number's message allowance is left. The quota is **per number**, not per organization: an organization with three numbers has three separate allowances. It resets at `cycle_end`, which is the organization's real billing boundary rather than a rolling window, so `resets_at` is
list_contactsList the people this number has exchanged messages with. Filter by `phone` or by `name`. They are separate filters, not one search box: `name` matches the contact's name, `phone` matches the number. `source` restricts to how the contact first appeared: `inbound` (they messaged this number), `outbo
get_contactFetch one contact: name, phone number and activity timestamps. `first_messaged_at` is when a message from this number first reached them on WhatsApp, and `last_interaction_at` is the last message that passed in EITHER direction, so it moves when they write to you as well. A message that failed befo
get_contact_profile_pictureGet a contact's profile picture, or the reason there is none. The answer carries `kind`: `available` with a temporary URL, or `unavailable` with a reason. `no_storage` means the organization has not configured object storage, which is a setup step rather than a fault with this contact. The person m
refresh_contactAsk WhatsApp for this contact's current name. Only the name is refreshed. The profile picture updates on its own the next time this number exchanges a message with the contact, and this does not change how messages reach them. It answers right away with `requested_at`; the refresh then runs in the
get_contact_quotaCheck how much of this number's contact allowance is left. A contact counts once per billing cycle when this number messages them through Turbo Notify, new **or** returning. Messaging the same person again in a later cycle counts again. Like the message quota, this is per number rather than per or
list_groupsList the WhatsApp groups this number is a member of. The list is built when the number connects: every group it belongs to is picked up then, whether or not anything has been said in it. A group joined since then is picked up from the join itself, without waiting for anyone to speak in it. `name`
get_groupFetch a group: its name, description, picture and settings. Returns how many participants it has, not who they are. Membership is deliberately not readable: it arrives as it changes, on the `group.participants_added` / `_removed` / `_promoted` / `_demoted` events, which `list_events` can read.
get_group_pictureGet a group's picture, or the reason there is none. Same shape as a contact's picture. The answer carries `kind`: `available` with a temporary URL, or `unavailable` with a reason. `no_storage` means the organization has not configured object storage.
list_numbersList every WhatsApp number this organization has, with its status. Start here when you do not know which aliases exist. The main number is always `main`; extras carry the alias the customer chose, and that alias is what every other tool's `number_alias` expects. Each number also carries `id` (`num
get_numberCheck one number: its phone number, status, and when that status began. `id` (`num_…`) is the number's permanent identifier. The alias can be renamed, the `id` cannot. Either one works as `number_alias`. `connected` means it can send right now. `connecting` means a connection was just requested an
connect_numberReconnect a number that is currently offline. Uses the credentials already stored for the number, so no QR code and no human are involved. Use it when `get_number` reports `disconnected` and you want to send. Returns immediately, before the connection is established. The answer has the number's `a
disconnect_numberTake a number offline deliberately, keeping its link to the phone. The stored credentials survive, so `connect_number` brings it straight back with no pairing. Nothing is deleted. Disconnecting does not stop billing: an extra number is billed every cycle until it is removed. Returns immediately, b
get_usageGet message and contact usage for the whole organization. The top-level totals are the **sum across every live number**: an organization with two numbers on a 50,000-message plan reports a quota of 100,000, not 50,000. The `numbers[]` breakdown shows each number separately, which is what you need t
list_eventsPoll everything that happened: messages, contacts, groups, numbers, quotas. This is how an agent learns about inbound messages without hosting a webhook endpoint. **Events come back newest first, so polling for new ones uses `ending_before`, not `starting_after`.** Typical loop: call with no curso