You connected WhatsApp to Claude or to ChatGPT. It reads your threads, tells you who is still waiting, drafts the reply, sends it from your number. Genuinely good.
Then you close the chat and everything stops.
That is not a bug and it is not a missing feature. It is what a chat connector is. Every guide on the internet, including ours, ends at the moment the connector starts working. This one starts there.
What a WhatsApp chat connector actually does
A chat connector gives your AI client a set of WhatsApp tools it can call during a conversation. You ask, it calls, it answers. It has no timer, no inbox listener, and no way to act between your messages. Nine tool families, all request and response.
chats- read threads, search, send inside a conversationscheduled_messages- send now, or hand a send to the platform for latercontacts- look up who is whogroups- create, update, leaveaudiences- reusable recipient listscampaigns- paced bulk delivery with pause, resume, cancelwebhooks- register and manage HTTPS callbacksengine- status, logout, reloadutils- phone validation, link preview, current date and time
If you have not wired one up yet, the click-paths live on their own pages: connect WhatsApp to ChatGPT and connect WhatsApp to Claude. Nothing below repeats those steps. This page assumes the connector already works and asks what you do with the other twenty-three hours of the day.
Why the connector alone is not running your business with AI
Because a connector only fires while you are typing. It cannot start a conversation at 09:00, cannot notice a customer replied at 23:40, and cannot tell you its own WhatsApp session died overnight. Triage and drafting are real value. Autonomy is a different mechanism, and you have to add it.
Run the honest test. Ask your assistant to chase an unpaid invoice next Tuesday morning. In a pure chat connector, one of two things happens: the model tells you it will remind you (it will not, the session ends), or it calls scheduled_messages and hands the job to a platform that runs without it. The second one is the whole point, and almost nobody explains that the handoff is what did the work.
Here is the split, laid out plainly:
| Job | Chat connector alone | Needs the rest of the toolkit |
|---|---|---|
| "Who is waiting on me?" | Yes | - |
| "Draft a reply to Dana" | Yes | - |
| "Send this Tuesday at 09:00" | Creates it only | Platform fires it |
| "React when a customer replies" | No | Inbound webhook |
| "Tell me the send actually left" | No | Delivery webhook |
| "Be reachable at 03:00" | No | Always-on engine |
A chief-of-staff style assistant is the first column done well. The second column is a different build, and it is where "control WhatsApp with AI" stops being a demo.
The three pieces that close the loop
Three, and they are independent of which chatbot you use. A scheduled send fires work forward in time. A webhook lets inbound events wake your code. A live engine makes both real at the moment they are due. Miss the third and the first two silently do nothing.
- Fire later -
POST /v1/scheduled-messages/{chatId}with asendAt. - React to inbound -
POST /v1/webhookswith the events you care about. - Stay online - an engine that is connected at fire time, not at schedule time.
All three sit on the same REST surface your connector is already talking to, authenticated with Authorization: Bearer bt_live_... (auth reference). That matters more than it sounds: the connector and your code are two clients of one platform, not two competing integrations. The agent-native argument is exactly this, that the API and the MCP surface should be the same surface.
Piece 1: schedule the send so it fires without you
A scheduled send moves execution off your machine and onto the platform. You create it now, from a chat or from code, and the platform owns delivery from there. The window is wide: sendAt must be at least 10 seconds and at most 365 days in the future, RFC 3339.

curl -X POST "https://api.blueticks.co/v1/scheduled-messages/+15551234567" \
-H "Authorization: Bearer $BLUETICKS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: invoice-4471-chase-1" \
-d '{
"type": "text",
"text": "Morning Ilan, following up on invoice 4471.",
"sendAt": "2026-08-25T09:00:00+03:00"
}'
Three details that save you a bad week:
- The recipient goes in the path, not the body. A phone number in E.164, or a chat id like
1234567890@g.us. Posting to bare/v1/scheduled-messagesreturns410 Gone. Idempotency-Keyis the retry control. Max 64 characters, scoped to your workspace. Replay the same key with the same body and you get200and the original response instead of a second message. Same key with a different body returns409 Conflict. Without it, one network timeout plus one retry equals one customer receiving your invoice chase twice.textis 1 to 4096 characters and a link preview card is attached automatically when the body contains a URL. Full variants for media and polls are in the sending reference.
The no-code version of this is one sentence to your assistant, covered in scheduling WhatsApp messages from Claude. The production version, with timezone and retry discipline, is in scheduling from Python. Both land on the same endpoint. The connector is a creation surface. The platform is the execution surface. Keep those two words separate in your head and most of the confusion about what AI can "do" on WhatsApp goes away.
Piece 2: let inbound events wake your code
A webhook is the inbound half. You register an HTTPS URL, the platform POSTs to it when something happens, and your code runs without anyone being in a chat. The events array on POST /v1/webhooks accepts 27 type strings today. Two of them matter on day one.

