---
title: "Render a lifecycle email without sending it"
method: POST
path: "/stats/admin-emails/preview"
tags: ["Admin Emails"]
---

# Render a lifecycle email without sending it

`POST /stats/admin-emails/preview`

## Request

- Base URL: `https://api.nippy.host`
- URL: `https://api.nippy.host/stats/admin-emails/preview`
- Auth: `bearer` (a scheme the document does not define)

Returns the subject, preheader, HTML and plain-text bodies exactly as they would be sent, for a context you supply. Nothing is sent and nothing is recorded.

## Request body

- PreviewLifecycleEmailDto
  - `template` 'welcome' | 'agent_welcome' | 'unblock' | 'update_lesson' | 'trial_tips' | 'activation_ask' | 'paid_activation' | 'first_visitors' | 'preview_expiring' | 'payment_failed' | 'plan_ended_unpaid', required: Which lifecycle template to render. Retired keys are rejected — they have no template function.
  - `context` LifecycleContextDto
    - `productUrl` string: Marketing/dashboard origin every link is built from.
    - `siteId` string, nullable: Id of the live site the email links to.
    - `siteContent` 'pdf' | 'html' | 'generic': What the live site is, from its upload manifest: a single PDF, a website, or neither.
    - `siteUrl` string, nullable: Public URL of the account's oldest live site. Null when nothing is live.
    - `siteHost` string, nullable: Display host of that site.
    - `paid` boolean: Account holds an entitled paid subscription (trial included).
    - `trial` boolean: That subscription is specifically in its trial period.
    - `planName` string, nullable: Paid plan display name.
    - `viewCount` number, nullable: Recorded views on the live site over the activity period.
    - `activityFrom` string, nullable: First day of the activity period, as printed.
    - `activityTo` string, nullable: Last day of the activity period, as printed.
    - `previewHost` string, nullable: Display host of the expiring preview.
    - `previewUrl` string, nullable: Public URL of that preview.
    - `publishesProgrammatically` boolean: Account publishes through an agent or the CLI rather than the dashboard.
    - `chargeAmount` string, nullable: The failed charge as the recipient sees it. Billing notices only.
    - `invoiceUrl` string, nullable: Stripe's hosted page for the unpaid invoice.
    - `sitesAffected` number: Live sites over the Free cap that a lapse takes, or has taken, offline.
    - `firstCharge` boolean: The failed charge was the first one after a free trial.
    - `unsubscribeUrl` string: Public opt-out link.
    - `companyName` string: Legal entity shown in the footer.
    - `companyAddress` string: Postal address shown in the footer of marketing mail.

## Response `200`

- APILifecycleEmailPreview
  - `template` 'welcome' | 'agent_welcome' | 'unblock' | 'make_it_yours' | 'update_lesson' | 'trial_tips' | 'trial_ending' | 'activation_ask' | 'feedback_ask' | 'week_one_upsell' | 'paid_activation' | 'first_visitors' | 'preview_expiring' | 'payment_failed' | 'plan_ended_unpaid', required
  - `subject` string, required
  - `preheader` string, required: The client's preview snippet, shown right after the subject line.
  - `html` string, required: Complete HTML document, exactly as sent.
  - `text` string, required: Plain-text alternative, exactly as sent.
  - `stream` 'broadcast' | 'transactional', required
  - `from` string, required: Sender this template goes out from — the founder-voice lifecycle address.
  - `context` object, required: The full context used for this render, after overrides were layered over the sample defaults.

## Other responses

- `403`: Admin access required

---

[API](https://skmtc.dev/nippy/apis/nippy-backend-api.md) · [All operations](https://skmtc.dev/nippy/apis/nippy-backend-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nippy/apis/nippy-backend-api/revisions/7ab23f040a55?raw)
