The 200 That Didn’t Do What You Asked
Here is the failure mode that costs developers the most time with any API, and it isn’t the errors. Errors are easy: you get a 4xx, you read the message, you fix the call. The expensive one is the request that returns 200 OK and quietly did something adjacent to what you meant.
You misspelled a parameter, so it was ignored and the default applied. You asked for double opt-in on a channel where it isn’t configured, so the subscriber was created confirmed. You sent a value the server clamped to its maximum. Every one of those succeeds. Every one of those ships to production and gets discovered three weeks later, by a customer.
Broadcast 2.16 adds a warnings array to API responses for exactly this: the request worked, and here is where the outcome differs from what you asked for.
{ "id": 4821, "email": "ada@example.com", "warnings": [ { "code": "unknown_parameter", "message": "Unknown parameter 'frist_name' was ignored." } ] }
It shows up when a parameter isn’t recognised, when double opt-in was skipped, when the server overrode a value you supplied. Nothing about your integration breaks by ignoring it — it’s additive, and a 200 is still a 200. But if you log warnings during development, an entire category of silent misbehaviour becomes visible on the first call rather than the thousandth.
There’s one warning worth calling out specifically, because it catches people: deactivating a subscriber through the update API now warns you that only the unsubscribe endpoint records an unsubscribe date and writes a suppression entry. Both calls “work”. Only one of them leaves the compliance trail you probably wanted.
Retrying a send can no longer send twice
Transactional email has a nasty property: the failure you can’t distinguish is a timeout. Your request went out, the connection dropped, and you have no idea whether the email sent. Retry and you might double-send a password reset. Don’t retry and the customer might get nothing.
2.16 adds an Idempotency-Key header to transactional sends.
curl -X POST https://your-broadcast.example.com/api/v1/transactional_emails \ -H "Authorization: Bearer $TOKEN" \ -H "Idempotency-Key: order-4821-receipt" \ -H "Content-Type: application/json" \ -d '{ "to": "ada@example.com", "subject": "Your receipt", "template_id": 12 }'
Retry that request as many times as you like — after a timeout, from a job that runs twice, from a queue that redelivers — and the email sends once. Pick a key derived from the thing you’re emailing about (the order ID, the reset request ID) rather than a random UUID per attempt, and your retry logic gets to be as dumb and aggressive as retry logic should be.

Migrating a list without losing its consent history
If you’re moving to Broadcast from another platform, your subscribers already double opted in. Making them do it again is both insulting and lossy — a chunk of them won’t, and you’ll have shrunk your list by migrating it.
Admin API tokens can now pass confirmed_at when creating a subscriber, bringing the original confirmation timestamp across intact. The consent record moves with the person, and no confirmation email goes out.
That is deliberately restricted to admin tokens. Being able to declare “this address consented, on this date, trust me” is a meaningful power, and it doesn’t belong on a token you handed to a form on your marketing site.
Three ways this changes a day
Writing an integration. Log the warnings array in your staging environment and you find the typo’d parameter on day one instead of after launch. It’s the cheapest possible feedback loop for a class of bug that otherwise has none.
Wiring up receipts or password resets. Set an idempotency key derived from the order or the reset token, then let your job queue retry as freely as it wants. Nobody gets two receipts.
Migrating from Mailchimp or ConvertKit. Export, then create each subscriber with their real confirmed_at. Your list arrives with its consent history rather than a fresh start, and nobody gets re-asked a question they already answered.
The rest of 2.16
The Domain DNS Health page got clearer about what it’s doing: it now explains that checks compare against a known-good baseline rather than an abstract idea of correctness, shows you the previous SPF record when one changes so you can see exactly what moved, and explains why DKIM records with randomized selector names need either the provider setup wizard or a manual selector. Cancelling a scheduled broadcast now reports an error when the cancellation fails, instead of looking like it worked. And documentation pages that link to other pages stopped failing to load, which was as embarrassing as it sounds.
Two patch releases followed within days. 2.16.1 taught DNS Health to recognise Amazon SES DKIM records, which use a minimal format that was being reported as missing even when the DNS was perfectly configured. 2.16.2 added all 18 SES regions to the email server form — including Europe (Stockholm) eu-north-1 — and fixed a genuinely nasty one: editing a server whose saved region wasn’t in the form’s list silently rewrote it to us-east-1 when you saved an unrelated change. The saved region is now preserved whether or not the list knows about it.
See the API response warnings documentation and the transactional email API reference, or read how Broadcast exposes a first-class surface for AI agents built on the same API.