> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscription Emails to Your Customers

> The six emails Waffo can send directly to a subscriber, exactly when each one fires, which language it is rendered in, how to keep them from colliding with your own emails, and what the subscription billing history returns.

Waffo can email your subscriber directly at six points in a subscription's
life. This page is about **those emails** — what fires them and how to avoid
sending the customer two of everything. For the webhooks Waffo sends to *your*
server, see the notification table in the
[Subscription FAQ](/docs/en/support/subscription-faq); for retry behavior see
[Subscription retries & payment methods](/docs/en/support/subscription-retry-and-payment-methods-faq).

## Which emails does Waffo send to my subscribers?

Six, each with its own independent on/off switch — so any subset can be
enabled for your account:

| Email | Fires when |
| - | - |
| Subscription activated | The subscription reaches `ACTIVE` on its **first** billing period. |
| Trial ending soon | Shortly before the trial period ends. |
| Upcoming payment | Shortly before each deduction, **trial periods included**. |
| Payment failed | A deduction attempt fails — with conditions, see below. |
| Subscription cancelled | A cancellation completes. |
| Subscription changed | You change the amount through the update API. |

The sixth row is the one most integrations miss. If you already email your own
customers about a price change, check whether the **subscription changed**
email is enabled for your account before you send your own.

## Exactly when does each one fire?

Three of the six are event-driven and land within moments of the event. Two run
on a daily job and therefore land within a window rather than at an exact
offset. One is triggered synchronously by your own API call.

| Email | Mechanism | Timing you can rely on |
| - | - | - |
| Subscription activated | Event-driven | On the transition to `ACTIVE`, only for the first period. A deferred-start subscription that activates on a zero-amount authorization also gets it. |
| Trial ending soon | Daily job | Once, on the first daily run that sees the trial ending within its short forward window (a few days). Sent only while the subscription is `ACTIVE` and actually in its trial. |
| Upcoming payment | Daily job | Once per period, on the first daily run that sees the next deduction within its forward window (about a day). Not sent for the final period. |
| Payment failed | Event-driven | See the next section. |
| Subscription cancelled | Event-driven | After the cancellation is committed, for any of the cancellation statuses. |
| Subscription changed | Synchronous with your update call | When an update actually changes the recurring amount, the trial amount, or the per-period scheduled amounts. |

Because the two reminder emails are driven by a **daily job over a forward
window**, treat their offsets as approximate. Do not build a customer-facing
promise such as "you will hear from us exactly N hours before" on top of them,
and do not use them as a clock for your own scheduling.

## Is the payment-failed email really sent on every failure?

No, and assuming it is will make your de-duplication wrong. It is suppressed
in two cases:

* **First-period failures do not send it.** A subscription whose very first
  deduction fails produces no failure email to the customer. If you want the
  customer told at that point, that is on you.
* **Attempts that are neither final nor part of the interval-based retry
  schedule do not send it.** In practice that means the immediate
  backup-payment-method attempts are silent; the customer is not emailed once
  per backup card tried.

What does send: each distinct scheduled retry attempt, and the final attempt
that closes the period. The email carries a link for the customer to add or
update a payment method, which is usually the action you want them to take.

## What triggers the subscription-changed email, and what is in it?

Your own call to the subscription update API, when it changes any of the
recurring amount, the trial amount, or the per-period scheduled amounts. It is
sent synchronously with that call rather than by a job.

The email tells the customer what the amount was, what it now is, and from
which period the new amount applies. Where you changed the per-period schedule,
both the previous and the new schedule are included.

Two consequences worth designing around:

* A **plan change** (upgrade/downgrade through the change API) is a different
  operation and does not fire this email. See the change/update distinction in
  the [Subscription FAQ](/docs/en/support/subscription-faq).
* Because the trigger is your API call, batching several updates for one
  subscription in quick succession can produce several emails. Make one update
  call per intended customer-visible change.

## What language are these emails in?

The recipient's language is resolved in this order:

1. The **cashier language** you specified on the subscription, if you set one.
2. Otherwise, it is derived from the subscription's **`userCurrency`** — the
   currency the customer is actually charged in.
3. If neither yields a supported locale, English.

The practical rule: **`userCurrency` decides the language unless you override
it.** If your customers' language does not track their billing currency — an
English-speaking customer billed in a local currency, say — set the cashier
language explicitly on the subscription rather than relying on the derivation.

