payloadSchema); a transactional email derives one from the pinned template (every trigger.* path the design reads). This guide turns those contracts into TypeScript types in your codebase, keeps them from drifting, and shows where Brew checks real fires against them.
Nested payload values (objects and arrays) require a Liquid-enabled workspace. The same nested shape sent to a legacy workspace is rejected with
400. See Merge tags and variables.Generate types with brew-cli
brew-cli types writes one file with a type per contract (the command needs a key with the automations scope; --transaction also needs sends):
Payload. Renaming a subject renames the type, which is exactly the drift --check exists to catch; colliding names get the object id appended so the file always compiles. A template reference with no type evidence (no fallback, no numeric or boolean usage) is emitted as unknown for you to refine, never silently asserted as string.
Field optionality follows each plane’s rules. Trigger fields are optional when required: false. Transactional fields are optional when the template gives them a | default: fallback; a path with no fallback fails strict fires when the caller omits it, so it is emitted as required.
In CI, gate drift with:
1 when the workspace’s contracts no longer match the committed file, which is the signal to regenerate and review the diff. A trigger schema edit or a transactional design change shows up as a type change in code review instead of a runtime surprise.
Pin the types in SDK calls
fire and send accept a payload type parameter, so call sites compile against the contract:
Fetch the wiring brief for an agent
Both reads accept?include=skill, which adds a skill field: a complete SKILL.md-shaped brief (endpoint, auth, the typed contract inline, copy-paste snippets, and a test loop) that a coding agent can follow to wire your service.
SKILL.md in your repo, or hand the URL to an agent. The in-app contract panel offers the same file under Copy as → Download SKILL.md, and it is generated from the same source as the API response.
Preflight before the first fire
GET on the fire endpoint verifies the exact credential you will use, without firing:
200 with status: "ready" means the key, brand scope, and permissions all pass, and details carries the payload contract plus what a fire would start. counts.automations: 0 means fires are accepted and logged but start no runs until an automation wired to the trigger is published.
Verify live fires in the app
Brew checks what your service actually sent against the contract:- The transactional object page shows Recent fires vs contract: each retained fire’s raw payload, with chips for required fields the caller omitted, keys the template never reads, and strict-render failures with the recorded error.
- A trigger fire’s detail sheet (Events page) shows a Contract check: the raw body replayed through the same validator the live fire used, so a key the fire dropped is labeled exactly as dropped.
- Both object pages walk you through wiring with a step list whose completion is derived from real data: a key exists, your test fire arrived, an automation is live.