Outbound webhooks for run / send / email-event lifecycle are on the roadmap. Until they ship, polling is the supported pattern. Both surfaces work today.
The Three Async Primitives
A
POST /v1/emails (AI generation) is also long-running (~30-90s) but blocks the HTTP call until the agent renders the design or refuses. It is not a job-returning async. You get the artifact back in the response.
Fire a Trigger, Then Poll the Run
Fire returns a list ofautomationRunIds, one per Published automation it started, alongside the triggerInstanceId for the fire itself. A matched automation whose run failed to start is listed in notStarted[] with its reason instead. One skipped on purpose, such as a paused automation past its enrollment window, is not listed, and a recipient a suppression already covers counts in counts.skipped. Each run id is a workflow run you can inspect. If no bound automation is Published, the call returns 422 NO_PUBLISHED_AUTOMATION instead of the 202. There is nothing to poll, so publish at least one bound automation and re-fire.
Recommended Polling Cadence
The
automation.runs.read policy is 100/min per key. A 2-second poll is well under that for a handful of concurrent agents.
Queue a Send, Then Verify
POST /v1/sends returns 202 { status, sendId, scheduledAt? }. The sendId is the only handle: it keys the send row for every later read, and no workflow run id is exposed. The body takes EITHER an audienceId OR an inline to (a single email or an array of ≤ 50), and names the sender with from: { email, name? }.
GET /v1/sends/{sendId}; add ?include=events to inline the per-recipient feed (delivered / opened / clicked / bounced) on the same row. It terminates on completed, partially_completed, failed, or canceled. For one-shot validations, the dashboard at brew.new/analytics is also a source of truth.
Idempotency on Async Retries
Use one stable key for each retried operation. See Idempotency for the replay contract and API design notes for the retry rationale.Agent Concurrency Patterns
Pattern 1: Fan Out, Fan In
An agent that runs 50 different welcome flows in parallel:automation.runs.write policy is 60/min. For 50 parallel fires, you’re well under; for 200+ you’d batch with Promise.allSettled + a 429-aware retry helper.
Pattern 2: Long-Poll a Single Run to Terminal
Use a generator so the agent can yield other work between polls:Pattern 3: Bulk Inspect by Automation
For dashboards / agents that want “the last 100 runs of this automation”:Cancel Instead of Waiting
A run or a send that should stop has its own action sub-path, so you never PATCH a status onto it:
Canceling answers
200 with the new status and, for a run, the
previousStatus it left. Emails already delivered are not recalled.
Why No Webhooks Today
Outbound webhooks remain on the roadmap. Until they ship, the poll loop on/v1/automations/runs is the supported way to wait for terminal status. See
API design notes
for the design rationale and Events & webhooks
for the planned contract.
Endpoints That Are Already Async-Friendly
See Also
- Idempotency: pair with every async retry.
- Rate limits: keep your poll loop under
automation.runs.read(100/min). - Webhooks & events: inbound model today + outbound roadmap.
- Pagination: for bulk-inspecting runs.
- Agentic cookbook: end-to-end recipes built on these primitives.
Need Help?
Our team is ready to support you at every step of your journey with Brew. Choose the option that works best for you:- Self-Service Tools
- Talk to Our Team
Search Documentation
Type in the “Ask any question” search bar at the top left to instantly find relevant documentation pages.
ChatGPT/Claude Integration
Click “Open in ChatGPT” at the top right of any page to explore it further with ChatGPT or Claude.