The same locale is applied to the subscription management link inside the
email, so the customer lands on a page in the same language.

## Can I edit the templates, or turn individual emails off myself?

Not from the Merchant Portal. On the current release:

* The six switches are **configured for your account by Waffo**, not
  self-serve. Tell your Waffo contact which of the six you want on, and which
  you would rather own yourself.
* The templates themselves are **not merchant-editable**. What does carry
  through is your **branding** — your merchant name and the logo/appearance you
  have configured for checkout are applied to the emails, so they are not
  unbranded.

If you need wording you control, the right pattern is to have the corresponding
Waffo email turned off and drive your own from the webhook for the same event.

## How do I keep Waffo's emails and my own from colliding?

Work from the table above and pick an owner per event. The reliable approach:

| If you want to own it | Then |
| - | - |
| The activation / welcome message | Ask for the activation email to be off; drive yours from the subscription status notification. |
| The renewal reminder | Ask for the upcoming-payment email to be off; you control the offset, which the daily job does not give you. |
| The dunning sequence | Ask for the payment-failed email to be off; drive yours from the payment order notification, which reports *every* attempt including the ones the email suppresses. |
| The price-change notice | Ask for the subscription-changed email to be off; you already know the change happened, because you made the call. |

Do not try to suppress Waffo's email by timing yours around it — the two
reminder emails land within a window, not at a fixed offset.

## Which webhook lines up with each customer email?

Every customer email has a server-side counterpart you can act on, which is
what makes "turn the email off and send your own" a workable pattern:

| Customer email | Drive your own from |
| - | - |
| Subscription activated | The subscription status notification, on the transition to `ACTIVE`. |
| Trial ending soon | Your own schedule, computed from the subscription's trial configuration — there is no per-reminder webhook. |
| Upcoming payment | Your own schedule, computed from the subscription's period configuration. |
| Payment failed | The subscription payment order notification, which reports **every** attempt — including the ones the email suppresses. |
| Subscription cancelled | The subscription status notification, on any cancellation status. |
| Subscription changed | `SUBSCRIPTION_UPDATE_NOTIFICATION`, plus the response to your own update call. |

The two reminders are the ones with no webhook equivalent, because they are
predictions rather than events. If you want reminders on an offset you control,
you compute them from the subscription itself.

## The customer says they never received an email. What should I check?

In this order — the first three account for almost every case:

1. **Is that switch on for your account?** All six are independently
   configurable and are set by Waffo, so an email you assume is on may not be.
   This is the first thing to confirm.
2. **Is it one of the suppressed cases?** A first-period failure sends no
   failure email, and backup-method attempts send none either. A customer whose
   very first charge failed will legitimately have heard nothing.
3. **Is the timing what you assumed?** The two reminder emails come from a
   daily job over a forward window, so "it did not arrive at exactly the
   offset I assumed" is expected behavior, not a missing email.
4. **Is the language what the customer expected?** An email in an unexpected
   language is sometimes reported as "no email". Check the subscription's
   `userCurrency` and whether you set a cashier language.
5. **Was the event itself real?** Confirm against the corresponding webhook
   above — if the subscription never reached `ACTIVE`, there is no activation
   email to look for.

## What does the subscription billing history return?

Two different views, and picking the wrong one is a common integration
mistake.

**The merchant inquiry API** returns a deliberately small per-period set. Pass
`paymentDetails=1` on the subscription inquiry to get it:

| Field | Meaning |
| - | - |
| `acquiringOrderId` | The order for that period — your join key into transactions and refunds. |
| `period` | The period number. |
| `orderCurrency` / `orderAmount` | The amount in your pricing currency. |
| `orderStatus` | Outcome of that period. |
| `orderUpdatedAt` | Last change to that period's order. |
| `topupDetails` | Only on periods that had a seat add-on charge: the top-up orders taken inside that period, each with its own `acquiringOrderId`, `topupAmount` and `orderStatus`. |

Note what is **not** there: no trial flag, no user currency or user amount, no
period start/end dates, no failure code. If you need those, you need the order
itself — query it by `acquiringOrderId`.

**The hosted subscription management page** that your customer sees renders a
richer per-period row, including the trial flag, both currency/amount pairs,
the period start and end, the bound method's masked card details and expiry, a
receipt link, and a customer-facing failure reason. That view is for the
customer; do not treat it as an API surface.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.