POST /v1/email/batches uploads a list, the agent task that drafts each row, a connected Resend integration and a field_map. The batch is created scheduled and starts drafting. Nothing is emailed until you POST /v1/email/batches/{batch_id}/sends. Before you start, read Email outbound for the acceptable-use rule and Resend setup.
Create a batch
recipients[].input is one CSV row keyed by header. Values are strings. Leave out empty cells instead of sending "". In the dashboard, Email → Outbound → New batch parses a CSV in the browser and posts the same request. The dashboard’s confirm dialog states how many task runs you are about to pay for.
The column space and field_map
Each row has one flat set of columns, merged in this order. A later layer wins:
The merged result is the row’s
columns. field_map.to, .subject and .body can each name either a CSV header or a task output field. For example, a list that already has addresses maps to to a CSV column such as email. A list of phone numbers maps to to an output field such as work_email, which the task looks up with its tools. Output fields you do not map are kept on the row and shown in review, but they are never sent.
Requirements on the task:
- Mapped output fields must be
string. Aboolean,integerornumberoutput field cannot be mapped. - Each row’s uploaded columns, plus edits to those columns, become the task’s
{{vars.*}}. All of them are passed, not only the ones the task declares. See inputs and output. - The task must be published. Drafting always uses the current published version. Publishing or rolling back a version that would break a live batch’s field map is refused. Deleting the task is refused while a batch using it is
scheduled,draftingorpaused.
to parses as an email address, and subject has no line break. When a mapped column that the task does not write is blank or invalid, no draft could fix it. That row is skipped with skip_reason: "unfillable" at upload, is never drafted, and costs nothing. skips.unfillable on the response counts these rows.
What is refused at create
Every problem is returned at once in one 400:- A mapped name that is neither a CSV header nor an output field of the published task, or that maps to a non-
stringoutput field. - A CSV header that is also a task output field name. Rename one of them.
- A required task variable with no matching column and no default.
- A header that is not a valid variable name. Headers must use letters, digits and underscores and start with a letter or underscore.
- A
from_emailwhose domain is not verified on the account, or afrom_emailorreply_tothat is not an address. - An integration that is missing, is not Resend, or is not
active. A task that is missing or has never been published. start_atin the past or more than 90 days ahead. Zero rows, or more than 10,000 rows in one request. Add more rows with add recipients.
Batch fields
The four
send_* fields are defaults. Each send copies them when it is created. PATCH /v1/email/batches/{batch_id} changes them for the next send. Use PATCH .../sends/{send_id} to change a send that already exists. A running batch or send applies a policy change within five minutes.
Warming up a new domain
send_daily_cap is either {"kind": "fixed", "limit": 200} (limit ≥ 1) or a ramp:
start emails a day and rises by step every interval_days (1–30) until it reaches end (end > start). It counts only days the batch actually sent, so weekends, closed windows and pauses do not advance it. send_daily_cap_today shows the limit in force today. Editing a ramp keeps its progress unless you change start. Each batch ramps separately, so two batches on the same domain together send the sum of their caps.
Review the drafts
GET /v1/email/batches/{batch_id}/recipients?status=draft&limit=50 returns rows in upload order (limit up to 200, with offset).
A
draft is always sendable. A row whose task run succeeded but produced nothing sendable, for example because no address was found, is draft_failed. The reason is in last_error, and the task output is kept so you can read what the task did find.
Export CSV on the batch page in the dashboard downloads every row. It contains your columns, the output fields, status and error. Values are written raw, so a cell starting with = opens as a formula in a spreadsheet.
Edit a cell
PATCH /v1/email/batches/{batch_id}/recipients/{recipient_id} writes overrides:
- An edit never overwrites
output, and a redraft never overwrites an edit. - An empty string clears the edit and falls back to the layer below.
- Editing one of your uploaded columns changes what the task receives the next time the row drafts.
- The row’s status is recomputed. Filling a missing mapped cell moves
draft_failedback todraft, and moves anunfillablerow back topendingso it gets drafted. Clearing a mapped cell moves a row the other way. The response includes the new status. queuedrows can still be edited. Once a row issending,sentorsend_failed, an edit returns 409.
Delete rows
POST /v1/email/batches/{batch_id}/recipients/delete with {"recipient_ids": [...]} permanently removes rows that were never sent: pending, draft (including queued), draft_failed or skipped. Other rows are returned in rejected with a reason.
Redraft
POST /v1/email/batches/{batch_id}/redraft with either recipient_ids or a selection resets rows to pending. It clears output, task_run_id, attempts and last_error, and the rows draft again.
Edited cells survive a redraft unless you pass
clear_overrides: true. unfillable rows are never redrafted. Redrafting moves a drafted or failed batch back to drafting. A paused batch stays paused. A canceled batch returns 409.
A typical way to improve drafts mid-batch: pause the send, publish a better task, redraft stale_version, then resume the send. The send picks up each new draft as it lands.
Send
Several
selected sends can be live at once, but a row belongs to only one. An all send cannot be live alongside any other send of the same batch. That conflict returns 409.
Send fields. Any field you omit is taken from the batch:
start_at: at most 90 days ahead.timezone,window: an explicitnullwindow means any hour.send_gap_seconds,send_attempts,send_retry_after_minutes,send_daily_cap: an explicitnullcap means uncapped.from_email,from_name,reply_to: apply to this send only. An overriddenfrom_emailis checked against your verified domains.
PATCH /v1/email/batches/{batch_id}/sends/{send_id} changes the pacing, window and cap, and start_at before the send begins. It never changes the sender or scope. To change which rows a send covers, cancel it and create another.
A send’s
counts has total (null for all), queued, drafting, sending, sent, send_failed and skipped. next_send_at and next_send_reason show what the send is waiting for. See monitoring.
Duplicates and resends
- An address is emailed at most once per batch. The check runs when a send claims the row, because the task may be the one that found the address. A second row with the same address is
skippedwithskip_reason: "duplicate_recipient". - There is no deduplication across batches, and Talqing keeps no suppression list. Resend keeps one on your account.
- Each email carries an idempotency key, the row’s id, which Resend honours for 24 hours. A row interrupted by a crash is resent under the same key and is not delivered twice.
Adding rows later
POST /v1/email/batches/{batch_id}/recipients appends up to 10,000 rows to any batch that is not canceled or failed. A drafted batch starts drafting again. Duplicates are dropped before drafting:
- If
tomaps to an uploaded column, a row whose address is already in the batch is dropped. - Otherwise, a row whose uploaded cells exactly repeat another row’s is dropped.
added, skipped (each entry has row_number and reason, plus recipient_id if the row was stored as unfillable), total_recipients and standing_send_id.
Row statuses
Fields locked after the first send
Once the batch has a send, or any row issending, sent or send_failed, a PATCH to from_email, from_name, reply_to, body_format or field_map returns 400. name, timezone, window, the drafting and sending fields, and send_daily_cap stay editable. A batch can be edited only while it is scheduled, drafting, paused or drafted.
Next
Monitoring
Statuses, counts, why a batch or send stops itself, webhooks and cost.
Research and outreach
A task that researches each lead, feeding an email batch end to end.