SendKuy API

MCP server

Give AI assistants and agents WhatsApp, SMS and email through SendKuy, with 17 tools over API v1.

@sendkuy/mcp is a Model Context Protocol server. It lets an AI assistant or agent reach people through your SendKuy account. It can send alerts and summaries, notify customers per order, send and check OTP codes, and run campaigns you prepared in the dashboard.

It runs on your machine through npx, talks to https://app.sendkuy.com/api/v1 with your API key, and lists only the tools that key may use.

Create a key for the agent

Open Developers → Keys and create a key just for the agent. Every key needs account:read, because the server reads the key's scopes when it starts. Then add only what the agent should do:

The agent should…Scopes
Read messages and webhook deliveries while you debugaccount:read, messages:read, webhooks:read
Send notifications and alertsaccount:read, messages:write, messages:read, groups:read, contacts:read
Run OTPaccount:read, verifications:write
Run campaigns from the dashboardaccount:read, campaigns:read, campaigns:write

A key with read scopes only never lists a tool that sends. When you change a key's scopes, restart the MCP client so the server reads them again.

Install

Cursor reads .cursor/mcp.json in a project, or ~/.cursor/mcp.json for every project. VS Code reads .vscode/mcp.json and asks for the key, so it stays out of the file. Claude Desktop reads claude_desktop_config.json, and Windsurf reads ~/.config/devin/mcp_config.json.

claude mcp add --transport stdio --env SENDKUY_API_KEY=sk_live_YOUR_API_KEY sendkuy -- npx -y @sendkuy/mcp

One click: Install in Cursor · Install in VS Code · Claude Desktop: open sendkuy-mcp.mcpb from the latest release. The Cursor link fills in sk_live_YOUR_API_KEY, so replace it with your key afterwards.

Scenarios

On-call alert

Who builds it: a team running its own monitoring agent. What the agent does: when a health check fails, it messages the on-call group on WhatsApp with the service and the error, once per incident.

When the checkout health check fails, send the on-call group a WhatsApp message with the service name and the error. Use the incident id as dedupe_key.

Tools: sendkuy_list_groups to find the on-call group, then sendkuy_send_message with its grp_ id in to and dedupe_key: "incident-4821". A monitor that fires three times for the same incident still sends one message, as long as the text stays the same: the same key with a different body is refused with idempotency_key_reused. Scopes: account:read, groups:read, messages:write.

Daily revenue summary

Who builds it: a store owner, or the developer who runs their back office. What the agent does: every evening, it reads the day's sales from the store's database and sends the owner a short summary.

Every day at 21:00, total today's paid orders, compare them with yesterday, and WhatsApp the summary to +6281234567890. Use daily-revenue-YYYY-MM-DD as dedupe_key.

Tools: sendkuy_send_message. Before a long run, sendkuy_get_account shows how much WhatsApp credit is left. Scopes: account:read, messages:write.

Store operations

Who builds it: a shop with stock and orders in its own system. What the agent does: it watches for low stock and orders that have waited too long, and tells the right person.

Every hour, find products with fewer than 5 units and orders paid more than 2 hours ago that are not packed. Message the warehouse lead about stock and the shop admin about orders.

Tools: sendkuy_find_contacts to look up staff by external_id, then sendkuy_send_message to their con_ ids. Scopes: account:read, contacts:read, messages:write.

A notification per order

Who builds it: a developer adding customer updates to a store. What the agent does: it collects every order shipped in the last hour and sends each customer their own tracking number.

For every order shipped since the last run, send the customer a WhatsApp message with their name, order number and tracking link. Email customers who have no phone number.

Tools: one sendkuy_send_batch call with a different body per row, mixing WhatsApp and email. A row without credit fails on its own; the rest still go out. sendkuy_get_messages confirms delivery afterwards. Scopes: account:read, messages:write, messages:read.

OTP

Who builds it: a developer adding phone verification to sign-up. What the agent does: it sends a code and checks what the user typed.

Send a verification code to +6281234567890 by WhatsApp, falling back to SMS. Then check the code 482913.

Tools: sendkuy_send_verification, then sendkuy_check_verification. Scopes: account:read, verifications:write.

A promotion to a customer group

Who builds it: a shop that writes its campaign in the SendKuy dashboard and lets an agent decide when it goes out. What the agent does: it finds the campaign and reports its audience. Then it starts the campaign, watches delivery, and pauses if something looks wrong.

Find the draft campaign "Promo Payday", tell me how many contacts it reaches, start it, and pause it if more than 10% of the first 200 fail.

Tools: sendkuy_list_campaigns, sendkuy_start_campaign, sendkuy_get_campaign, sendkuy_control_campaign. For a quick one-off with the same text to everyone, sendkuy_send_message with the group's grp_ id is enough. Scopes: account:read, campaigns:read, campaigns:write.

Debugging an integration

Who builds it: you, while wiring SendKuy into your app. What the agent does: it answers questions about what happened, without you opening the dashboard.

Which WhatsApp messages failed in the last hour, and why? What is the status of msg_9cBe3A1H…? Why is my webhook failing?

Tools: sendkuy_list_messages, sendkuy_get_messages, sendkuy_list_webhook_deliveries. Scopes: account:read, messages:read, webhooks:read.

Tools

ToolWhat it doesScopes
sendkuy_get_accountPlan, credits per channel, usage this period, the key's scopesaccount:read
sendkuy_send_messageOne body to 1–100 recipients, contacts or a group, on one channelmessages:write
sendkuy_send_batchUp to 500 messages with different content, answered row by rowmessages:write
sendkuy_get_messagesStatus of up to 20 messages by idmessages:read
sendkuy_list_messagesRecent messages by channel, status and timemessages:read
sendkuy_cancel_messageCancel a message not sent yetmessages:write
sendkuy_send_verificationSend an OTP codeverifications:write
sendkuy_check_verificationCheck the code a user typedverifications:write
sendkuy_check_whatsapp_numbersWhich numbers are on WhatsAppnumbers:read
sendkuy_find_contactsA contact by phone or external_idcontacts:read
sendkuy_list_templatesSaved message templatestemplates:read
sendkuy_list_groupsContact groups and their sizegroups:read
sendkuy_list_campaignsCampaigns prepared in the dashboardcampaigns:read
sendkuy_start_campaignStart a campaigncampaigns:write
sendkuy_get_campaignProgress and delivery statscampaigns:read
sendkuy_control_campaignPause, resume or cancelcampaigns:write
sendkuy_list_webhook_deliveriesWebhooks and their latest delivery attemptswebhooks:read

Good to know

  • Tools that send really send, and spend credit. Give the agent a key with only the scopes it needs.
  • dedupe_key stops a repeated step from sending twice. Derive it from the event, such as order-1234-shipped, and keep changing values such as the time out of the message. The same key with different content is refused with idempotency_key_reused. A refusal is remembered under the key as well: after fixing a bad number or topping up, retry with a new key. Keys last about 24 hours. See Idempotency.
  • A suppressed recipient still gets a message id. Someone who unsubscribed or is on your suppression list is checked when the message goes out, so the message fails later. Read the final status with sendkuy_get_messages.
  • Without a key the server still starts. It lists every tool and answers each call with an error until SENDKUY_API_KEY is set.
  • Errors carry the API's own code and a link to Errors, so the agent can fix the call itself, for example a phone number without the leading +.
  • A send to a large group answers with counts. sendkuy_send_message returns the number of messages per status and the first 20; read the rest with sendkuy_list_messages.