Let your AI work in your WhatsApp support
Raabta speaks MCP, the standard way AI apps use other software. Connect Claude, ChatGPT, Cursor or your own agent and ask it things like “show today's urgent chats”, “draft replies for the refund questions” or “close chats nobody answered in a week”. You sign in once and choose exactly what it may do — no key to copy, and you can switch it off any time.
Raabta's MCP address
https://raabta.komyosys.ai/mcpWant to see it first? Raabta customers can run every tool by hand on Menu → AI access → Playground.
Connect in a minute
Claude (claude.ai and Claude Desktop)
- Open Settings → Connectors and choose Add custom connector.
- Name it Raabta and paste the address above.
- Press Connect: Raabta opens — sign in, choose your business and permissions, press Allow.
Claude Code
- Run this once, then type
/mcpin Claude Code and choose Authenticate next to raabta.
claude mcp add --transport http raabta https://raabta.komyosys.ai/mcpChatGPT
- Open Settings → Apps & Connectors → Advanced and turn on Developer mode (plans that allow custom connectors).
- Choose Create, name it Raabta, paste the address above, authentication OAuth.
- ChatGPT opens Raabta: sign in, choose permissions, press Allow.
Cursor
- Click Add to Cursor, then press Connect next to raabta in Cursor's MCP settings.
VS Code (GitHub Copilot)
- Click Install in VS Code and sign in when VS Code asks.
Any other MCP app
- Add a remote (streamable HTTP) server with this config. Apps that support MCP sign-in will open Raabta by themselves.
{
"mcpServers": {
"raabta": {
"type": "http",
"url": "https://raabta.komyosys.ai/mcp"
}
}
}Only owners and managers of a business can connect an AI. Prefer a key for your own scripts or bots? Create one on Menu → AI access and send it asAuthorization: Bearer ak_….
You decide what it may do
Read tickets
Tickets, chats, voice-note transcripts, ratings, stats, team list (always on)
Read knowledge base
Search help articles
Write internal notes
Team-only notes on tickets
Suggest replies
Drafts a human approves before sending
Update tickets
Status, priority, category, summary, assignee, tags, snooze, split, merge, link; pin/follow for a named team member
Close quiet chats in bulk
Closes open/pending chats with no message for 3+ days (up to 200 at a time; customers aren't messaged)
Edit knowledge base
Create and update help articles
Message customers directly · owner only
Sends WhatsApp replies and forwards messages without approval
Safe by default
- Each connection only sees one business, with the permissions you ticked. Reading is always on; everything else is opt-in.
- Limits per connection: 60 calls a minute and, if it may message customers, 200 messages a day. Access ends when you choose (30 days to never).
- Every action is in the AI audit log, and shows on the ticket with 🤖 and the AI's name. Revoke it on AI access and it stops at once.
- When a team member takes over a chat, nothing from an AI reaches that customer until the chat is handed back.
- Standard MCP sign-in (OAuth 2.1 with PKCE): short-lived tokens (1 hour), rotating refresh tokens, only hashes stored. Raabta never sees your AI app's password, and the AI app never sees yours.
What an AI can do (21 tools)
| Tool | What it does | Needs |
|---|---|---|
list_ticketsread only | List or search support tickets (newest activity first). Search matches ticket number, customer name/phone, summary and message text. | Read tickets |
get_ticketread only | Full ticket: details, complete timeline (customer/agent/AI messages incl. voice-note transcripts, internal notes, status changes), pending reply drafts and the customer's previous tickets. Each message has a message_id (for split_ticket / forward_message). | Read tickets |
get_statsread only | Support statistics for the last N days: volume, status/category/priority breakdown, response and resolution times, SLA breaches, customer rating. | Read tickets |
list_teamread only | Active human support staff (name, email, role). Use the email to assign tickets. | Read tickets |
get_activityread only | Audit log: who did what and when (staff, AI, customers, system), with before → after values. Optionally for one ticket. | Read tickets |
get_customerread only | Customer profile by WhatsApp phone number (digits with country code): name, company, email, notes, custom fields, ticket history, average rating. | Read tickets |
search_knowledgeread only | Search the organization's knowledge base (help articles / FAQ) used to answer customers. | Read knowledge base |
upsert_knowledge | Create a knowledge-base article, or update one by article_id. Write clear question-style titles and step-by-step answers. | Edit knowledge base |
add_note | Add an internal note to a ticket. Only the support team sees notes, never the customer. | Write internal notes |
create_draft | Propose a reply to the customer. A human agent reviews it in the dashboard and decides whether to send it. | Suggest replies |
update_ticket | Change a ticket's status, priority, category, summary or assignee. Only the given fields change. assignee_email "" unassigns. | Update tickets |
set_tags | Add and/or remove tags (labels) on a ticket. New tag names are created automatically. Returns the ticket's tags. | Update tickets |
snooze_ticket | Snooze a ticket: hide it from the Active inbox until a time (at most 90 days ahead). It comes back by itself then, or at once when the customer writes. Give until (ISO time) or hours; neither = unsnooze now. The alert when it is back goes to alert_email (a team member, see list_team), else the ticket's assignee. | Update tickets |
pin_ticket | Pin a ticket to the top of a team member's own Inbox (each person has at most 10 pins), or unpin it (pin: false). Pins belong to a person, so name them by email (see list_team). | Update tickets |
follow_ticket | Make a team member follow a ticket (they get alerts about customer replies and changes), or stop following (follow: false). Name them by email (see list_team). | Update tickets |
split_ticket | "New ticket from here": when a customer raises a new issue in the same chat, move that message and every later one to a new ticket for the same customer. Both tickets are linked. Take message_id from get_ticket's timeline. Returns new_ticket_number. | Update tickets |
merge_ticketscan't be undone | Merge a duplicate ticket of the SAME customer into this one: its messages, notes, drafts and tags move here and the duplicate is closed. Cannot be undone. For related tickets of different customers use link_tickets. | Update tickets |
link_tickets | Link two related tickets (e.g. different customers with the same problem), or unlink them (unlink: true). Linked tickets show in each ticket's linked_ticket_numbers. | Update tickets |
close_quiet_ticketscan't be undone | Close open/pending chats with no message for `days` days (default 7, at least 3), oldest first, at most 200 per call. Snoozed and merged tickets are skipped. Customers are not messaged; if one writes again a new ticket opens. Call with dry_run: true first to see which tickets would close. | Close quiet chats in bulk |
send_messagemessages customers | Send a WhatsApp text reply directly to the ticket's customer. The customer sees it immediately; it is marked as sent by this AI. Pass an idempotency_key to make retries safe: the same key never sends twice. If the result says delivery is unknown, do not resend automatically. | Message customers directly |
forward_messagemessages customers | Forward a message (its text, and a copy of its file) from one ticket to another ticket's customer. The customer sees it immediately; it counts toward this key's daily send limit. Take message_id from get_ticket's timeline. Pass an idempotency_key to make retries safe. If the result says delivery is unknown, do not resend automatically. | Message customers directly |
Ready-made prompts
Your AI app lists these in its prompt menu (in Claude Code type /mcp__raabta__). Each shows only if the connection has its permissions.
Morning triage morning_triage
What needs attention today: urgent and late chats, who is waiting longest, what is unassigned.
Needs: Read tickets
Draft replies for waiting chats reply_drafts
Reads chats waiting for a reply and saves a reply draft on each for the team to approve. Sends nothing.
Needs: Read tickets, Suggest replies
Ticket deep dive ticket_deep_dive
Everything about one ticket: what happened, what the customer wants, history, and the best next step.
Needs: Read tickets
Review quiet chats quiet_chats_review
Lists chats nobody has replied to for a number of days (dry run) and asks before closing them.
Needs: Read tickets, Close quiet chats in bulk
Weekly support report weekly_report
A short report of the last 7 days: volume, speed, who handled what, recurring questions.
Needs: Read tickets
Live alerts for your own agent (webhooks)
Chat apps like Claude act when you ask. To have your own agent react by itself, add a webhook on Menu → AI access: Raabta POSTs JSON to your https address on a new chat, a customer message, the AI handing a chat to the teamor a missed reply deadline. The event has the ticket number; your agent then calls get_ticket and acts through MCP. Works with n8n, Make, Zapier or a Claude Agent SDK app.
- Headers:
Raabta-Event,Raabta-Delivery(unique id — ignore repeats),Raabta-Signature: t=…,v1=… - Answer with any 2xx within 10 seconds. Otherwise Raabta retries 5 more times over about 15 minutes; 50 failures in a row switch the webhook off.
- Body:
type,created_at,delivery_id,ticket(number, status, priority, channel, summary, customer_name, …) andmessage(text) when there is one.
Check the signature (Node.js)
import crypto from "node:crypto";
// rawBody: the request body exactly as received (a string), header: req.headers["raabta-signature"]
export function fromRaabta(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // older than 5 minutes
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Python
import hmac, hashlib, time
def from_raabta(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])For developers
- Server
https://raabta.komyosys.ai/mcp— streamable HTTP (JSON-RPC over POST, stateless), MCP 2025-06-18- Sign-in
- OAuth 2.1 authorization code + PKCE (S256), dynamic client registration, refresh tokens. Metadata:
https://raabta.komyosys.ai/.well-known/oauth-protected-resource/mcpandhttps://raabta.komyosys.ai/.well-known/oauth-authorization-server - Keys
Authorization: Bearer ak_…from AI access (for scripts and your own agents)- Capabilities
- tools and prompts (no resources yet); every request is logged per connection and shown to the business on AI access → Usage
- Events
- signed webhooks — see Live alerts
- Tool list
https://raabta.komyosys.ai/mcp/tools(JSON, public)- Errors
- 401 with a
WWW-Authenticateheader pointing to the sign-in metadata; tool errors come back asisErrorresults