> ## 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.

# When Does a Subscription Actually Charge?

> How Waffo works out each billing date from the subscription start, why a monthly subscription started on the 31st springs back to the 31st after February, whether a late retry moves the next date, why a first-period failure is not retried, and what every per-period charge status means.

This page is about **timing**: which day a period is charged, and how that day
moves. Retry policy and payment-method behaviour are in
[Subscription retries & payment methods](/docs/en/support/subscription-retry-and-payment-methods-faq);
amounts are in
[Subscription amounts & per-period scheduling](/docs/en/support/subscription-amount-scheduling-faq).

## When is a renewal charge actually initiated?

Waffo stores a **next-charge timestamp** on the subscription and initiates that
period's charge on a periodic sweep once the timestamp has passed. Two
consequences:

* The date is deterministic; the **time of day is not**. Plan reconciliation and
  customer messaging at day granularity, not to the minute.
* All stored subscription timestamps — the next-charge time, period start and
  end, the subscription end time — are **UTC**, and the API returns them in
  ISO 8601. If your billing calendar is local, convert on your side; there is no
  per-merchant billing timezone setting.

There is no way to pin a subscription to "charge at 09:00 in the customer's
timezone". The nearest control you have is `startTime` on
`/api/v1/subscription/create`, which sets the anchor the whole schedule is
derived from — see
[Subscription creation & validation](/docs/en/support/subscription-creation-validation-faq).

## How is each subsequent billing date derived?

From the **subscription's start time**, by adding whole cycles:

```
charge date of period n = subscription start + (n − 1) × (periodInterval × periodType unit)
```

Not from the date the previous charge succeeded, and not by stepping from the
previous period's date. Every period is computed from the same anchor, so a
period that was charged late does not shift the ones after it, and rounding
never accumulates from one period to the next.

The cycle used is the **cycle in force for that period number**: if you
configured a separate trial cycle, the trial periods are counted from the start
in the trial cycle, and the regular periods are counted from the end of the
trial in the regular cycle. The switch happens at the period number where the
trial ends.

## A monthly subscription started on the 31st. What happens in February?

It **clamps to the last valid day of a short month, and springs back to the
31st afterwards.**

Because every period is computed as *start + n months*, adding one month to 31
January gives 28 February (29 in a leap year) — there is no 31 February — but
adding two months gives 31 March, and adding three gives 30 April. The clamp
applies only to the month being landed on; it does not become the new anchor.

| Period | Scheduled date |
| - | - |
| 1 | 31 January |
| 2 | 28 February (clamped) |
| 3 | 31 March |
| 4 | 30 April (clamped) |
| 5 | 31 May |

This is the single most common surprise in month-end subscriptions: **the
subscription does spring back to the 31st.** A customer who started on the 31st
is charged on the last day of every month — the 28th, 29th, 30th or 31st,
whichever that month has. Do not build a reminder that assumes a fixed
day-of-month for such a subscription.

If billing on a stable day-of-month matters to your product, start the
subscription on a day that exists in every month (1–28), or set `startTime`
explicitly rather than letting "now" decide the anchor.

## A period only succeeded after three days of retries. Does the next period move?

**By default, no.** The next period is computed from the subscription's start
as described above, so a period recovered by retries does not push the rest of
the schedule back — the customer does not gain days.

There is an **account-level setting that rebases the schedule onto the actual
payment time** instead: where it is enabled, a successful renewal recomputes the
next charge date from the moment that charge succeeded, and the subscription's
end date is recomputed with it. Two things to know about it:

* It only ever moves the schedule **forward**. If the recomputed date is earlier
  than the stored one, the stored one stands.
* It is configured on your acquiring agreement by Waffo, not in the Portal. If
  you need "the customer always gets a full cycle from the day they actually
  paid", ask your Waffo contact which behaviour is set on your account before
  you build against either one.

Because the two behaviours produce different dates, do not derive next-charge
dates yourself. Read `nextPaymentDateTime` back from
`/api/v1/subscription/inquiry` after each period.

## Which date field should I read for a "next charge" reminder?

| Field | What it means | When it changes |
| - | - | - |
| `startDateTime` | When the subscription started | Written once |
| `currentPeriod` | The period number the subscription is on now | Advances when the next period is opened |
| `nextPaymentDateTime` | The scheduled charge time of the **next** period | Advances with `currentPeriod`; **not advanced on the final period**; **returned as `null` while the renewal is held** |
| `endDateTime` | When the subscription's final period ends | Written when the total period count is resolved; recomputed if the schedule is rebased |

So: read `nextPaymentDateTime` for reminders, but handle two cases before you
promise a customer a date.

* **`null` does not mean "no more charges."** Waffo returns `null` while the
  subscription's renewal is being held — for example because the current period
  is still being attempted, or a plan change is pending on it. Once the hold
  clears, a date reappears. Treat `null` as *not known yet*, not as *finished*.
