# Creating a batch

> Send an approved WhatsApp template to a CSV: prerequisites, Meta's rules, to_column, variable_map, pacing and send_daily_cap.

A WhatsApp batch sends one approved template to every row of a list, from a
number connected under [WhatsApp → Numbers](https://docs.talqing.com/whatsapp/messaging.md). Replies are
answered by the text agent on that number, or by one the batch names, which sees
the row's columns. Creating
a batch (`POST /v1/whatsapp/batches`) sends nothing: it lands as a `draft` you
review and then [send](https://docs.talqing.com/whatsapp/sending-and-monitoring.md).

## Before your first batch

- **A connected number** — Twilio or Gupshup, set up in [WhatsApp](https://docs.talqing.com/whatsapp/messaging.md).
  Put a published text agent on its **Messages** cell if you want replies
  answered; without one, replies are stored and counted but nobody answers.
- **An approved template** — write one under [WhatsApp → Templates](https://docs.talqing.com/whatsapp/templates.md)
  and submit it to WhatsApp (Twilio), or create it in your Gupshup app. Only
  approved templates can be picked for a batch.
- **Opted-in recipients** — you may only message people who gave you their
  number and agreed to hear from you on WhatsApp
  ([WhatsApp Business Messaging Policy](https://business.whatsapp.com/policy)).
  Messaging anyone else puts your number at risk.

## Rules Meta enforces

| Rule | Consequence |
| --- | --- |
| Every template is `marketing`, `utility` or `authentication`, and Meta re-checks approved ones | A promotional template submitted as utility is recategorized as marketing. A first message to a prospect is marketing. |
| US (`+1`) numbers never receive marketing templates | The row fails (`63049`) and is never resent. The form warns when a marketing template meets `+1` numbers. |
| Per-person marketing limit | Meta holds back a marketing template from someone who has had too many (`63049` on Twilio, `131049` on Gupshup). The batch resends it later — see `delivery_attempts` below. |
| Business messaging limit: 250 unique people a day, rising to 2,000, 10,000, 100,000 and unlimited as quality holds | Shared by every number in your business portfolio, which is why `send_daily_cap` defaults to 250. |

## Which templates can be sent

| BSP | Sendable |
| --- | --- |
| Twilio | Text, image, video or document header; footer; URL, phone, quick-reply, copy-code and call buttons |
| Gupshup | Text-only templates |

Carousel, catalog, flows and authentication templates are listed but refused.
`GET /v1/whatsapp/templates?integration_id=…` returns each template's `header`,
`body`, `footer`, `buttons` and `variables`; one with `unsupported_reason` set
cannot be sent from a batch.

## Create the batch

In the dashboard: **WhatsApp → Outbound → New batch**. Pick the sender and
template, type rows or upload a CSV (**Download a sample file** gives exactly the
columns the template needs), map the phone column and each template variable —
including one in a header or button URL — and set the pace. The preview shows
row 1 as it will arrive.

```bash cURL
curl -X POST https://api.talqing.com/v1/whatsapp/batches \
  -H "Authorization: Bearer $TALQING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": "224c93a2-f6c9-408d-bd21-bc1459f3a76f",
    "template_id": "HX91d46793053aedda5877d6c92a5f1b2f",
    "to_column": "phone",
    "variable_map": { "first_name": "first_name" },
    "send_daily_cap": { "kind": "fixed", "limit": 250 },
    "recipients": [
      { "input": { "phone": "+919876543210", "first_name": "Asha", "company": "Acme" } }
    ]
  }'
```

```typescript TypeScript
const batch = await talqing.whatsapp.batches.create({
  createWhatsAppBatchRequest: {
    integration_id: "224c93a2-f6c9-408d-bd21-bc1459f3a76f",
    template_id: "HX91d46793053aedda5877d6c92a5f1b2f",
    to_column: "phone",
    variable_map: { first_name: "first_name" },
    send_daily_cap: { kind: "fixed", limit: 250 },
    recipients: [{ input: { phone: "+919876543210", first_name: "Asha", company: "Acme" } }],
  },
});
```

```python Python
batch = talqing.whatsapp.batches.create(
    integration_id="224c93a2-f6c9-408d-bd21-bc1459f3a76f",
    template_id="HX91d46793053aedda5877d6c92a5f1b2f",
    to_column="phone",
    variable_map={"first_name": "first_name"},
    send_daily_cap={"kind": "fixed", "limit": 250},
    recipients=[{"input": {"phone": "+919876543210", "first_name": "Asha", "company": "Acme"}}],
)
```

Template variables are `1`, `2`… on Gupshup and named or numbered on Twilio;
`variable_map` maps each one to a column.

## Fields

| Field | Default | Meaning |
| --- | --- | --- |
| `name` | The template's name | 1–200 characters |
| `integration_id` | — | The connected WhatsApp number |
| `template_id` | — | An approved template on that number |
| `to_column` | — | The column holding phone numbers |
| `variable_map` | — | Template variable → column, for every variable the template has |
| `recipients` | — | 1–10,000 rows per request, each `{"input": {column: value}}`; a batch has no total ceiling |
| `timezone` | `UTC` | IANA zone for `window` and the daily cap |
| `window` | None | Sending hours and days |
| `send_gap_seconds` | `1` | Seconds between messages, 1–3600 |
| `send_daily_cap` | `{"kind": "fixed", "limit": 250}` | Messages per local day; `null` is uncapped |
| `delivery_attempts` | `3` | Sends per row, the first included, while Meta's per-person limit holds it back. 1–5; `1` never resends |
| `delivery_retry_after_hours` | `48` | Hours before a held-back row is resent, 24–168 |

`send_daily_cap` is `{"kind": "fixed", "limit": 250}` or a ramp,
`{"kind": "ramp", "start": 50, "end": 250, "step": 25, "interval_days": 1}`,
which warms up a new sender. A ramp rises by `step` every `interval_days`
**sending days** — a weekend or a pause earns nothing — and belongs to the
batch: two batches on one sender ramp independently.

## What is refused at create

The whole batch is refused, every problem listed in one `400`, when:

- a template variable is unmapped, mapped to a column that does not exist, or
  `variable_map` names a variable the template does not have;
- `to_column` is not in the list, or no row holds a valid number in it;
- the template is no longer approved or cannot be sent from a batch, the
  integration is not `active`, or a Twilio sender is not `ONLINE`.

A problem with one row never refuses the batch. The row is kept as `skipped`
with the reason, and becomes `ready` once its cell is fixed:

| Row problem | Reason shown |
| --- | --- |
| Phone blank or not a valid number | `phone is empty`, `'98x' is not a valid phone number` |
| Same number as an earlier row | `same number as row 12` |
| A mapped cell is blank, has a line break or tab, or more than four spaces in a row | `first_name is empty` |

A number without a country code is read in the **sender's** country. The
earliest row with a number keeps it, even after it is sent; delete that row and
the next row with the number takes it.

## Which agent answers

Leave the agent out and replies go to the agent on the number's **Messages**
trigger, whichever it is when they reply. Or name one: the batch takes
`agent_id`, `agent_version`, `agent`, `agent_override`, `agent_team` and `vars`
as an [outbound call](https://docs.talqing.com/telephony/outbound-calls.md) does (no `secrets`: one bag for
a whole list is the wrong shape). Each send saves that agent for the person's
reply, [as a posted template does](https://docs.talqing.com/channels/posting.md#choosing-the-agent). The
number still needs its Messages trigger on, or replies never reach Talqing
(`422` `messages_off`).

## What the replying agent knows

Every non-blank cell of a row becomes `{{userdata.<column>}}` for the agent
that answers a reply — the same rule as a [call batch](https://docs.talqing.com/telephony/batch-calling.md).
The template sits in the conversation as the agent's own first message, header,
footer and buttons included as text (`[Button: Book a demo → https://…]`).

## Next

- [Sending and monitoring](https://docs.talqing.com/whatsapp/sending-and-monitoring.md): Send the draft, pace it, and follow rows to delivered, read and replied.
- [WhatsApp](https://docs.talqing.com/whatsapp/messaging.md): Connect the number and put a text agent on its replies.
