# Sending and monitoring

> Send a WhatsApp batch now or at start_at, add or delete rows, read row statuses and error codes, and resume a self-paused batch.

A batch is created as a `draft`. Review it on the batch page — edit any row's
cells, its phone included (`PATCH …/recipients/{recipient_id}` with
`overrides`), or delete rows — then send it with
`POST /v1/whatsapp/batches/{batch_id}/send`.

> **Warning:**
> Sending messages real people and cannot be recalled.

## Send

**Start sending** on the batch page asks when (now or at a time) and shows the
batch's timezone, window, pace and daily cap; change any of them there. The send
body takes `start_at` plus the same pacing fields as create (`timezone`,
`window`, `send_gap_seconds`, `send_daily_cap`, `delivery_attempts`,
`delivery_retry_after_hours`); an omitted field keeps the batch's value.

```bash cURL
curl -X POST https://api.talqing.com/v1/whatsapp/batches/5e2b9d14-7c3a-4f80-a1d6-3b9e0c4f7a22/send \
  -H "Authorization: Bearer $TALQING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "start_at": "2026-10-20T10:00:00+05:30", "timezone": "Asia/Kolkata" }'
```

```typescript TypeScript
const batch = await talqing.whatsapp.batches.send({
  batch_id: "5e2b9d14-7c3a-4f80-a1d6-3b9e0c4f7a22",
  sendWhatsAppBatchRequest: { start_at: "2026-10-20T10:00:00+05:30", timezone: "Asia/Kolkata" },
});
```

```python Python
batch = talqing.whatsapp.batches.send(
    "5e2b9d14-7c3a-4f80-a1d6-3b9e0c4f7a22",
    start_at="2026-10-20T10:00:00+05:30",
    timezone="Asia/Kolkata",
)
```

## Changing a running batch

