POST endpoints use the Idempotency-Key HTTP header.
Most writes replay the cached response for 24 hours; trigger fires replay for 90 days.
The same key with a different body returns 409 IDEMPOTENCY_CONFLICT.
A key is shared by the HTTP API and MCP.
A write retried over the other interface with the same inputs and key replays its first result.
One replay can look different from a normal HTTP result. When an MCP create_email call outlasts its wait, it returns status: "generating", emailId, and runId.
An HTTP retry of POST /v1/emails with the same key replays the accepted result instead of generating a second design.
Poll GET /v1/emails/{emailId}?runId={runId} until the design is ready or failed.
Contract
Why Every Retry Needs It
Stable keys prevent duplicate work when a network error or event redelivery makes a caller repeat aPOST. See API design notes
for the rationale and this page’s contract for the exact behavior.
In-Progress Requests and Storage Outages
For writes using the response cache, a running request holds its key for up to 15 minutes. A retry during that time returns409 IDEMPOTENCY_IN_PROGRESS.
Wait, then replay with the same inputs and key.
Replay guarantees depend on the idempotency store. If that store is unavailable, six writes fail closed. They return a retryable 503 SERVICE_UNAVAILABLE with a Retry-After header:
POST /v1/sendsPOST /v1/emails/auditPOST /v1/emails/{emailId}/inbox-placement-testsPOST /v1/automations/{automationId}/testPOST /v1/automations/{automationId}/runPOST /v1/automations/triggers/{triggerEventId}/fire
Replayed Trigger Fires
POST /v1/automations/triggers/{triggerEventId}/fire says when a response is a replay.
The first fire answers 202 with status: "triggered".
A repeat answers 200 with status: "replayed" and the original triggerInstanceId and automationRunIds.
No new runs start. The MCP fire_trigger_event tool reports a replay the same way.
A fire key is matched against the stored trigger receipt and keeps replaying for its 90-day retention period.
Use one key per business action and never reuse a key for a different fire.
The fire takes its key only from the Idempotency-Key header. A body idempotencyKey field is rejected with 400 INVALID_REQUEST.
Recommended Key Patterns
The key MUST be stable per logical operation. Common recipes:
Anti-patterns to avoid:
<uuid()>per call: defeats the purpose; every retry gets a fresh key.Date.now()per call: same as above.<sha256(body)>: vulnerable to partial replays where body bytes change.
Worked Example: Fire a Trigger with Retry
- Reuse the same
idempotencyKeyacross every retry of the same logical operation. The first request wins; later attempts replay its result. - Mint a fresh
idempotencyKeywhen the body changes. A new email recipient = a new key.
409 IDEMPOTENCY_CONFLICT Envelope
Where It Interacts with Other Contracts
- Rate limits: an idempotent replay counts against the rate-limit window. If you saw a
429on the first attempt, the retry will hit the gate too. HonorRetry-After, don’t burn keys. A429isn’t stored under the key, so the same key works once the window clears. - Workflow runs: a trigger replay returns the original
automationRunIds[]at the top level, so polling follows the same runs. - Sends: a production-send replay returns the original
sendId. A fresh key creates another send of the design.
SDK Behavior
The official@brew.new/sdk generates a key for each supported POST operation and retains it across automatic retries.
Image-upload steps have separate retry rules.
To recover across processes, supply and retain a stable key in RequestOptions:
Related
- Rate limits: pair with idempotency for safe retry loops.
- Errors: full
409 IDEMPOTENCY_CONFLICTenvelope. - Async jobs & polling: for fire / send retries you typically don’t need to call again. Poll the run instead.
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.
Ask ChatGPT or Claude
Click here to open the Copy page menu at the top of this page, then send the page to ChatGPT, Claude, or your editor.