Skip to main content
Supported 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 a POST. 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 returns 409 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/sends
  • POST /v1/emails/audit
  • POST /v1/emails/{emailId}/inbox-placement-tests
  • POST /v1/automations/{automationId}/test
  • POST /v1/automations/{automationId}/run
  • POST /v1/automations/triggers/{triggerEventId}/fire
Other writes using it can run without deduplication. For another write that must never repeat, disable automatic retries and check whether the first request succeeded before retrying.

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. 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

Two invariants:
  1. Reuse the same idempotencyKey across every retry of the same logical operation. The first request wins; later attempts replay its result.
  2. Mint a fresh idempotencyKey when the body changes. A new email recipient = a new key.

409 IDEMPOTENCY_CONFLICT Envelope

The cached original response can be re-fetched by replaying with the same body. There is no separate “get cached result” endpoint.

Where It Interacts with Other Contracts

  • Rate limits: an idempotent replay counts against the rate-limit window. If you saw a 429 on the first attempt, the retry will hit the gate too. Honor Retry-After, don’t burn keys. A 429 isn’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:
  • Rate limits: pair with idempotency for safe retry loops.
  • Errors: full 409 IDEMPOTENCY_CONFLICT envelope.
  • 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:

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.