curl -X POST "https://api.blueticks.co/v1/webhooks" \
-H "Authorization: Bearer $BLUETICKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/whatsapp",
"events": ["new_message_received_webhook", "message.delivered"],
"description": "inbound + delivery"
}'
One naming trap. The inbound event is new_message_received_webhook. If you copy an events example from an older spec snapshot you may see message.received instead. That string is not in the accepted enum and the request will be rejected. Use the long name.
The two directions already have their own pages and I am not going to rewrite them here. Receiving inbound messages and answering them, with working Flask and Express handlers, is in WhatsApp webhooks and auto-reply. Tracking what happened to a message you sent is in delivery status webhooks, published the day before this one, and it is the natural companion to this section.
What is worth repeating, because people build on it and get burned:
message.delivereddoes not mean the recipient received it. It fires from an internalconfirmedstate, meaning the send is visible in WhatsApp's own state. It is not the second grey tick and you should not render it as one.- Do not build on read receipts.
message.readexists in the enum, but it rarely fires in practice. The events verified end to end today aremessage.queued,message.sendingandmessage.delivered. Three of five. Treat the other two as best effort. - The delivery lifecycle covers API-originated messages only. A message you type on your phone emits nothing.
Piece 3: keep an engine online for the moment the work is due
This is the piece that decides whether any of the above is real. Your number is driven by an engine, either a browser session or a hosted always-on gateway. A scheduled send needs that engine connected at fire time, not at schedule time. It is the single most common failure in this entire stack.

Picture the sequence, because it is completely undramatic. Tuesday 16:00, you tell your assistant to chase the invoice Friday at 09:00. The scheduled message is created, the API returns cleanly, everyone is happy. Thursday 18:00 you shut the laptop for a long weekend. Friday 09:00 arrives and there is nothing on your side holding a WhatsApp session. Nothing errored on Tuesday. Nothing warned you Thursday.
Check it before you rely on it, with one call:
curl "https://api.blueticks.co/v1/engines" \
-H "Authorization: Bearer $BLUETICKS_API_KEY"
You get an array. Empty means no engine is paired, and that is a normal 200, not an error. A populated entry carries connected, plus state and stream for the underlying WhatsApp connection. Your assistant can ask the same question through the engine tool's status action, in plain language: "is my WhatsApp engine connected?" Make that the first thing you check when something did not send, before you touch the connector config.
When no engine is online, a send does not queue politely and hope. The API answers 503 with No WhatsApp engine is connected for this account, which your connector surfaces as the tool failing. Blunt, but at least it is honest (error reference).
The two ways to be connected behave completely differently:
| Browser session | Hosted always-on gateway | |
|---|---|---|
| Where it runs | Your browser tab | Managed infrastructure |
| Laptop closed | Session ends | Keeps running |
| 03:00 scheduled send | Nothing fires | Fires |
| Good for | Desk hours | Everything you are not present for |
Either way it is your own number, linked by QR scan, and WhatsApp caps a standard account at four linked devices with each session counting against that. The longer version of this problem is in scheduled messages with your phone and computer off.
Your AI is awake at 03:00. Is your WhatsApp? No Meta developer console, no template approval queue, no per-message fees. Put your own number on an always-on engine so the sends you scheduled actually leave. Start free.
Wiring the whole loop from one Claude Code session
For developers the fastest path is not a settings screen. Add the remote server to Claude Code, authorise it, then let the same session write the unattended half against the same API. Five steps, one terminal, and the result outlives the session.

