# The WhatsApp reply would not send

Six things stop a finished WhatsApp reply and they look similar on screen: the autonomy mode held it, a STOP or a block refused it, the plan's allowance is spent, the 24-hour window has closed, the template is not one Meta approved, or the hourly cap for the connection type is reached. The decision log distinguishes them.

- **Status:** Available
- **Audience:** both
- **Channels:** whatsapp
- **In the app:** #/whatsapp, #/needs-you, #/autonomy-audit
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/troubleshooting/whatsapp-send-failed/

## What the symptom looks like

There is a reply on the conversation and the customer has not received it. Either it sits as a draft, or it shows a failure. Other messages on other threads may be going out normally, which rules out a dead channel and points at something specific to this message or this contact.

## What it means

A reply passes several independent gates after it is written, and any one of them can stop it on its own. Some are Connect's decisions, one is commercial, and three are Meta's rules applied locally before the network call. Diagnosing this is mostly a matter of finding out which gate you are looking at, because they have different fixes and most of them are not faults at all.

## Causes, in the order worth checking

| Cause | How it presents | What to do |
|---|---|---|
| Autonomy held it | A draft, with an item in Needs You — or nothing queued at all under `draft_only` | Approve it, or change the mode for the scope that applies |
| A STOP, a block or a do-not-contact | The send is refused outright, naming the reason | Nothing, usually. This is the gate working |
| The conversation is paused or taken over | No draft is written at all; on a QR-linked number the handset took it over | Resume it from the conversation, once the person on the phone has finished |
| The plan's allowance is spent | The approval is accepted and the send waits | Wait for the reset, or change the plan. Owner workspaces have no allowance |
| The 24-hour window has closed | A refusal naming the window, with the time it closed | Send an approved template, or wait for the customer to write first |
| The template is unknown or not approved | A refusal naming the template and its state at Meta | Sync templates, or use a name exactly as Meta approved it |
| The hourly cap is reached | A refusal saying how many automatic messages have gone from this number in the last hour | Wait. 120 an hour on an Official API number, 20 on a QR-linked one |

Check them roughly in that order. The first three are visible without leaving the conversation, the fourth explains an approval that seemed to do nothing, and the last three name themselves in the refusal — which is why reading the reason beats guessing at it.

## What Connect did complete

- It read the message, grounded an answer and wrote a reply — the work up to the send is done and is not repeated when you approve it.
- It evaluated every gate and recorded which one stopped the message, with the rule that applied.
- It kept the draft. Nothing is lost, and an edit you make before approving is what is sent.
- It left the conversation, the relationship and the timeline consistent — there is no half-sent state.

## What Connect did not complete

The send. The customer has received nothing, and nothing about a held or refused reply is visible to them — no typing indicator, no partial message, no delivery attempt. From their side the business simply has not answered yet, and the clock they are counting is still running.

Connect also did not retry against a refusal it knows will repeat. A suppression will refuse the next attempt for the same reason, and a closed window will not reopen because the message was sent again. Retrying into a standing refusal is noise, not resilience.

## What you can do

1. Open the item in Needs You, if there is one, and read why it is there.
   - Result: A held draft names its hold. If there is no item at all, the mode is `draft_only`, which deliberately queues nobody.
2. Try to approve it.
   - Result: A suppression refuses at this point and shows its origin. An approval that is accepted but does not send is the allowance.
3. Read the refusal on the conversation. It names which rule stopped the message.
   - Result: A window reason means the message was fine and the moment was wrong — answering promptly while a window is open prevents it rather than fixing it. A template reason means the name is not on the list synced from Meta, or Meta has not approved it. A cap reason means waiting, and nothing else.

## What an administrator can do

Change the autonomy rule at the right scope — contact, endpoint, channel or workspace, narrowest first — if replies are being held more than you intended. Clear a suppression only where clearing it is genuinely correct; a do-not-contact entry is deliberately harder to remove and the Connect Assistant cannot remove one at all. If every send is failing rather than one, treat it as a credential problem: a rotated token breaks sending while inbound messages keep arriving, because the webhook is authenticated by the app secret rather than by the token.

One check applies before any of the others on a fresh installation: is a number connected at all? Production has none, so on the live build every send fails with `not_connected` and nothing above is the cause — see [What WhatsApp cannot do here](/docs/whatsapp/whatsapp-limits/).

## When to escalate

Escalate to Meta when sends fail with a reason that is not the window, the cap, a template or a credential — or when a template Meta's own console shows as approved is refused after a fresh sync. Escalate internally when a reply is held with no visible hold and no queued item: that combination is not one of the causes above and is worth investigating rather than working around.

## Questions

### Is a held reply the same as a slow reply?

No. A held reply has never been handed to Meta, so from the customer's side it is no reply at all. That distinction matters most when somebody is waiting for an answer.

### Can I force a send past a suppression?

No, and that is the point of it. If the suppression is wrong, correct the suppression — with the authority that requires — rather than bypassing it for one message.

### Why did approving do nothing at all?

Most often the allowance on a customer plan. The approval is recorded and the send waits; the item stays visible until it goes.

## Related

- [Replying on WhatsApp](https://connectbyjbrh.com/docs/whatsapp/replying/)
- [What WhatsApp cannot do here](https://connectbyjbrh.com/docs/whatsapp/whatsapp-limits/)
- [Delivery and read status](https://connectbyjbrh.com/docs/whatsapp/message-status/)
- [Opting out of WhatsApp](https://connectbyjbrh.com/docs/whatsapp/opt-out/)
- [What Connect may do](https://connectbyjbrh.com/docs/autonomy/)
- [Troubleshooting](https://connectbyjbrh.com/docs/troubleshooting/)
- [Why 'sent' must require provider evidence](https://connectbyjbrh.com/research/provider-evidence-for-sent/)

## What this page is based on

- `backend/app/whatsapp.py` — the refusals in `send_message` and `dispatch`, and `AUTO_SENDS_PER_HOUR`
- `backend/app/whatsapp_engine.py` — the checks that stop a draft being written at all
- `docs-source/sources/GENERAL.md` §5 — autonomy scopes and the audit trail, §8 — the Assistant's narrower rights
- Connect capability registry (docs-source/facts.py) — `WHATSAPP`, `held_draft_approval`