* **On the final period the value is stale rather than future.** It is not
  advanced there, so it still shows the last period's own date. Cross-check
  `currentPeriod` against the subscription's final period count, or check
  `endDateTime`, before telling a customer they will be charged again.

For "is this subscription finished", read the **status** — the terminal statuses
on [Subscription creation & validation](/docs/en/support/subscription-creation-validation-faq)
are the answer, not a date field.

## What do the per-period charge statuses mean?

Every billing period has its own order, with its own status. The Portal renders
these as *Initial*, *To Pay*, *Retrying*, *Paid* and *Closed*:

| Status | Portal label | Meaning |
| - | - | - |
| `INIT` | Initial | The period's order exists but has not been submitted for payment yet. |
| `TO_PAY` | To Pay | Submitted; awaiting the payment result. |
| `NEED_RETRY` | Retrying | The attempt failed and another attempt is scheduled. |
| `PAY_SUCCESS` | Paid | The period was collected. Final. |
| `ORDER_CLOSE` | Closed | The period will not be collected — retries were exhausted, or it was closed. Final. |

Two rules that matter more than the labels:

* `PAY_SUCCESS` and `ORDER_CLOSE` are the **only** final statuses. Anything else
  can still change.
* A period reaching `ORDER_CLOSE` does **not** change the subscription's own
  status. The subscription stays `ACTIVE` and the next period is attempted on
  schedule. Entitlement decisions are yours to make from these per-period
  outcomes; see
  [Subscription retries & payment methods](/docs/en/support/subscription-retry-and-payment-methods-faq).

## Why was the very first charge not retried at all?

Because the first charge of an immediately-starting subscription is a
**customer-present** payment, not a background renewal. When it fails, that
period's order is closed straight away: no retry schedule, no backup-method
attempt, and no payment-failed email to the customer.

The reasoning is that the customer is right there — the correct recovery is to
let them try again, or to try a different payment method, not to retry a card
they are watching fail.

| Case | First charge behaviour |
| - | - |
| Subscription starts immediately | Failure closes the period with no retry |
| Subscription has a future `startTime` | The activation charge **is** treated as a background renewal: backups are tried and the retry schedule applies |

The second row is the exception people trip over. A deferred-start subscription
is authorised up front and charged later without the customer present, so its
first charge behaves like every later one.

Recovery for the immediate case is to create a **new** subscription once the
customer picks another method. Do not create a separate one-off order for the
same period and expect the subscription to notice it.

## Can I let the customer pay a failed period themselves instead of waiting?

There is **no merchant-facing endpoint that collects a specific failed
period.** The subscription API surface is `create`, `inquiry`, `cancel`,
`manage`, `change`, `change/inquiry` and `update` — none of them re-drives a
period's charge, and there is no "pay now" or "repay" call.

What you can actually do:

| Goal | How |
| - | - |
| Get the failed period collected | Let the retry schedule run. Have the customer add or fix a payment method on the hosted management page so the next attempt has something chargeable. |
| Bill the customer something immediately | Create an ordinary **one-off order**. It is a separate transaction and is not attached to the subscription period. |
| Move the customer to a different plan or price | `/api/v1/subscription/change` — see [Subscription plan changes](/docs/en/support/subscription-plan-change-faq). |
| Stop billing | `/api/v1/subscription/cancel`. |

Adding a working payment method is the highest-value action, because a bound
backup is tried **immediately** on the next failure rather than waiting for the
retry interval.

## Can I change the retry policy myself in the Portal?

No. The retry strategy — per-cycle interval and maximum attempts — lives on your
acquiring agreement and is set by Waffo. There is no Portal screen and no API
that writes it, so it cannot be changed self-serve, and it is not a per-request
parameter either.

The same is true of the other schedule-shaping settings on the agreement: the
rebase-after-payment behaviour above, and whether pending retries are closed
when a subscription is cancelled. All three are account-level. When one of them
is changed, ask explicitly whether it applies to subscriptions that already
exist or only to new ones — the answer depends on which setting it is, and
assuming the wrong one is how reconciliation breaks.

## How do I test all of this without waiting for a real cycle?

Use the sandbox renewal simulator: activate a subscription, fetch its management
URL with `/api/v1/subscription/manage`, open it, and drive one period at a time
with the simulate-next-payment controls. Each click is one period, so you can
chain "period 2 succeeds, period 3 fails". Details and the reserved test amounts
are in
[Sandbox simulator](/docs/en/developer-docs/tools-and-references/developer-tools/sandbox-simulator)
and [Sandbox testing](/docs/en/support/sandbox-testing-faq).

What the sandbox does **not** let you do is fast-forward the real clock, so the
month-end behaviour above is best verified by reading `nextPaymentDateTime` after
each simulated period rather than by waiting — a subscription started on the
31st should show the 28th/29th for February and the 31st again for March.


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