-
Add the server. Claude Code's documented form for a remote HTTP MCP server is
claude mcp add --transport http <name> <url>, per the Claude Code MCP reference:claude mcp add --transport http blueticks https://api.blueticks.co/mcpThe
/mcppath is not decoration. The bare host is not an MCP endpoint. Streamable HTTP is the current transport, introduced in protocol revision 2025-03-26 to replace HTTP with SSE. -
Authorise it. Run
/mcpinside a session to complete the OAuth flow. Claude Code supports OAuth 2.0 for remote HTTP servers, and from v2.1.186 you can also runclaude mcp login <name>straight from your shell. -
Verify the prerequisite before anything else. "Is my WhatsApp engine connected?" If that answer is no, stop. Everything downstream fails for one reason and you will spend an hour blaming the connector.
-
Mint an API key for the unattended half. The connector authenticates as you, in a session. Your cron job, your queue worker and your webhook receiver cannot. They need a
bt_live_key with the scopes they actually use,messages:writeandwebhooks:writebeing the usual pair. Get started at the API quickstart, and the own-number model is explained in WhatsApp REST API on your own number. -
Let the session write the receiver. This is where a coding agent earns its keep. It has the webhook schema in front of it from step 1, so ask it for the handler, the signature check and the idempotent write, then run it somewhere that is not your laptop.
The division of labour at the end looks like this. The connector is your interactive surface: read, triage, draft, approve, schedule. The API key is your unattended surface: fire, react, retry, log. Same platform, same number, two clients, and neither one depends on which chatbot you happen to prefer.
Where the two connectors stand right now
Functionally the two clients reach the same nine tool families, so neither can do something to your WhatsApp the other cannot. The difference is how you get in. Claude connects through a remote connector today. ChatGPT connects through developer mode, and developer mode is not guaranteed to be present on your account.
OpenAI's own wording, in the connect-and-test guide, is worth quoting exactly because people keep inventing plan tiers around it:
"Developer mode availability can depend on account and workspace policy."
There is no listed WhatsApp app you install from a directory today. You add the server yourself. On a work account an admin can switch developer mode off entirely, which makes it a conversation with them rather than a setting you can win, so check before you plan an evening around it. If you want the comparison of hosted and self-hosted MCP servers rather than of chat clients, that is the roundup, not this page.
The part that actually matters for this article: none of the three loop pieces depend on the connector. Scheduled sends, webhooks and engine status are REST endpoints. A cron job hitting them does not know or care whether you also talk to the same platform from Claude, from ChatGPT, or from neither. Pick the chat client on ergonomics. Build the loop once.
What breaks, and how you find out
Five failure modes, in the order they show up in real use. Four of the five are silent, which is the reason to instrument the loop rather than trust it.
- No engine at fire time. The most common by a distance. Symptom: a scheduled send that never arrives and no error you ever saw. Detection: poll
GET /v1/enginesbefore you rely on a send, and move overnight work to an always-on engine. - A duplicate send after a retry. Symptom: a customer gets the same chase twice. Cause: a timeout on the send call, a retry, and no
Idempotency-Key. Set one per logical send, not per HTTP attempt. - Treating
message.deliveredas "they read it". Symptom: your dashboard says delivered, your customer says they never got it. It certifies WhatsApp state, not a handset. - A webhook receiver that 500s quietly. Symptom: the loop works for a week then goes dead. Return
200fast, do the work asynchronously, and log every event id you accept so you can tell a redelivery from a new event. - Assuming session memory. Symptom: you told the assistant "chase Ilan on Friday", it agreed, nothing happened. Nothing persisted, because a chat turn is not a scheduler. If it did not create a scheduled message or a row in your own system, it does not exist.
One more that is not technical. Automating a personal WhatsApp account carries real risk, because unauthorised automated or bulk messaging violates WhatsApp's Terms of Service and WhatsApp enforces it. Replying inside conversations you were already having sits at the low end. Cold outreach at volume sits at the high end. Nobody selling you a connector can promise your number is safe, and anyone who does is selling something they cannot deliver.
Frequently asked questions
Can ChatGPT or Claude send WhatsApp messages while I am asleep?
Not by themselves. A chat connector only acts during a conversation. To have something happen while you are asleep, the AI has to hand the job to a platform that runs without it, either as a scheduled message with a sendAt, or as a webhook that wakes your own code. The platform then needs a connected engine at that moment.
What is the difference between the MCP connector and the REST API?
They are two clients of the same platform. The connector is interactive and authenticates as you inside a chat session. The REST API uses a bt_live_ key with scopes and runs unattended from cron jobs, queue workers and webhook receivers. Same number, same account, same nine tool families behind the scenes.
Why did my scheduled WhatsApp message not send?
In most cases no engine was connected when it came due. A scheduled send needs a live WhatsApp session at fire time, not at schedule time, so a browser tab you closed on Thursday cannot send on Friday. Check GET /v1/engines, or ask your assistant "is my WhatsApp engine connected?"
Which webhook events can I actually rely on?
message.queued, message.sending and message.delivered for outbound, and new_message_received_webhook for inbound. message.read is in the enum but rarely fires today, so do not build logic that waits for it. And message.delivered certifies WhatsApp state rather than a handset, so it is not the same thing as two grey ticks.
Do I need Claude Code specifically, or does the terminal matter?
Not at all. The loop is REST. Claude Code is convenient because claude mcp add --transport http plus /mcp gets you connected in under a minute and the same session can write your webhook receiver, but a cron job in any language hitting the same endpoints gives you an identical result.



