Preview Emails
Return (or generate+cache) preview emails for ONE lead.
Single-lead flow: the UI asks for a specific lead_id (typically whichever lead is currently selected in the "Preview as" dropdown). Backend generates only for that lead — avoids spending tokens on leads the user never opens and keeps GenerationThinking overlay short.
touch scopes the request to ONE touch so a cache-miss request is a single generation that fits the worker budget (issue #1338: both touches in one request blew past the gunicorn timeout and surfaced as connection resets). The client requests touch-1, then touch-2 as a dependent query — each touch commits its cache row immediately, so a retry never re-pays for an already-generated touch. An unconfigured touch returns [] (200): "no follow-up set up" is a normal state, not an error. Without touch the legacy walk over all configured touches is kept for old clients during the rolling deploy.
Idempotent: generated_email is the cache keyed by (lead_id, touch_number, email_templates_version). Switching leads in the UI is a fresh queryKey on the client; revisiting a previously-selected lead within the same session is a cache hit (react-query), and even across sessions the backend returns the cached DB rows without another LLM call. Touch-2 self-heals a missing touch-1 row via get_or_generate_email's internal recursion.
Generation failures return structured details the client can render: 400 {code: 'no_template'|'leak_detected', touch, message} for user- fixable states, 502 {code: 'generation_failed', touch, message} for upstream LLM failures (kept distinct from our own 500s in monitoring).
language_used and highlights come out of the JSONB snapshot on each row — no new DB column, old rows default to empty values.
Path parameters
Query parameters
Cookies
Response
Successful Response
Changes
No recorded changes to this endpoint across all 1 revision of this API.