Create an automation
Deterministic create — the body carries the full graph ({ name, triggerEventId?, nodes, connections }). Returns 201 with the bare AutomationRow.
Trigger binding (exactly one): for an EVENT automation pass triggerEventId (then publish with PATCH … { "published": true }). For a MANUAL-AUDIENCE automation OMIT triggerEventId and give the trigger node config: { "mode": "manualAudience", "audienceId": "aud_…" } — it is launched on demand with POST /v1/automations/{automationId}/run rather than published.
Typed conditions: every filter and condition-mode split uses a non-empty conditions array. Each condition requires field, type (string, number, date, or bool), and a canonical snake_case operator. Unary operators omit value; comparisons require a type-correct scalar, non-empty array, or exact two-value between tuple as documented by AutomationNode.
Chain POST /v1/emails { prompt } first to mint the design each sendEmail node references — every sendEmail node MUST carry emailId, emailVersionId, subject (previewText is optional: the email design’s JSX <Preview> is the preview source of truth). domainId is optional on create/save; publishing (PATCH … { published: true }) or running (POST …/run) requires a verified domainId from GET /v1/domains. messageClass is optional and behaves as "marketing" at send time when unset.
Dry-run — add dryRun: true (alias dry_run) to validate without persisting; returns 200 with an AutomationDryRunReport: { valid, blockers[], warnings[], blockingIssues[], nodeCounts }. blockers[] (severity error) fail publish; warnings[] are advisory. blockingIssues[] lists per-node references the bound trigger or contact catalog cannot provide. valid is false when any blocker or any blocking issue is present.
Authorizations
Send your Brew API key as Authorization: Bearer brew_xxx.
Headers
Optional idempotency key for safe retries. Reusing the same key with the same request body returns the original response for 24 hours.
1 - 100The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise 400 BRAND_ID_REQUIRED — there is no default brand); list ids with GET /v1/brands. Brand-scoped credentials may omit it, and sending a different brand returns 403 BRAND_SCOPE_MISMATCH. A brand outside your organization returns 404 BRAND_NOT_FOUND.
1 - 64Body
1 - 120500- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
20001 - 2561000Validate only — runs the full publish-gate check and returns blockers/warnings without creating anything.
Accepted alias of dryRun.
Response
Dry-run result (returned only for dryRun: true; no writes). valid is false when any blockers[] entry or any blockingIssues[] entry is present. Create and update both return blockingIssues[] (possibly empty).
Whether the graph would publish cleanly. false when any blockers[] entry or any blockingIssues[] entry is present.
Publish blockers (severity: "error"). Publishing fails while any remain.
Advisory findings (severity: "warning"). Publishing succeeds despite them.
Per-kind node counts of the validated graph.
Trigger-payload / draft-variable compatibility findings. Present (possibly empty) on POST and PATCH dry-run responses. valid is false when any entry is present.