Send one letter template to up to 1,000 recipients in a single call, each letter rendered with its own data and tracked together.
Send the same letter to many recipients in one call. A batch takes a stored
letter template and a recipient list, renders one letter per recipient, and
groups them under a single letter_batch you can track together.
Batches use the same scopes as single letters: creating a batch needs
letters:send; reading one needs letters:read.
Create a batch
POST /v1/letters/batches takes a templateId and a recipients array — one
entry per letter, up to 1,000. Each recipient is a postal to address plus
the optional templateData that fills the template's
placeholders for that one letter. Every other option is set once and applies
to every letter in the batch.
Request fields
| Field | Required | Description |
|---|---|---|
templateId | yes | The stored letter template rendered once per recipient. An unknown id returns 404. |
recipients | yes | 1–1,000 entries of { to, templateData? }. to needs a country and a street or poBox; templateData fills that letter's {{placeholders}}. |
from | no | Optional sender block applied to every letter. |
print | no | mode, sides, addressPlacement — shared by every letter. See Print & delivery options. |
delivery | no | Delivery class; defaults to economy. Shared by every letter. |
paymentSlip | no | Declares a payment slip (qr, sepaDe, sepaAt) the template already draws, applied to every letter. |
autoSend | no | true (default) queues each letter for posting; false stores them as drafts. |
notifications | no | Owner milestone emails per letter; defaults to true. See Status & tracking. |
metadata | no | Opaque JSON object applied to every letter. |
The whole request is validated before anything is created — the template id,
the shared options, and every recipient's address and country. One malformed
recipient fails the call with 400 or 422 and no letter is created. Past
create, each letter is its own irreversible physical send: the cancellation
window applies per letter, not to the batch as a whole.
Track a batch
GET /v1/letters/batches/{id} returns the batch with a live rollup: its
member letters counted by status in statusCounts, and completed — the
number of letters in a terminal state (delivered, undeliverable,
canceled, or failed).
To work with the letters individually, list them with the batchId filter —
each member is an ordinary letter you can fetch, track, and cancel one at a
time on Send a letter. Each member's
letter.status_changed webhook events also carry the batchId, so a webhook
consumer can attribute every update to its batch.
From an MCP agent
Connect an MCP-compatible agent to the hosted server
and batches are available as named tools, gated by the same scopes. Sending is
state-changing, so send_letters requires an explicit confirm: true.
Tool (action) | Operation | Scope |
|---|---|---|
send_letters { "action": "sendBatch" } | Create a batch | letters:send |
list_letters { "action": "getBatch" } | Get a batch's status rollup | letters:read |
list_letters { "action": "list", "batchId": … } | List a batch's member letters | letters:read |
To project a batch's cost, price one letter with the template's page count and your delivery class. Each member is priced for its own page count, so when every recipient renders the same number of pages the batch total is the recipient count times the per-letter price.
Next steps
- API reference — full request and response schemas for batches.