| Action | Endpoint | Effect |
| --- | --- | --- |
| Edit | `PATCH /v1/whatsapp/batches/{batch_id}` | `name` at any time; pacing on any batch not `canceled` or `failed`, from the next message; `variable_map` only before sending; the agent fields on any batch not `canceled` or `failed`, replacing its agent from the next message (all of them `null` returns replies to the number's agent). Editing a ramp keeps the level reached unless you change `start`. |
| Pause | `POST …/pause` | Stops before the next message. |
| Resume | `POST …/resume` | Carries on from the next row. |
| Cancel | `POST …/cancel` | Stops for good. Sent messages stay sent; replies are still answered. |
| Delete | `DELETE /v1/whatsapp/batches/{batch_id}` | Removes a `draft`, `completed`, `canceled` or `failed` batch and its rows, delivery and reply counts included. Cancel a live batch first. Conversations it started stay. |

## Adding and deleting rows

`POST /v1/whatsapp/batches/{batch_id}/recipients` appends up to 10,000 rows to
any batch that is not `canceled` or `failed`.

> **Warning:**
> On a `sending` or `completed` batch, **added rows are messaged** at the batch's
> pace and hours with nobody pressing send; a completed batch goes back to
> `sending`. A draft holds them for review, and a paused batch until you resume.

```bash
curl -X POST https://api.talqing.com/v1/whatsapp/batches/5e2b9d14-7c3a-4f80-a1d6-3b9e0c4f7a22/recipients \
  -H "Authorization: Bearer $TALQING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "recipients": [{ "input": { "phone": "+919812345678", "first_name": "Arjun" } }] }'
```

The response has `added`, `total_recipients` and `skipped`. A number already in
the batch, or earlier in the request, is skipped with `recipient_id: null`. A
row with a bad phone or blank mapped cell is stored as `skipped` and returned
with its `recipient_id` so you can fix the cell. `row_number` is the row's
1-based position in your request.

`POST …/recipients/delete` with `recipient_ids` removes `ready` or `skipped`
rows for good; a row that was sent or is sending comes back in `rejected`. If the
deleted row held a number another row repeats, that row takes the number and
becomes `ready`.

## Row statuses

| Status | Meaning |
| --- | --- |
| `ready` | Will be sent |
| `skipped` | Skipped by a person, a repeated number, or a cell that cannot be sent (`skip_reason`: `operator`, `duplicate_recipient`, `unfillable`) |
| `sending` | Being handed to your BSP |
| `queued` | Accepted by your BSP, not yet sent on |
| `sent` | On its way to WhatsApp |
| `delivered` | On the recipient's phone |
| `read` | Opened (only when the recipient has read receipts on) |
| `undelivered` / `failed` | Did not arrive; `error_code` and `last_error` say why |

Replied rows are found with the `replied` filter on
`GET …/recipients?status=replied`; `replied_at` is set on the row. Receipts
arrive out of order, and a row only moves forward.

## Held-back rows are resent

A marketing template Meta held back under the person's marketing limit
(`63049`, `131049`) stays `undelivered` with a `next_attempt_at`
`delivery_retry_after_hours` later (default 48), and is sent again until
`delivery_attempts` (default 3, the first send included) is spent. US numbers
are never resent. Set `delivery_attempts: 1` to never resend.

## Common failures

| Shown as | Code | Meaning |
| --- | --- | --- |
| Not on WhatsApp | `63024`, `1002` | The number has no WhatsApp account |
| Not a valid WhatsApp number | `63003` | WhatsApp does not accept the number |
| Meta's marketing limit for this person | `63049`, `131049` | Held back; resent as above. Always final for a US number |
| WhatsApp refused a variable | `63013` | A value was blank or had a line break or extra spaces |
| Opted out | `63033`, `63050` | Opted out of your messages, or of marketing messages |
| Your business can't message this country | `63058` | Meta restricts your business there |

To try failed rows again, choose **New batch from failed rows** in the batch
page's menu: it opens the create form with the same sender, template, mapping
and pace, and those rows as the list.

## When the batch stops itself

The batch goes to `paused` with `failure_reason` set; fix the cause and resume.

| Cause | What to do |
| --- | --- |
| The credential is rejected, the sender is inactive, or the business account is refused | Fix the credential or account, then resume |
| WhatsApp rejected, paused or disabled the template | Check the template at your BSP, then resume |
| The BSP wallet is empty | Top up, then resume |
| WhatsApp is limiting the sender (`63018`, `63038`) | Usually the daily messaging limit. Resume later |
| Ten sends in a row failed | Resume once your BSP recovers |
| The batch's agent was deleted or unpublished, or the number's Messages trigger was turned off | Pick another agent or turn messages on, then resume |
| The last 20 delivered-or-failed messages were all refused (not counting *not on WhatsApp* and held-back rows) | Check the template and the list, then resume |

It goes to `failed`, for good, only when no resume could work: the sender was
disconnected, or the person who created the batch left the workspace or can no
longer send.

After a crash, a Twilio row whose outcome is unknown is looked up and adopted
rather than sent twice. Gupshup has no lookup, so such a row is marked `failed`
with a note to check the recipient's WhatsApp before resending.

## Webhooks and export

`whatsapp_batch.started`, `.completed`, `.paused` and `.failed` carry the same
body as `GET /v1/whatsapp/batches/{batch_id}`. `.completed` fires again each time
rows added later have all been sent. See
[webhook events](https://docs.talqing.com/api-reference/webhook-events.md).

Each sent template is also an item in the recipient's thread, and its receipts
fire [`conversation.item.status`](https://docs.talqing.com/api-reference/webhook-events.md) like any other
outbound message. To message one person rather than a list, post the template
with [`POST /v1/conversations/items`](https://docs.talqing.com/channels/posting.md).

Each row links to its conversation, where the batch's agent, or the one on the
sender's number, answers replies. The row's cells are `{{userdata.<column>}}` to the agent that
answers the reply, whatever its `conversation.context`. **Export CSV** on the batch page downloads every row with its
status, error and timestamps.

## Next

- [Creating a batch](https://docs.talqing.com/whatsapp/creating-a-batch.md): Prerequisites, Meta's rules, and every create field.
- [WhatsApp](https://docs.talqing.com/whatsapp/messaging.md): The text agent that answers replies.
