# NoChurn documentation Source: https://www.nochurn.sh/docs/ NoChurn works on three kinds of churn: payments that fail, customers who want to cancel, and customers who already left. It reads your billing from Stripe (Stripe Connect), from a supported billing tool, or from your own code through the REST API, and acts in four flows: prevention, recovery, cancel and win-back. Everything starts in **test mode**: test keys (`nc_test_…`) never retry a real payment and no email leaves NoChurn. ## Start here - [Quickstart](/docs/quickstart/): a test key, a first API call, your billing, then the cancel flow. - [Concepts](/docs/concepts/): test and live mode, the three customer ids, events, idempotency and the four flows. - [API reference](/docs/api/): every public endpoint, with examples. ## Guides - [Your own billing (API)](/docs/billing-api/): send subscriptions and payment attempts when you do not bill with Stripe. - [Cancel modal](/docs/cancel-modal/): the signed customer token and the headless cancel flow, with click to cancel at every step. - [In-app banner and wall](/docs/in-app/) and [Access check](/docs/access/): what your app shows after a failed payment or during a pause, and the server-side check behind it. - [Custom data](/docs/custom-data/): your own attributes and usage events, for the churn score and the churn drivers. - [Webhooks](/docs/webhooks/): receive NoChurn's events and verify their signature. - [Chargebacks](/docs/chargebacks/): disputes, evidence and early fraud warnings. - [Test mode and sandbox](/docs/testing/): play a customer's life in test mode and run the integration checklist. - [AI apps and MCP](/docs/mcp/): let a coding agent integrate NoChurn for you, in test mode. ## Reference - [Errors](/docs/errors/): every error code, with when it happens and how to fix it. - [Webhook events](/docs/webhooks/events/): every event type, with an example payload. - [Integrations](/docs/integrations/): Stripe, billing platforms, merchants of record, payment providers, app stores and help desks. ## Base URL ```text https://api.nochurn.sh ``` Every endpoint is under `/v1`. Requests and responses are JSON; amounts are in cents. --- # Quickstart Source: https://www.nochurn.sh/docs/quickstart/ Everything on this page runs in **test mode**: no real payment is retried and no email leaves NoChurn. A human switches to live mode in the dashboard once the integration works. ## 1. Get a test key Create a free account at [app.nochurn.sh](https://app.nochurn.sh/signup), then open **Developers** and create a secret key. Test keys start with `nc_test_`. Keep the key on your server, for example in `NOCHURN_API_KEY`: never in front-end code, a mobile app or a committed file. | Secret | Where it lives | Used for | | --- | --- | --- | | `nc_test_…` / `nc_live_…` secret key | Your backend (`NOCHURN_API_KEY`) | Every server-side call: `Authorization: Bearer ` | | `pk_test_…` / `pk_live_…` publishable key | Your front end or app (public) | The cancel flow and the in-app screens, with a signed customer token | | `ncws_…` widget signing secret | Your backend (`NOCHURN_WIDGET_SECRET`) | Signing customer tokens | | `whsec_…` webhook secret | Your backend (`NOCHURN_WEBHOOK_SECRET`) | Verifying `NoChurn-Signature` on webhooks | ## 2. Make a first call `GET /v1/account` returns the account of the key. A test key only ever sees test data. ```bash curl https://api.nochurn.sh/v1/account \ -H "Authorization: Bearer $NOCHURN_API_KEY" ``` ```js const response = await fetch("https://api.nochurn.sh/v1/account", { headers: { Authorization: `Bearer ${process.env.NOCHURN_API_KEY}` }, }); console.log(await response.json()); ``` ```python response = requests.get("https://api.nochurn.sh/v1/account", headers={"Authorization": f"Bearer {os.environ['NOCHURN_API_KEY']}"}, timeout=10) print(response.json()) ``` ```ruby require "net/http" require "json" uri = URI("https://api.nochurn.sh/v1/account") request = Net::HTTP::Get.new(uri) request["Authorization"] = "Bearer #{ENV.fetch('NOCHURN_API_KEY')}" response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) } puts JSON.parse(response.body) ``` A wrong or missing key answers `401` with an error body: `{ "error": { "code", "message", "fix", "docs_url" } }`. Every error has this shape, see [Errors](/docs/errors/). ## 3. Connect your billing **With Stripe.** In the dashboard, open **Integrations** and click **Connect Stripe** (Stripe Connect, test mode first). NoChurn imports customers, subscriptions, invoices and payment methods, then follows Stripe's events. It never sees card numbers. Details: [Stripe](/docs/integrations/stripe/). **With another billing tool.** Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, the App Store and Google Play connect from **Integrations** with their API credentials: see [Integrations](/docs/integrations/). **With your own billing code.** Send subscriptions and every payment attempt to the API. A failed payment opens the recovery flow; NoChurn then asks your backend to retry through the `billing.retry_requested` webhook. Amounts are in cents. ```bash curl -X POST https://api.nochurn.sh/v1/subscriptions -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"external_id":"sub_123","customer":{"external_id":"user_123","email":"jane@example.com"},"plan":"Pro","amount":4900,"currency":"usd","interval":"month","status":"active","current_period_end":"2026-12-05T00:00:00Z"}' curl -X POST https://api.nochurn.sh/v1/payments -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"external_id":"pay_123","customer":"user_123","subscription":"sub_123","invoice":"inv_123","amount":4900,"currency":"usd","status":"failed","decline_code":"insufficient_funds","invoice_url":"https://app.example.com/billing"}' ``` ```js const NOCHURN_API_URL = process.env.NOCHURN_API_URL || "https://api.nochurn.sh"; async function post(path, body) { const response = await fetch(`${NOCHURN_API_URL}${path}`, { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCHURN_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify(body), }); const data = await response.json().catch(() => null); if (!response.ok) throw new Error(`NoChurn: ${data?.error?.message} ${data?.error?.fix ?? ""}`); return data; } await post("/v1/subscriptions", { external_id: "sub_123", customer: { external_id: "user_123", email: "jane@example.com" }, plan: "Pro", amount: 4900, currency: "usd", interval: "month", status: "active", current_period_end: "2026-12-05T00:00:00Z", }); await post("/v1/payments", { external_id: "pay_123", customer: "user_123", subscription: "sub_123", invoice: "inv_123", amount: 4900, currency: "usd", status: "failed", decline_code: "insufficient_funds", invoice_url: "https://app.example.com/billing", }); ``` ```python NOCHURN_API_URL = os.environ.get("NOCHURN_API_URL", "https://api.nochurn.sh") def post(path, body): response = requests.post(f"{NOCHURN_API_URL}{path}", json=body, timeout=10, headers={"Authorization": f"Bearer {os.environ['NOCHURN_API_KEY']}"}) if response.status_code >= 300: error = response.json().get("error", {}) raise RuntimeError(f"NoChurn: {error.get('message')} {error.get('fix', '')}") return response.json() post("/v1/subscriptions", {"external_id": "sub_123", "customer": {"external_id": "user_123", "email": "jane@example.com"}, "plan": "Pro", "amount": 4900, "currency": "usd", "interval": "month", "status": "active", "current_period_end": "2026-12-05T00:00:00Z"}) post("/v1/payments", {"external_id": "pay_123", "customer": "user_123", "subscription": "sub_123", "invoice": "inv_123", "amount": 4900, "currency": "usd", "status": "failed", "decline_code": "insufficient_funds", "invoice_url": "https://app.example.com/billing"}) ``` ```ruby require "net/http" require "json" def nochurn_post(path, body) uri = URI("#{ENV.fetch('NOCHURN_API_URL', 'https://api.nochurn.sh')}#{path}") request = Net::HTTP::Post.new(uri) request["Authorization"] = "Bearer #{ENV.fetch('NOCHURN_API_KEY')}" request["Content-Type"] = "application/json" request.body = JSON.generate(body) response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) } data = JSON.parse(response.body) rescue nil raise "NoChurn: #{data&.dig('error', 'message')} #{data&.dig('error', 'fix')}" if response.code.to_i >= 300 data end nochurn_post("/v1/subscriptions", { external_id: "sub_123", customer: { external_id: "user_123", email: "jane@example.com" }, plan: "Pro", amount: 4900, currency: "usd", interval: "month", status: "active", current_period_end: "2026-12-05T00:00:00Z" }) nochurn_post("/v1/payments", { external_id: "pay_123", customer: "user_123", subscription: "sub_123", invoice: "inv_123", amount: 4900, currency: "usd", status: "failed", decline_code: "insufficient_funds", invoice_url: "https://app.example.com/billing" }) ``` `invoice_url` is the page of your app where the customer updates their card: the recovery emails link to it. The full guide: [Your own billing (API)](/docs/billing-api/). ## 4. Identify your customers Whatever the billing, send your own user id (`external_id`) and a few attributes from your backend, at signup and whenever they change. `POST /v1/customers` answers `409` when the customer already exists: then update it. The two base attributes the integration checklist looks for are `signup_source` and `onboarding_done`. ```bash curl -X POST https://api.nochurn.sh/v1/customers -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"external_id":"user_123","email":"jane@example.com","name":"Jane Doe"}' curl -X POST https://api.nochurn.sh/v1/customers/user_123/attributes -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"attributes":{"signup_source":"ads","onboarding_done":true}}' ``` With Stripe, also put that id in the Stripe customer's `metadata.user_id` (the key is configurable): NoChurn then links the Stripe customer to the one your app identified instead of creating a duplicate. More in [Custom data](/docs/custom-data/) and [Concepts](/docs/concepts/#three-customer-ids). ## 5. Receive webhooks Add a route to your backend, register it (`POST /v1/webhook_endpoints`, or Developers › Webhooks in the dashboard), store the `whsec_…` secret it returns once, and verify `NoChurn-Signature` on every delivery. The code, in Node, Python and Ruby: [Webhooks](/docs/webhooks/). ## 6. Open the cancel flow Publish the cancel flow in test mode from the dashboard (**Cancel flow**), then open it from your cancel button. Your server signs a short customer token; your front end opens a cancel session with the publishable key and that token, shows each step, and keeps a **Cancel now** button visible at every step. The steps, the token code and the headless calls: [Cancel modal](/docs/cancel-modal/). ## 7. Check the integration `GET /v1/integration/verify` runs a 7-point checklist (billing connected, webhook verified, identify received, cancel flow opened, click to cancel, failed-payment email, no secret in code). Each point is `pass`, `fail` with its `fix`, or `unknown`. The [sandbox scenarios](/docs/testing/) play a failed payment, a removed card or a cancel flow for you. When everything passes, a human goes live in the dashboard. > Prefer to let your coding agent do it? Connect the [NoChurn MCP server](/docs/mcp/): it works in test mode and uses the same tested code. --- # Concepts Source: https://www.nochurn.sh/docs/concepts/ ## Test and live mode Every account has two separate sets of data: **test** and **live**. A secret key belongs to one of them: `nc_test_…` only sees test data, `nc_live_…` only live data. Customers, subscriptions, flows, webhook endpoints and custom attributes are all kept per mode, and every object carries `livemode`. In test mode NoChurn uses your billing tool's test data (Stripe test mode, a sandbox site) and never emails a real inbox. Live keys are created by a person in the dashboard; AI apps work in test mode and need a human for anything live (see [AI apps and MCP](/docs/mcp/)). ## Authentication | Caller | Header | Sees | | --- | --- | --- | | Your backend | `Authorization: Bearer nc_test_…` | Everything the key allows (a key is `full`, or `restricted` with none / read / write per resource) | | Your front end or app | `Authorization: Bearer pk_test_…` plus `X-NoChurn-Customer-Token` | One customer's cancel flow and in-app screens, from an allowed origin | | An AI app | `Authorization: Bearer ncat_…` (OAuth) | Test mode by default; see [MCP](/docs/mcp/) | Publishable keys (`pk_…`) are refused on the secret-key endpoints, and secret keys on the few endpoints that only take a publishable key. ## Three customer ids Each customer has a NoChurn id (`cst_…`, always), a Stripe id (`cus_…`, when Stripe is connected) and your own user id (`external_id`, when you send it). Responses and webhooks carry the three, `null` when absent. Wherever the API takes a customer (`/v1/customers/{id}`, `customer` in payments, usage events, cancel sessions…) you can pass any of them. `cst_` is read as a NoChurn id, `cus_` as a Stripe id when it exists on a connected Stripe account, anything else as your `external_id`. An unknown value answers `404` [`customer_not_found`](/docs/errors/#customer_not_found); a value that matches two customers answers `409` [`ambiguous_customer`](/docs/errors/#ambiguous_customer): use the explicit parameter then. `GET /v1/customers/resolve` tells which customer a value names. Always create customers with your user id. With Stripe, also put it in the Stripe customer's `metadata.user_id` (the key is configurable): NoChurn then links the two instead of creating a duplicate. NoChurn never merges two customers on its own: a possible duplicate is proposed, and a person merges it or dismisses it. ## Other ids Every NoChurn id has a prefix, never shared with Stripe's (`cus_`, `sub_`, `in_`, `pm_`, `evt_`): `cst_` customer, `nsub_` subscription, `ninv_` invoice, `npm_` payment method, `npay_` payment attempt, `nevt_` event, `key_` API key, `acc_` account. ## Events Every decision NoChurn takes (a retry scheduled, an email held, an offer accepted, a customer flagged) is written as an event with its reason. `GET /v1/events` lists them, newest first. The same events reach your systems as [webhooks](/docs/webhooks/), each with its `nevt_…` id: see the [event types](/docs/webhooks/events/). ## Idempotency - **What you send.** Payments are idempotent on their `external_id` (your payment id): sending the same attempt twice records it once. Usage events take an `idempotency_key` and are deduplicated on it. - **What NoChurn sends.** Webhook deliveries are retried and can be replayed: the event `id` stays the same, so deduplicate on it. The `billing.*_requested` webhooks carry an `idempotency_key` for the action your billing runs. - **What NoChurn does in your billing tool.** Each action on Stripe carries an `Idempotency-Key`, so a retried job never charges or cancels twice. ## Pagination Lists return `{ "object": "list", "data": [...], "has_more": true, "next_cursor": "…" }`, newest first. Pass `?limit=` (1 to 100, default 20) and `?starting_after=` for the next page. ## Errors Every error is `{ "error": { "code", "message", "fix", "docs_url" } }` with a meaningful HTTP status. The `fix` says what to do; `docs_url` points to the code's section in [Errors](/docs/errors/). ## The four flows | Flow | id | What it does | | --- | --- | --- | | Prevention | `prevention` | Acts on early signals, for example a card removed before the renewal | | Recovery | `recovery` | A failed payment: retries, recovery emails with a card update link, in-app banner and wall | | Cancel | `cancel` | The cancel flow: reasons, offers (discount, pause, downgrade, talk to us) and click to cancel at every step | | Win-back | `winback` | Emails to customers who left | Each flow has a draft and published versions per mode: `GET /v1/flows/{id}` returns the draft, `PATCH` edits it and `POST /v1/flows/{id}/publish` publishes it to test or live. A flow can be paused, and its emails previewed before anything is sent. ## Click to cancel A customer who asks to cancel can always do it: the cancel flow shows **Cancel now** at every step, and a requested cancellation is always carried out (in Stripe by NoChurn, or in your billing through `billing.cancel_requested`). Offers come before the cancellation, never instead of it. --- # Your own billing (API) Source: https://www.nochurn.sh/docs/billing-api/ Choose billing by API when your app does not bill with Stripe or one of the [supported tools](/docs/integrations/): another processor, or billing you built yourself. NoChurn never charges a card it does not hold. Your backend tells NoChurn what happens; NoChurn decides and asks your backend to act. Set the account's billing source once: `PATCH /v1/account { "billing_source": "api" }` (or pick "API" at onboarding). ## What your backend sends **Subscriptions.** `POST /v1/subscriptions` when a subscription is created or changes: | Field | | | --- | --- | | `external_id` | Your subscription id | | `customer` | Your user id, or `{ external_id, email }` to create the customer at the same time | | `plan` | Plan name | | `amount`, `currency` | Price per interval, in cents | | `interval` | `month` or `year` | | `status` | The subscription status | | `current_period_end` | Next renewal, ISO 8601 | Later changes go to `PATCH /v1/subscriptions/{id}`. **Payment attempts.** `POST /v1/payments` for every attempt, failed or succeeded: | Field | | | --- | --- | | `external_id` | Your payment id. Idempotent: the same id is recorded once | | `customer`, `subscription` | Your ids | | `invoice` | Your invoice id: groups the attempts of one bill | | `amount`, `currency` | In cents | | `status` | `failed` or `succeeded` | | `decline_code` | The processor's decline code, e.g. `insufficient_funds` | | `invoice_url` | The page of your app where the customer updates their card. The recovery emails link to it | A failed payment opens the recovery flow. A succeeded one on the same invoice closes it as recovered. ```bash curl -X POST https://api.nochurn.sh/v1/subscriptions -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"external_id":"sub_123","customer":{"external_id":"user_123","email":"jane@example.com"},"plan":"Pro","amount":4900,"currency":"usd","interval":"month","status":"active","current_period_end":"2026-12-05T00:00:00Z"}' curl -X POST https://api.nochurn.sh/v1/payments -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"external_id":"pay_123","customer":"user_123","subscription":"sub_123","invoice":"inv_123","amount":4900,"currency":"usd","status":"failed","decline_code":"insufficient_funds","invoice_url":"https://app.example.com/billing"}' ``` ```js // Node 18+, server side only. Env: NOCHURN_API_KEY, NOCHURN_API_URL (optional). Amounts in cents. const NOCHURN_API_URL = process.env.NOCHURN_API_URL || "https://api.nochurn.sh"; async function post(path, body) { const response = await fetch(`${NOCHURN_API_URL}${path}`, { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCHURN_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify(body), }); const data = await response.json().catch(() => null); if (!response.ok) throw new Error(`NoChurn: ${data?.error?.message} ${data?.error?.fix ?? ""}`); return data; } // sub: { id, userId, email, plan, amountCents, currency, interval: "month" | "year", status, currentPeriodEnd: Date } return post("/v1/subscriptions", { external_id: String(sub.id), customer: { external_id: String(sub.userId), email: sub.email }, plan: sub.plan, amount: sub.amountCents, currency: sub.currency, interval: sub.interval, status: sub.status, current_period_end: sub.currentPeriodEnd.toISOString(), }); } // payment: { id, userId, subscriptionId, invoiceId, amountCents, currency, status: "failed" | "succeeded", declineCode?, invoiceUrl } return post("/v1/payments", { external_id: String(payment.id), customer: String(payment.userId), subscription: String(payment.subscriptionId), invoice: String(payment.invoiceId), amount: payment.amountCents, currency: payment.currency, status: payment.status, decline_code: payment.declineCode, invoice_url: payment.invoiceUrl, }); } ``` ```python # Python, requests, server side only. Amounts in cents. NOCHURN_API_URL = os.environ.get("NOCHURN_API_URL", "https://api.nochurn.sh") def _post(path, body): response = requests.post(f"{NOCHURN_API_URL}{path}", json={k: v for k, v in body.items() if v is not None}, timeout=10, headers={"Authorization": f"Bearer {os.environ['NOCHURN_API_KEY']}", "Content-Type": "application/json"}) if response.status_code >= 300: error = response.json().get("error", {}) raise RuntimeError(f"NoChurn: {error.get('message')} {error.get('fix', '')}") return response.json() def record_subscription(sub): return _post("/v1/subscriptions", { "external_id": str(sub["id"]), "customer": {"external_id": str(sub["user_id"]), "email": sub.get("email")}, "plan": sub["plan"], "amount": sub["amount_cents"], "currency": sub["currency"], "interval": sub["interval"], "status": sub["status"], "current_period_end": sub["current_period_end"].isoformat(), }) def record_payment(payment): return _post("/v1/payments", { "external_id": str(payment["id"]), "customer": str(payment["user_id"]), "subscription": str(payment["subscription_id"]), "invoice": str(payment["invoice_id"]), "amount": payment["amount_cents"], "currency": payment["currency"], "status": payment["status"], "decline_code": payment.get("decline_code"), "invoice_url": payment.get("invoice_url"), }) ``` ```ruby # Ruby, Net::HTTP, server side only. Amounts in cents. require "net/http" require "json" require "uri" require "time" def nochurn_post(path, body) uri = URI("#{ENV.fetch('NOCHURN_API_URL', 'https://api.nochurn.sh')}#{path}") request = Net::HTTP::Post.new(uri) request["Authorization"] = "Bearer #{ENV.fetch('NOCHURN_API_KEY')}" request["Content-Type"] = "application/json" request.body = JSON.generate(body.compact) response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) } data = JSON.parse(response.body) rescue nil raise "NoChurn: #{data&.dig('error', 'message')} #{data&.dig('error', 'fix')}" if response.code.to_i >= 300 data end def record_subscription(sub) nochurn_post("/v1/subscriptions", { external_id: sub[:id].to_s, customer: { external_id: sub[:user_id].to_s, email: sub[:email] }, plan: sub[:plan], amount: sub[:amount_cents], currency: sub[:currency], interval: sub[:interval], status: sub[:status], current_period_end: sub[:current_period_end].utc.iso8601 }) end def record_payment(payment) nochurn_post("/v1/payments", { external_id: payment[:id].to_s, customer: payment[:user_id].to_s, subscription: payment[:subscription_id].to_s, invoice: payment[:invoice_id].to_s, amount: payment[:amount_cents], currency: payment[:currency], status: payment[:status], decline_code: payment[:decline_code], invoice_url: payment[:invoice_url] }) end ``` ## What NoChurn asks your backend to do NoChurn sends [webhooks](/docs/webhooks/) your backend applies. Each one carries an `idempotency_key`: pass it on, so the action happens once even when the webhook is delivered twice. | Event | Your backend | | --- | --- | | `billing.retry_requested` | Attempts the payment of the invoice now, then reports the result with `POST /v1/payments` | | `billing.cancel_requested` | Cancels the subscription. `reason` is `customer_cancelled` (`at_period_end` says when) or `recovery_lost` (cancel at the end of the period) | | `billing.discount_requested` | Applies the accepted discount offer to the subscription | | `billing.pause_requested` | Pauses the subscription | | `billing.downgrade_requested` | Moves the subscription to the offered plan | Payloads: [Webhook events › Billing by API](/docs/webhooks/events/#billing). A cancellation the customer asked for must always be carried out (click to cancel). ## Check it in test mode With a test key, `POST /v1/sandbox/customers` creates a customer billed by API, and `POST /v1/sandbox/failed_payment` plays a failed payment: see [Test mode and sandbox](/docs/testing/). --- # Cancel modal Source: https://www.nochurn.sh/docs/cancel-modal/ The cancel flow asks why the customer is leaving, shows the offer you attached to that reason (discount, pause, downgrade or talk to us), and cancels in one click if they still want to. **Cancel now** is visible at every step, and a requested cancellation is always carried out. ## Configure the flow In the dashboard, **Cancel flow** edits the reasons, offers, texts per language, feedback question and design, as a draft. Publish it to test mode first. The same is available through the API: `GET /v1/flows/cancel` returns the draft, `PATCH /v1/flows/cancel` edits it and `POST /v1/flows/cancel/publish` with `{ "to": "test" }` publishes it. Offers live in a library (`/v1/offers`) and are attached to reasons. ## The customer token The browser never names a customer itself: your server signs a short token for the logged-in user, and the browser sends it with the publishable key. - **Format:** JWT HS256, signed with the widget signing secret (`ncws_…`, created in Developers or with `POST /v1/account/widget_secret`, shown once; rotating it invalidates the tokens signed with the old one). - **Claims:** `kind: "external"`, `value` (your user id), `exp` (24 hours at most), and `subscription`: the subscription the cancel button is about (`sub_…`, `nsub_…` or its id in your billing). Always send `subscription` when a customer can have several. - **Where:** an authenticated endpoint of your backend that your front end calls before opening the flow. Never ship the secret to the browser or the app. ```js // Node, server side. Env: NOCHURN_WIDGET_SECRET (ncws_…). const base64url = (input) => Buffer.from(input).toString("base64url"); const claims = { kind: "external", value: String(userId), exp: Math.floor(Date.now() / 1000) + ttlSeconds }; if (subscription) claims.subscription = String(subscription); const header = base64url(JSON.stringify({ alg: "HS256", typ: "JWT" })); const payload = base64url(JSON.stringify(claims)); const signature = createHmac("sha256", secret).update(`${header}.${payload}`).digest("base64url"); return `${header}.${payload}.${signature}`; } ``` ```python # Python, server side. Env: NOCHURN_WIDGET_SECRET (ncws_...). def _b64url(data): return base64.urlsafe_b64encode(data).rstrip(b"=").decode() def sign_customer_token(user_id, secret=None, ttl=3600, subscription=None): secret = secret or os.environ["NOCHURN_WIDGET_SECRET"] claims = {"kind": "external", "value": str(user_id), "exp": int(time.time()) + ttl} if subscription: claims["subscription"] = str(subscription) header = _b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()) payload = _b64url(json.dumps(claims).encode()) signature = hmac.new(secret.encode(), f"{header}.{payload}".encode(), hashlib.sha256).digest() return f"{header}.{payload}.{_b64url(signature)}" ``` ```ruby # Ruby, server side. Env: NOCHURN_WIDGET_SECRET (ncws_…). require "openssl" require "base64" require "json" def sign_customer_token(user_id, secret = ENV.fetch("NOCHURN_WIDGET_SECRET"), ttl: 3600, subscription: nil) encode = ->(data) { Base64.urlsafe_encode64(data, padding: false) } claims = { kind: "external", value: user_id.to_s, exp: Time.now.to_i + ttl } claims[:subscription] = subscription.to_s if subscription header = encode.call(JSON.generate({ alg: "HS256", typ: "JWT" })) payload = encode.call(JSON.generate(claims)) "#{header}.#{payload}.#{encode.call(OpenSSL::HMAC.digest('SHA256', secret, "#{header}.#{payload}"))}" end ``` The publishable key (`pk_test_…`) only works from the origins you allow on it (Developers, or Cancel flow › Install). ## Headless: your UI, NoChurn's logic Build the screens yourself (web, desktop or a native app) and let NoChurn decide what to show and what to do. 1. Open a session: `POST /v1/cancel_sessions { locale }` with `Authorization: Bearer pk_test_…` and `X-NoChurn-Customer-Token: `. The session carries its `step`, the texts, the reasons and the offer. 2. Render the step and send each answer to `POST /v1/cancel_sessions/{id}/answer` (table below). 3. **Click to cancel.** Show a visible **Cancel now** button at every step, wired to `POST /v1/cancel_sessions/{id}/cancel`. At `choose_subscription`, ask which one first and send `{ subscription }` (one "Cancel this one" button per subscription): NoChurn never guesses and never cancels them all, and answers `422` [`subscription_required`](/docs/errors/#subscription_required) without it. | Step | Answer | | --- | --- | | `choose_subscription` | `{ subscription }`: only when the customer has several live subscriptions and the token names none; list `subscriptions` and let them pick | | `reason` | `{ reason, comment? }` | | `offer` | `{ accept_offer: true }` or `{ accept_offer: false }` | | `feedback` | `{ feedback }` | | `confirm` | `POST /v1/cancel_sessions/{id}/cancel` (step 3) | ```js // Browser. publishableKey: pk_test_… (your origin allowed on it); customerToken: signed by YOUR server. const NOCHURN_API_URL = "https://api.nochurn.sh"; function nochurnHeaders(publishableKey, customerToken) { return { Authorization: `Bearer ${publishableKey}`, "X-NoChurn-Customer-Token": customerToken, "Content-Type": "application/json" }; } async function call(path, publishableKey, customerToken, body) { const response = await fetch(`${NOCHURN_API_URL}${path}`, { method: "POST", headers: nochurnHeaders(publishableKey, customerToken), body: JSON.stringify(body ?? {}), }); const data = await response.json(); if (!response.ok) throw new Error(`NoChurn: ${data.error?.message} ${data.error?.fix ?? ""}`); return data; } // Opens a session: its step (choose_subscription, reason, offer, feedback, confirm), subscriptions, reasons and offer. return call("/v1/cancel_sessions", publishableKey, customerToken, { locale }); } // answer: { subscription } | { reason, comment? } | { accept_offer: true | false } | { feedback } return call(`/v1/cancel_sessions/${sessionId}/answer`, publishableKey, customerToken, answer); } // subscription: required at choose_subscription only (the one the customer pressed "Cancel this one" on). return call(`/v1/cancel_sessions/${sessionId}/cancel`, publishableKey, customerToken, subscription ? { subscription } : {}); } ``` From a server, the same session opens with the secret key and `{ customer, subscription }`. `GET /v1/cancel_sessions/{id}` reads a session again after an error. What happens on a cancellation: with Stripe or a billing tool that can cancel through its API, NoChurn cancels the subscription; with [billing by API](/docs/billing-api/), your backend receives `billing.cancel_requested` and applies it. Either way the `cancel_session.completed` webhook tells you the outcome. ## The NoChurn modal NoChurn's own modal is served by the browser script `js.nochurn.sh/v1`, with the publishable key and the same customer token. Its design comes from the flow (`GET /v1/cancel_flows/{id}/theme`: a preset, tokens such as colours, font, radius and spacing, the logo, a format `modal`, `panel` or `page`, and optional custom CSS). Custom CSS can never hide the cancel button: the script checks it at render and puts it back. The script's reference (install tag, functions, options) will be on its own page; until then, use the headless flow above. ## Fallback link If the modal cannot open, the cancellation still goes through: a stable URL per publishable key, `https://cancel.nochurn.sh/k/`, receives the signed token **by POST** (an HTML form with a `token` field, `locale` optional), opens a hosted session and redirects to a page with one button that cancels. The token never appears in a URL. The URL is returned as `cancel_fallback_url` by `GET /v1/cancel_flows/{id}` with a publishable key. ## Native apps `GET /v1/cancel_flows/default/theme` gives native apps the same design tokens. Subscriptions sold through the App Store or Google Play are managed by Apple and Google: send those customers to the store's subscription settings. --- # In-app banner and wall Source: https://www.nochurn.sh/docs/in-app/ After a failed payment, NoChurn can tell the customer inside your app, not only by email: first a **banner** with a link to pay, then, once the grace period is over, a **wall** that blocks the app until the invoice is paid. A paused plan can show a banner or a wall too, with a **Resume now** button. > The wall is a convenience, not a lock: a script blocker gets around it. If access must stop, also check it on your server with [`GET /v1/customers/{id}/access`](/docs/access/). ## Settings - **Failed payment:** Recovery flow › In-app in the dashboard (`inapp` in the recovery flow's draft). `wall.enabled`, `wall.after_days` (0 to 60, 0 = as soon as the payment fails), `annual_grace_days` (0 to 90, for annual plans), `banner.dismiss_hours` (1 to 168), and the texts per language. - **Pause:** Cancel flow › Offers › Pause: `pause.inapp` is `none` (default), `banner` or `wall`. A customer counts as paused when all their live subscriptions are paused. The banner and the wall use the design of the published cancel flow, and texts in English, French, German, Italian and Portuguese that you can override. ## Read the state: GET /v1/inapp/state From the browser: the publishable key (`pk_test_…`), the signed customer token in `X-NoChurn-Customer-Token` (same token as the [cancel flow](/docs/cancel-modal/#the-customer-token)) and an allowed origin. From a server: a secret key and `?customer=`. Optional `?locale=`. The answer says what to show, and nothing is cached: call it again after a payment and it answers `access: "full"`. | Field | | | --- | --- | | `access`, `access_reason` | `full` or `restricted`; `payment_failed` or `paused` | | `banner` | Whether to show it, its `kind`, its texts, `restricts_at` and `days_left` before the wall (when the wall is on), `details` | | `wall` | Whether to show it, its `kind`, its texts and link, `details` | | `texts`, `theme`, `locale` | The texts in the customer's language and the cancel flow's design; `null` when nothing is shown | `details` for a failed payment: the amount due, its currency, the invoice due date, the brand, last 4 digits and expiry of the card, and a simple decline category (`expired`, `insufficient_funds`, `authentication_required` or `declined`), never the processor's message. For a pause: `paused_at`, `resumes_at`, the regular amount and `resume_allowed`. The wall always carries a way to cancel (`cancel`, with a fallback link): cancelling is never blocked. ## Actions from the customer - `POST /v1/inapp/dismiss` hides the banner for `dismiss_hours`. The wall cannot be dismissed. - `POST /v1/inapp/resume` resumes the paused subscription at the billing provider and returns the new state (access full at once). The token's `subscription` claim names the subscription when there are several; without it and with several paused, the answer is `422` [`subscription_required`](/docs/errors/#subscription_required). Nothing paused (a second click included) answers `409` [`nothing_to_resume`](/docs/errors/#nothing_to_resume). With billing by API, resuming is up to your app ([`capability_missing`](/docs/errors/#capability_missing)). Both are rate limited per key and customer, and per IP ([`rate_limited`](/docs/errors/#rate_limited)). ## Rendering it NoChurn's browser script (`js.nochurn.sh/v1`) shows the banner and the wall from this state. You can also draw them yourself, on the web or in a native app, from the same fields. --- # Access check Source: https://www.nochurn.sh/docs/access/ The [in-app wall](/docs/in-app/) is a convenience: a script blocker or a direct call to your API gets around it. If access to your app must stop after a failed payment, check it **on your server** too. NoChurn uses one calculation for the wall, this endpoint and the webhooks, so they always agree. ## When a customer is restricted - **Failed payment.** The recovery flow is published and running in the mode, its in-app wall is on, and an invoice is still unpaid after the grace period: `wall.after_days` (0 to 60) after the failure, or `annual_grace_days` (0 to 90) for an annual plan. `0` restricts as soon as the payment fails. - **Paused plan.** The cancel flow's pause setting shows a wall (`pause.inapp: "wall"`, off by default) and every live subscription of the customer is paused. A customer held out of the flow, a customer whose flows are paused, a paused flow or a wall turned off: access stays full. ## Check it on your server Secret key, read access to customers. `{id}` is any of the customer's ids (`cst_…`, `cus_…` or your user id). ```json { "object": "customer_access", "customer": "cst_4w9Nj8EJEvWj7MDT", "livemode": false, "access": "restricted", "reason": "payment_failed", "since": "2026-11-11T10:00:00Z", "failing_since": "2026-11-04T10:00:00Z", "restricts_at": null, "invoice": "ninv_1dMMAnaZyLmBNtDB", "pay_url": "https://…", "cancel_url": "https://cancel.nochurn.sh/a/…", "subscription": null, "paused_at": null, "resumes_at": null } ``` - `access`: `full` or `restricted`; `reason`: `null`, `payment_failed` or `paused`. - `since`: when the restriction started; `restricts_at`: when it will start if nothing is paid (`null` once restricted, or without a wall). - `pay_url`: the same payment link as the recovery emails. `cancel_url`: a signed page with one **Cancel** button, valid 30 days. A blocking page must offer both: paying **and** cancelling (click to cancel). - Pause: `subscription`, `paused_at` and `resumes_at`. Block your app's pages and API when `access` is `restricted`, never the pages to pay or cancel. If NoChurn cannot be reached, let the customer in (fail open): a paying customer is never locked out by an outage. ```bash curl https://api.nochurn.sh/v1/customers/user_123/access -H "Authorization: Bearer $NOCHURN_API_KEY" ``` ```js // Node 18+, server side only. Fails open: if NoChurn cannot be reached, the customer keeps access. const NOCHURN_API_URL = process.env.NOCHURN_API_URL || "https://api.nochurn.sh"; try { const response = await fetch(`${NOCHURN_API_URL}/v1/customers/${encodeURIComponent(String(userId))}/access`, { headers: { Authorization: `Bearer ${process.env.NOCHURN_API_KEY}` }, signal: AbortSignal.timeout(3000), }); if (!response.ok) return { access: "full", reason: null, error: response.status }; return await response.json(); } catch (error) { return { access: "full", reason: null, error: String(error) }; } } // Express: block the app, never the pages to pay or cancel. // app.use("/app", async (req, res, next) => { // const result = await checkAccess(req.user.id); // if (result.access !== "restricted") return next(); // res.status(402).json({ reason: result.reason, pay_url: result.pay_url, cancel_url: result.cancel_url }); // }); ``` ```python # Python, requests, server side only. Fails open. from urllib.parse import quote NOCHURN_API_URL = os.environ.get("NOCHURN_API_URL", "https://api.nochurn.sh") def check_access(user_id): try: response = requests.get(f"{NOCHURN_API_URL}/v1/customers/{quote(str(user_id), safe='')}/access", headers={"Authorization": f"Bearer {os.environ['NOCHURN_API_KEY']}"}, timeout=3) except Exception as error: # network error, timeout return {"access": "full", "reason": None, "error": str(error)} if response.status_code >= 300: return {"access": "full", "reason": None, "error": response.status_code} return response.json() ``` ```ruby # Ruby, Net::HTTP, server side only. Fails open. require "net/http" require "json" require "uri" require "erb" def check_access(user_id) uri = URI("#{ENV.fetch('NOCHURN_API_URL', 'https://api.nochurn.sh')}/v1/customers/#{ERB::Util.url_encode(user_id.to_s)}/access") request = Net::HTTP::Get.new(uri) request["Authorization"] = "Bearer #{ENV.fetch('NOCHURN_API_KEY')}" response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https", open_timeout: 3, read_timeout: 3) { |http| http.request(request) } return { "access" => "full", "reason" => nil, "error" => response.code.to_i } unless response.is_a?(Net::HTTPSuccess) JSON.parse(response.body) rescue StandardError => e # network error, timeout { "access" => "full", "reason" => nil, "error" => e.message } end ``` ## Cache it with the webhooks Rather than calling the API on every request, listen to two [webhooks](/docs/webhooks/) and keep the state on your side: - [`customer.access_restricted`](/docs/webhooks/events/#customer-access_restricted): once, when the grace period ends (or the plan is paused with the wall on). It carries `customer`, `access`, `access_reason`, `invoice`, `since`, `failing_since`, `grace_days` and a readable `reason`. - [`customer.access_restored`](/docs/webhooks/events/#customer-access_restored): when the invoice is paid, voided or marked uncollectible, recovery stops, the settings change or the plan resumes, with `restored_because`. Each transition is sent once. NoChurn re-checks customers with an unpaid invoice under recovery every 10 minutes, and right after a payment. When in doubt, `GET /v1/customers/{id}/access` is the truth at any time. --- # Custom data Source: https://www.nochurn.sh/docs/custom-data/ Your billing knows what customers pay. Your app knows how they got there and whether they use it. Send that to NoChurn as **attributes** (facts about a customer) and **usage events** (what they do). They feed the churn score, the churn drivers of Data & AI, segments and offers. ## Attributes `POST /v1/customers/{id}/attributes` merges attributes into a customer (`{id}` is any of its ids). You can also pass `attributes` when you create or update a customer. ```bash curl -X POST https://api.nochurn.sh/v1/customers/user_123/attributes \ -H "Authorization: Bearer $NOCHURN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"attributes":{"signup_source":"ads","onboarding_done":true,"seats":3,"activated_at":"2026-03-16"}}' ``` ```js // user: { id, email, name }; attributes: e.g. { signup_source: "ads", onboarding_done: true }. // Creates the customer (409 if it already exists: then updates it), then sends the attributes. const NOCHURN_API_URL = process.env.NOCHURN_API_URL || "https://api.nochurn.sh"; async function nochurn(method, path, body) { const response = await fetch(`${NOCHURN_API_URL}${path}`, { method, headers: { Authorization: `Bearer ${process.env.NOCHURN_API_KEY}`, "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), }); const data = await response.json().catch(() => null); return { status: response.status, ok: response.ok, data }; } const id = encodeURIComponent(String(user.id)); const created = await nochurn("POST", "/v1/customers", { external_id: String(user.id), email: user.email, name: user.name }); if (created.status === 409) { await nochurn("PATCH", `/v1/customers/${id}`, { email: user.email, name: user.name }); } else if (!created.ok) { throw new Error(`NoChurn: ${created.data?.error?.message} ${created.data?.error?.fix ?? ""}`); } const result = await nochurn("POST", `/v1/customers/${id}/attributes`, { attributes }); if (!result.ok) throw new Error(`NoChurn: ${result.data?.error?.message} ${result.data?.error?.fix ?? ""}`); return result.data; } ``` ```python from urllib.parse import quote NOCHURN_API_URL = os.environ.get("NOCHURN_API_URL", "https://api.nochurn.sh") def _headers(): return {"Authorization": f"Bearer {os.environ['NOCHURN_API_KEY']}", "Content-Type": "application/json"} def _raise_for(response): if response.status_code >= 300: error = (response.json() or {}).get("error", {}) raise RuntimeError(f"NoChurn: {error.get('message')} {error.get('fix', '')}") def identify_customer(user, attributes): customer_id = quote(str(user["id"]), safe="") created = requests.post(f"{NOCHURN_API_URL}/v1/customers", headers=_headers(), timeout=10, json={"external_id": str(user["id"]), "email": user.get("email"), "name": user.get("name")}) if created.status_code == 409: requests.patch(f"{NOCHURN_API_URL}/v1/customers/{customer_id}", headers=_headers(), timeout=10, json={"email": user.get("email"), "name": user.get("name")}) else: _raise_for(created) response = requests.post(f"{NOCHURN_API_URL}/v1/customers/{customer_id}/attributes", headers=_headers(), timeout=10, json={"attributes": attributes}) _raise_for(response) return response.json() ``` ```ruby require "net/http" require "json" require "uri" require "erb" def nochurn_request(method, path, body = nil) uri = URI("#{ENV.fetch('NOCHURN_API_URL', 'https://api.nochurn.sh')}#{path}") request = Net::HTTP.const_get(method.capitalize).new(uri) request["Authorization"] = "Bearer #{ENV.fetch('NOCHURN_API_KEY')}" request["Content-Type"] = "application/json" request.body = JSON.generate(body) if body response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) } [ response.code.to_i, (JSON.parse(response.body) rescue nil) ] end def identify_customer(user, attributes) id = ERB::Util.url_encode(user[:id].to_s) status, data = nochurn_request(:post, "/v1/customers", { external_id: user[:id].to_s, email: user[:email], name: user[:name] }) if status == 409 nochurn_request(:patch, "/v1/customers/#{id}", { email: user[:email], name: user[:name] }) elsif status >= 300 raise "NoChurn: #{data&.dig('error', 'message')} #{data&.dig('error', 'fix')}" end status, data = nochurn_request(:post, "/v1/customers/#{id}/attributes", { attributes: attributes }) raise "NoChurn: #{data&.dig('error', 'message')} #{data&.dig('error', 'fix')}" if status >= 300 data end ``` ### Rules and limits - **Keys:** snake_case, starting with a letter, 40 characters at most (`signup_source`, not `Signup Source`). - **Values:** text (255 characters at most), numbers, booleans or dates (`2026-03-16` or ISO 8601). Flatten objects and lists. `null` removes the key from the customer. - **Types are locked:** the type of a key is set by its first value; another type later answers `422` [`attribute_type_mismatch`](/docs/errors/#attribute_type_mismatch) and writes nothing. `POST /v1/attribute_definitions` declares a key and its type before the first send. - **100 keys per account and mode.** One more answers [`attribute_limit_reached`](/docs/errors/#attribute_limit_reached). - **Sensitive attributes:** mark a key sensitive (`PATCH /v1/attribute_definitions/{key}`) and it is never sent to the AI. - Test and live mode keep separate attributes. ### What to send first `signup_source` and `onboarding_done` are the two the integration checklist looks for. Then, as you have them: `signup_date`, `plan` and `billing_interval`, `company_size` or `seats`, `activated_at`, `last_active_at`, the usage of your key feature, `support_tickets` or `nps`, `country` and `industry`, `coupon_used`, `trial_days`. The [Custom data & AI](/ai/) page says which question each one answers. Send them at signup and whenever they change (a signup handler, an after-save hook, a background job). ## Usage events `POST /v1/usage_events` records what a customer does: `{ customer, name, timestamp?, properties?, idempotency_key? }`. `POST /v1/usage_events/batch` takes up to 1,000 events. Events are deduplicated on `idempotency_key`, rolled up each night into the attributes `last_active_at`, `events_30d` and `_30d`, and never sent to the AI. ```bash curl -X POST https://api.nochurn.sh/v1/usage_events -H "Authorization: Bearer $NOCHURN_API_KEY" -H "Content-Type: application/json" -d '{"customer":"user_123","name":"project_created","properties":{"template":"blank"},"idempotency_key":"evt_42"}' ``` From the browser, NoChurn's script sends `page_view` and your own events to `POST /v1/widget/events` with the publishable key and the signed customer token: no secret key in the front end. ## CSV import `POST /v1/imports` takes a CSV of customers and attributes (multipart `file`, or the text as `csv`). Columns are mapped by name: `customer`, `external_id`, `email`, `stripe_customer`, `name`, `country`, `locale`; any other column becomes an attribute. `dry_run` returns the mapping and the first rows without writing. `GET /v1/imports/{id}` gives the error report. ## What comes out Data & AI ranks the attributes most linked to churn (`GET /v1/insights`), with the sample size of each group: correlation, not cause. The churn score of each customer (`GET /v1/customers/{id}/score`) uses them too. --- # Webhooks Source: https://www.nochurn.sh/docs/webhooks/ NoChurn sends an HTTPS `POST` to your endpoints each time something happens that your systems may care about: a payment recovered, a customer who cancelled, access to restrict, an order for your billing. The list of types and their payloads: [Webhook events](/docs/webhooks/events/). ## Create an endpoint From the dashboard (**Developers › Webhooks**) or the API. The URL must be `https://`. `events` lists the types to receive, or `["*"]` for all of them. An endpoint belongs to the mode of the key: a test endpoint only receives test events. ```bash curl -X POST https://api.nochurn.sh/v1/webhook_endpoints \ -H "Authorization: Bearer $NOCHURN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://app.example.com/webhooks/nochurn","events":["*"],"description":"Backend"}' ``` The response carries the signing secret, `whsec_…`, **once**: store it in your backend as `NOCHURN_WEBHOOK_SECRET`. You can rotate it later (`PATCH /v1/webhook_endpoints/{id}` with `rotate_secret: true`, which returns the new one once), change the URL or the types, or disable the endpoint (`status: "disabled"`). `POST /v1/webhook_endpoints/{id}/test` sends a signed test event right now (type `test`, an id starting with `nevt_test_`) and returns the delivery with your endpoint's answer. ## Verify the signature Each delivery carries these headers: | Header | Value | | --- | --- | | `NoChurn-Signature` | `t=,v1=` | | `NoChurn-Event` | The event type, e.g. `recovery.recovered` | | `NoChurn-Delivery` | The delivery id (`whd_…`), different for each delivery | | `User-Agent` | `NoChurn-Webhooks/1.0` | `v1` is the hex HMAC-SHA256 of `"."` with your endpoint secret. To verify: 1. Read the **raw** request body, not re-serialised JSON. 2. Recompute the HMAC and compare it with `v1` in constant time. 3. Reject a `t` more than 5 minutes away from your clock (replayed requests). 4. Answer `400` on a bad signature. On a good one, answer `2xx` fast and handle the event after answering. ```js // Node 18+. Express: express.raw({ type: "application/json" }); Next.js route handler: await request.text(). const parts = Object.fromEntries(String(header || "").split(",").map((part) => part.split("=", 2))); const t = Number(parts.t); if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds || !parts.v1) return false; const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex"); const a = Buffer.from(expected, "utf8"); const b = Buffer.from(String(parts.v1), "utf8"); return a.length === b.length && timingSafeEqual(a, b); } // app.post("/webhooks/nochurn", express.raw({ type: "application/json" }), (req, res) => { // if (!verifyNoChurnSignature(req.body.toString("utf8"), req.get("NoChurn-Signature"))) return res.sendStatus(400); // const event = JSON.parse(req.body.toString("utf8")); // res.sendStatus(200); // }); ``` ```python # Use the raw body (Django: request.body; Flask: request.get_data()). def verify_nochurn_signature(raw_body, header, secret=None, tolerance=300): secret = secret or os.environ["NOCHURN_WEBHOOK_SECRET"] if isinstance(raw_body, bytes): raw_body = raw_body.decode("utf-8") parts = dict(part.split("=", 1) for part in (header or "").split(",") if "=" in part) try: t = int(parts.get("t", "")) except ValueError: return False if abs(time.time() - t) > tolerance or "v1" not in parts: return False expected = hmac.new(secret.encode(), f"{parts['t']}.{raw_body}".encode(), hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts["v1"]) ``` ```ruby # Use the raw body (Rails: request.raw_post). require "openssl" def verify_nochurn_signature(raw_body, header, secret = ENV.fetch("NOCHURN_WEBHOOK_SECRET"), tolerance: 300) parts = header.to_s.split(",").to_h { |part| part.split("=", 2) } t = Integer(parts["t"].to_s, exception: false) return false if t.nil? || (Time.now.to_i - t).abs > tolerance || parts["v1"].nil? expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{parts['t']}.#{raw_body}") expected.bytesize == parts["v1"].bytesize && OpenSSL.fixed_length_secure_compare(expected, parts["v1"]) end # Rails (skip CSRF on this API controller): # def create # return head(:bad_request) unless verify_nochurn_signature(request.raw_post, request.headers["NoChurn-Signature"]) # event = JSON.parse(request.raw_post) # head :ok # end ``` These functions are the ones NoChurn tests against its own signer. The MCP server hands the same code to coding agents. ## Retries A delivery succeeds when your endpoint answers a `2xx`. Any other status, a timeout (NoChurn waits 10 seconds for the answer) or a connection error is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 8 hours and 24 hours: **7 attempts** in all. After the last one the delivery is marked `failed`. Redirects are not followed. A disabled endpoint receives nothing. `GET /v1/webhook_deliveries` lists deliveries (filter by `endpoint`, `status`: `pending`, `retrying`, `delivered`, `failed`, `skipped`, and `type`) with their attempts, the status your endpoint answered and how long it took. `GET /v1/webhook_deliveries/{id}` adds the payload. Each attempt is also a line of the dashboard's Logs. ## Replay a delivery `POST /v1/webhook_deliveries/{id}/replay` sends the same payload, with the **same event id**, as a new delivery right now, and returns it with your endpoint's answer. Use it once your endpoint is fixed. Replaying needs the admin role in the dashboard (or a key with write access to webhooks), and it is written to the account's events. ## Handle duplicates A retry or a replay delivers an event you may have handled already, and events can arrive out of order. Make your handler idempotent: - Store the event `id` (`nevt_…`) when you handle it, and skip an id you have seen. `NoChurn-Delivery` changes with every delivery, so do not deduplicate on it. - For the `billing.*_requested` orders, also pass their `idempotency_key` to your billing, so that a payment is never retried twice or a subscription cancelled twice. - When the order matters, read the current state from the API (for example `GET /v1/customers/{id}/access`) rather than trusting the last event received. ## Slack and Intercom The flows can also post a message to a Slack channel or add an internal note on the customer's Intercom contact, for the events a person wants to hear about. Those are set in the dashboard (flow settings) or with `/v1/flow_notifications`, not with webhook endpoints. --- # Chargebacks Source: https://www.nochurn.sh/docs/chargebacks/ When a customer disputes a payment, NoChurn gathers the evidence it already has, drafts a reply and waits for a person to review it. When the card network sends an early fraud warning, NoChurn shows it so you can refund before it becomes a dispute. ## Which providers | Provider | Disputes in NoChurn | | --- | --- | | Stripe, Braintree, Razorpay | Evidence gathered and a reply drafted; sent to the provider after review. Stripe also sends early fraud warnings | | Paddle, Lemon Squeezy, Polar | The merchant of record answers disputes; NoChurn shows them read only | | Chargebee, Recurly, Maxio, Zuora | Disputes stay with the payment gateway behind them; when that gateway is a connected Stripe account, NoChurn handles them as above | | Mollie, GoCardless | No API to contest: chargebacks show read only | | App Store, Google Play | Refund requests: NoChurn prepares the answer from your data | Details per provider: [Integrations](/docs/integrations/). ## How a dispute is handled 1. **Opened.** The dispute arrives from the provider with its deadline. Admins are told by email when it opens and again 72 hours before the deadline (Slack is optional). 2. **Evidence.** NoChurn collects what it has on the customer, each piece with its source: the cancel flow and what the customer chose, the emails sent, usage, conversations from your help desk (quoted as is, never rewritten), and your policies. `PATCH /v1/disputes/{id}/evidence` includes, excludes, reorders or adds a note; `POST /v1/disputes/{id}/evidence_files` attaches a PDF, JPEG or PNG (5 MB each, as many files as the provider accepts). 3. **Draft.** The AI drafts the reply from the included evidence only, and must cite it. `POST /v1/disputes/{id}/draft` drafts again; `PATCH /v1/disputes/{id}/draft` edits or approves it (any edit sends it back to draft). 4. **Review and send.** A person sends it: `POST /v1/disputes/{id}/submit`, final, admin or owner, with `confirm: true`. After that nothing can change. If a reply was already sent another way (for example from the provider's dashboard), NoChurn does not send a second one and answers `409` [`dispute_already_submitted`](/docs/errors/#dispute_already_submitted). 5. **Or accept.** `POST /v1/disputes/{id}/accept` (final, admin or owner, `confirm: true`) when contesting is not worth it. NoChurn also estimates the chance of winning (0 to 100, with its factors), which a person can override (`PATCH /v1/disputes/{id}/win_score`). It can suggest accepting a dispute when contesting is likely to cost more than it brings back, compared with your contest cost (`disputes_settings.contest_cost_cents`, no default value: without it, NoChurn never suggests accepting). NoChurn never accepts a dispute on its own. ## Automatic sending Off by default. When you turn it on (`disputes_settings.auto_submit` on `PATCH /v1/account`, owner or admin), NoChurn sends only a reply a person has approved, `auto_submit_hours_before` the deadline, and only when the chance of winning reaches `auto_submit_min_score`. ## Early fraud warnings `GET /v1/fraud_warnings` lists them (Stripe). `POST /v1/fraud_warnings/{id}/refund` refunds the payment before a dispute (final, admin or owner, `confirm: true`); by default it also cancels the customer's subscriptions (`cancel_subscription_on_fraud_refund`). `POST /v1/fraud_warnings/{id}/dismiss` keeps the payment. Automatic refunds are off by default (`auto_refund_fraud_warnings`). ## Numbers `GET /v1/disputes/summary` counts the disputes by state, with the amount won (disputes won only) and a win rate that always comes with the number of decided disputes, `null` until one is decided. --- # Test mode and sandbox Source: https://www.nochurn.sh/docs/testing/ ## Test mode A test key (`nc_test_…`) only reads and writes test data. In test mode NoChurn uses your billing tool's test data (Stripe test mode, a sandbox site or test credentials) and never emails a real inbox: emails are written, never delivered to your customers. Test and live keep separate customers, flows, webhook endpoints and attributes, so nothing you try leaks into live. New accounts start in test mode. Flows are published to test first (`POST /v1/flows/{id}/publish` with `{ "to": "test" }`), and a person switches to live in the dashboard. ## Sandbox scenarios Test mode only (a live key answers `403` [`test_mode_only`](/docs/errors/#test_mode_only)). Each scenario writes a `sandbox.*` event in the account's journal. | Endpoint | What it plays | | --- | --- | | `POST /v1/sandbox/customers` | A test customer with an active subscription (billed by API, no Stripe call) renewing in 5 days, and a test card | | `POST /v1/sandbox/failed_payment` | `{ customer, invoice_url? }`: a failed payment. The recovery flow (published in test) starts and writes its day-0 email | | `POST /v1/sandbox/card_removed` | `{ customer }`: the card is removed before the renewal; the customer is flagged | | `POST /v1/sandbox/cancel_flow_run` | `{ customer, reason?, accept_offer?, subscription? }`: plays the cancel flow, and cancels in one click when no offer is accepted | ```bash curl -X POST https://api.nochurn.sh/v1/sandbox/customers -H "Authorization: Bearer $NOCHURN_API_KEY" curl -X POST https://api.nochurn.sh/v1/sandbox/failed_payment -H "Authorization: Bearer $NOCHURN_API_KEY" \ -H "Content-Type: application/json" -d '{"customer":"cst_…"}' ``` To test your webhook handler, `POST /v1/webhook_endpoints/{id}/test` sends a signed test event to it right now. ## The integration checklist `GET /v1/integration/verify` checks 7 points in test mode. Each one is `pass`, `fail` (with its `fix`) or `unknown`. | Key | Passes when | | --- | --- | | `billing_connected` | A billing tool is connected in test mode, or your app sent a customer and a subscription (sandbox ones do not count) | | `webhook_verified` | Your webhook endpoint answered a delivery with `2xx` | | `identify_received` | A customer has the base attributes `signup_source` and `onboarding_done` | | `cancel_flow_opened` | Your app opened the cancel flow (sandbox runs do not count) | | `click_to_cancel` | A cancellation was carried out in test mode | | `failed_payment_email` | A failed payment produced the day-0 recovery email with a card update link | | `no_secret_in_code` | No secret key in the files sent with `POST /v1/integration/verify { snippets }` (scanned, never stored) | When all pass, a person goes live in the dashboard: live keys, live publication of the flows and the live billing connection. ## Test cards and test data Use your billing provider's own test cards and sandbox accounts. NoChurn stores no card number in any mode: only the brand, last 4 digits, expiry, funding, country and wallet. --- # AI apps and MCP Source: https://www.nochurn.sh/docs/mcp/ The NoChurn MCP server lets an AI coding agent integrate NoChurn into your app: account setup, test keys, the cancel flow, customer data, webhooks, tested code, sandbox scenarios and the integration checklist. It also answers business questions, read only: why customers churn, who is at risk, what NoChurn saved. **Test mode by default.** Every tool takes `mode: "test" | "live"` (default `test`). In live mode, reads work only if you allowed them for that app, and **every change needs a human**: the tool creates a live request and returns an approval link for an owner or admin. The agent never sees a live secret. ## Two ways to connect | | Remote (recommended) | Local | | --- | --- | --- | | Transport | Streamable HTTP, `https://mcp.nochurn.sh/mcp` | stdio, npm package `@nochurn/mcp` | | Credential | OAuth 2.1: the client opens a NoChurn sign-in, you pick the account | A **test** secret key `nc_test_…` in `NOCHURN_API_KEY` (anything else is refused) | | Shown in the journal as | The AI app, by name | The API key | ## Install ### Claude Code Remote (the browser opens on first use): ```sh claude mcp add --transport http nochurn https://mcp.nochurn.sh/mcp ``` Local, with a test key from Developers: ```sh claude mcp add nochurn --env NOCHURN_API_KEY=nc_test_… -- npx -y @nochurn/mcp ``` Then ask "Integrate NoChurn into this app", or run the prompt `/mcp__nochurn__integrate_nochurn`. ### Cursor `~/.cursor/mcp.json`, or `.cursor/mcp.json` in the project (never commit a key): ```json { "mcpServers": { "nochurn": { "url": "https://mcp.nochurn.sh/mcp" } } } ``` Local: ```json { "mcpServers": { "nochurn": { "command": "npx", "args": ["-y", "@nochurn/mcp"], "env": { "NOCHURN_API_KEY": "nc_test_…" } } } } ``` ### VS Code (Copilot agent mode) `.vscode/mcp.json`: ```json { "servers": { "nochurn": { "type": "http", "url": "https://mcp.nochurn.sh/mcp" } } } ``` Local, with the key asked once and stored by VS Code: ```json { "inputs": [{ "id": "nochurn-key", "type": "promptString", "description": "NoChurn test secret key (nc_test_…)", "password": true }], "servers": { "nochurn": { "type": "stdio", "command": "npx", "args": ["-y", "@nochurn/mcp"], "env": { "NOCHURN_API_KEY": "${input:nochurn-key}" } } } } ``` ### Windsurf The MCP config file of Cascade (Cascade › MCP › "Open MCP config file" shows where it is on your build), remote: ```json { "mcpServers": { "nochurn": { "serverUrl": "https://mcp.nochurn.sh/mcp" } } } ``` For the local server, use the same `command` / `args` / `env` block as Cursor, in the file of your home directory, never in the project. ### ChatGPT Remote only. Add NoChurn as a custom connector in ChatGPT's settings, with the URL `https://mcp.nochurn.sh/mcp` and OAuth authentication; ChatGPT opens the NoChurn sign-in, where you pick the account and approve. Depending on the plan, custom connectors may need to be allowed first (developer mode, or an admin of the workspace). The menu names change over time: follow OpenAI's help for the current steps. ## What the agent can do | Group | Tools | | --- | --- | | Discovery | `docs_search`, `docs_get`, `openapi_get` | | Account | `account_get_setup`, `account_connect_stripe_link`, `billing_source_set` | | Keys | `api_keys_create_test`, `publishable_key_get`, `widget_secret_create` | | Detection | `project_detect` | | Cancel flow | `cancel_flow_get`, `cancel_flow_update_draft`, `cancel_flow_set_theme`, `cancel_flow_preview_url`, `flow_publish_test` | | Code | `integration_get_snippets` (tested code, the same as in these docs) | | Data | `attributes_define`, `customers_update_attributes` | | Webhooks | `webhook_endpoints_create`, `webhook_endpoints_send_test` | | Sandbox | `sandbox_create_customer`, `sandbox_simulate_failed_payment`, `sandbox_simulate_card_removed`, `sandbox_run_cancel_flow` | | Verification | `integration_verify` (the [7-point checklist](/docs/testing/#the-integration-checklist)) | | Insights (read only) | `churn_drivers`, `customers_at_risk`, `revenue_saved` | | Live mode | `request_go_live`, `live_request_status` | Every API error comes back as a tool error with NoChurn's `message`, `fix` and `docs_url`. Customer content in tool results (names, emails, attribute values, AI text) is marked as data, never as instructions. ## Rights of an AI app - **Scopes:** `read`, `configure` and `sandbox`. There is no live scope. Writes are limited to a closed list of endpoints that only touch test mode or a draft. - **Your role applies:** the app can do what the person who connected it can do, no more. - **Live reads** only when that person ticked "Allow reading live data" when connecting, or turned it on later in **Settings › AI apps**. Otherwise a live read answers `403` [`live_read_not_granted`](/docs/errors/#live_read_not_granted). - **Live writes** never run directly (`403` [`live_approval_required`](/docs/errors/#live_approval_required)). The app asks with `POST /v1/live_requests`; an owner or admin approves it in the dashboard, and it runs in that person's name. Some things can never be requested: the team, AI access, two-factor settings, the NoChurn plan, existing keys and deleting the account. - **Revoke** an app in **Settings › AI apps** (`DELETE /v1/oauth/grants/{id}`): its pending live requests are cancelled. Every action of an app is written to the account's events with the app's name as the actor. --- # Integrations Source: https://www.nochurn.sh/docs/integrations/ NoChurn reads your billing from Stripe, another billing tool, or your own code. Help desks add their conversations on top. Connect them from **Integrations** in the dashboard, test mode first; `GET /v1/billing_providers` lists the billing tools with their guide. What each tool lets NoChurn do differs: who retries a failed payment, whether there is a page to update the card, which offers can be applied, and whether disputes can be answered. Each page below says it, from the same table NoChurn's code reads. ## Most used - [Stripe](/docs/integrations/stripe/): one click with Stripe Connect. - [Any billing, by API](/docs/integrations/api/): send subscriptions and payments from your code. Full guide: [Your own billing (API)](/docs/billing-api/). ## Billing platforms - [Chargebee](/docs/integrations/chargebee/) - [Recurly](/docs/integrations/recurly/) - [Maxio](/docs/integrations/maxio/) - [Zuora](/docs/integrations/zuora/) ## Merchants of record They collect the payment and answer disputes themselves; NoChurn adds the cancel flow, win-back, the churn score and your data. - [Paddle](/docs/integrations/paddle/) - [Lemon Squeezy](/docs/integrations/lemon-squeezy/) - [Polar](/docs/integrations/polar/) ## Payment providers - [Braintree](/docs/integrations/braintree/) - [Mollie](/docs/integrations/mollie/) - [GoCardless](/docs/integrations/gocardless/) - [Razorpay](/docs/integrations/razorpay/) ## App stores Apple and Google keep the payment, the retries and the cancel button. NoChurn reads every subscription change; customers are linked only when your app passes its user id at purchase. - [App Store](/docs/integrations/app-store/) - [Google Play](/docs/integrations/google-play/) ## Your own billing system, by webhooks - [Custom billing](/docs/integrations/custom/): NoChurn reads the webhooks your billing system already sends, through a mapping you test on a sample. ## Help desks Read only. Conversations are matched to customers by email and used in the churn score, the churn drivers and dispute evidence. - [Intercom](/docs/integrations/intercom/) - [Zendesk](/docs/integrations/zendesk/) - [HubSpot](/docs/integrations/hubspot/) - [Help Scout](/docs/integrations/help-scout/) - [Gorgias](/docs/integrations/gorgias/) - [Crisp](/docs/integrations/crisp/) ## Your user id in each tool NoChurn reads your own user id (`external_id`) in each billing tool at one place: Stripe's customer `metadata.user_id` by default (`external_id_metadata_key` on the account), or the field you set on the connection (`internal_id_field`, `PATCH /v1/billing_connections/{id}`). With it, a customer from the tool is linked to the one your app sends instead of becoming a duplicate. --- # Failed payments: Get back the payments that failed for no good reason. Source: https://www.nochurn.sh/features/failed-payments/ Most failed payments are an expired card or a bad day at the bank. NoChurn retries at the right moment, writes the email, and gives your customer a ten-second way to fix their card. ## How it works 1. **A payment fails.** NoChurn reads the failure from your billing, with the decline code, the plan and the customer’s history. A recovery opens in the dashboard. 2. **It picks the right retry.** Retries land on likely paydays (the 1st, the 15th, the last working day, Fridays) in the customer’s time zone. A hard decline, like a stolen card or a closed account, skips straight to the email. 3. **It writes the email.** Day 0, 3, 7 and 14 by default. Each email is written for this customer: plan, language, how long they have been with you, why the payment failed. It is checked before it leaves. 4. **The card gets updated.** A signed link opens a hosted page, no login needed. The new card becomes the default and the invoice is retried. The recovery closes as recovered or lost, with the reason. ## What you control - **Who retries.** Keep your provider’s own retries, or let NoChurn take over the schedule. One switch per billing connection. - **Retry window.** Pick the days and hours retries may run. NoChurn stays inside them. - **Email sequence.** Change the days, the number of emails and the tone. Every email can be previewed before it goes live. - **Human review.** Let the automatic checks send, or ask for a person to approve each email first. - **Your brand.** Your logo, colors, sender name and reply-to. Replies come back to your team. - **Replies sorted for you.** Customer replies are sorted: card changed, wants to cancel, invoice question, other. Each one triggers the right action or goes to your team. ## Built in - **Card numbers never reach NoChurn.** NoChurn sees the brand, last 4 digits, expiry, country and type. The card itself stays with your payment provider. - **No email without a check.** Length, links, tone, and no promise you did not set up. Anything that fails the check waits for a person. - **Every decision is written down.** Why a retry was scheduled, why an email was sent, why a recovery closed. All of it shows on the customer’s timeline. ## API Using your own billing? Send failed payments to the API. NoChurn decides when to retry and tells you through a signed webhook. - `POST /v1/payments`: Report a payment, failed or successful - `GET /v1/recoveries`: List open, recovered and lost recoveries - `webhook billing.retry_requested`: Your billing runs the charge now - `webhook recovery.recovered`: The payment went through - `webhook recovery.lost`: The sequence ended without a payment ## FAQ **Does NoChurn replace Stripe’s Smart Retries?** Only if you want it to. You can keep Stripe’s retries and use NoChurn for the emails and the card update page, or let NoChurn take over the retry schedule for that Stripe account. **Who writes the recovery emails?** NoChurn writes each one with AI, from the plan, the language, the customer’s tenure and the decline reason, in the tone you set. Every email is checked before sending, and you can require a person to approve them. **Can I test it without charging anyone?** Yes. With a test key or Stripe test mode, nothing real is charged and no email leaves NoChurn. You see every step in the dashboard as if it were live. **What happens when a customer replies?** The reply is sorted. If the customer says they changed their card, NoChurn checks and retries. If they want to cancel, the cancel is honoured. Anything else goes to your team. --- # Chargebacks: Answer every chargeback with evidence you already have. Source: https://www.nochurn.sh/features/chargebacks/ When a customer disputes a payment, NoChurn builds the case from what it already knows, drafts the reply, and waits for you. You read it, edit it, and send it before the deadline. ## How it works 1. **A dispute opens.** NoChurn picks it up from your payment provider with the reason, the amount and the deadline. It shows in your to-do list and on the customer’s timeline. 2. **The evidence comes together.** For the dispute reason, NoChurn pulls what it has: cancel flow history, renewal reminders, invoices, usage after the charge, support conversations. Each piece keeps its source. 3. **A reply is drafted.** AI writes the response using only the evidence in the file. Nothing is added that is not there. Customer messages are quoted, never rewritten. 4. **You review and send.** Edit the draft, include or drop evidence, then submit to your provider in one click. Reminders arrive three days and one day before the deadline. ## What you control - **Evidence by reason.** Subscription canceled, fraudulent, product not received, credit not processed, duplicate: each reason has its own checklist. - **Your own documents.** Add a file or a note to any case, or take out an item you would rather not send. - **Who can submit.** Only admins and owners can send a reply. Every submission is logged with who sent it. - **Auto-submit, if you want it.** Off by default. Turn it on and NoChurn submits before the deadline when nobody has. - **Early fraud warnings.** When the card network flags a payment, refund it in one click (and stop the subscription if you choose) to avoid the dispute and its fee. - **Prevention at the source.** Renewal reminders, one-click cancel and a clear bank statement name cut “I didn’t recognise this” disputes. ## Built in - **Nothing is sent without you.** Submitting a dispute is final, so a person approves it unless you turned on auto-submit yourself. - **Only real evidence.** Every item links back to where it came from. The AI can’t invent a fact or a date that is not in the file. - **Never submitted twice.** If your provider already submitted the case (Stripe Smart Disputes, for example), NoChurn shows it read only. ## API Every dispute is also in the API, from the evidence file to the submission. - `GET /v1/disputes`: Disputes by status, deadline or customer - `GET /v1/disputes/:id`: Evidence file, draft and history - `PATCH /v1/disputes/:id/draft`: Edit the reply - `POST /v1/disputes/:id/submit`: Send it to the provider (admins only) - `POST /v1/fraud_warnings/:id/refund`: Refund a flagged payment ## FAQ **Does NoChurn submit disputes on its own?** No, unless you switch on auto-submit. By default an admin reviews the draft and submits it. Submitting is final, so NoChurn never does it behind your back. **Where does the evidence come from?** From what NoChurn already has on the customer: cancel flow answers, emails and reminders sent, invoices, usage you send by API, and conversations from your help desk if you connected one. **Can the AI make things up?** The draft is written only from the items in the evidence file, and each item links to its source. You read the full text before it goes anywhere. **What about Paddle or the App Store?** A merchant of record answers disputes itself, so NoChurn shows them read only. For App Store refund requests, NoChurn can send Apple the real usage data instead of a written reply. --- # Cancel flows: Ask why they leave. Offer the right thing. Let them go in one click. Source: https://www.nochurn.sh/features/cancel-flows/ A short flow at the moment of cancellation: a reason, an offer that fits that reason, and a cancel button that is always there. Styled like your app, or built by you on the API. ## How it works 1. **The customer clicks cancel.** Your app opens the NoChurn flow: a modal, a side panel or a full page, with one script tag, a React component or a hosted link. 2. **They pick a reason.** Too expensive, missing a feature, not using it enough, switching tools, or their own words. You choose the list and the order. 3. **They see one offer.** A discount, a pause, a smaller plan, or a call with your team, picked for that reason and that customer. Or no offer at all. 4. **They stay, or they leave.** Accepting applies the offer in your billing right away. Cancelling is executed, at any step, every time. Both land in the dashboard with the reason. ## What you control - **Visual editor.** Live preview on desktop and mobile. Colors, font, corners, logo and layout, with a contrast check as you go. - **Your CSS.** Write CSS against stable class names. The flow renders in a shadow DOM, so your site and the flow never clash. - **Offers by segment.** Different offers for monthly and annual plans, new and long-time customers, or any attribute you send. - **Five languages.** Texts in English, German, French, Italian and Portuguese, with a suggested translation you review. - **Drafts and versions.** Changes stay in draft until you publish. Every version is kept, and you can roll back. - **Headless.** Prefer your own screens? Fetch reasons and offers from the API and post the answer back. Web, desktop, iOS or Android. ## Built in - **Cancel is always one click away.** “Cancel now” is visible at every step, and a cancellation that is asked for is carried out. No maze. - **CSS can’t hide the button.** If custom CSS hides the cancel button or makes it hard to read, NoChurn restores it and warns you. - **Works with a keyboard.** Focus stays in the flow, Escape closes it, and the roles stay right whatever the theme. ## API Run the whole flow from your own interface. The texts come back translated and ready to show. - `POST /v1/cancel-sessions`: Start a flow for a customer - `POST /v1/cancel-sessions/:id/reason`: Send the reason, get the offer - `POST /v1/cancel-sessions/:id/accept`: Apply the offer - `POST /v1/cancel-sessions/:id/cancel`: Cancel, from any step - `webhook cancel_session.completed`: The flow ended: saved or cancelled ## FAQ **Is this legal under click-to-cancel rules?** The flow is built for it: the cancel button is on every step, an asked-for cancellation is always executed, and custom CSS cannot hide the button. Check the rules that apply to your business with your own counsel. **How long does it take to set up?** One script tag and one line of JavaScript for the hosted modal, or a React component. Most teams start with the default reasons and change them later. **Can I use my own design?** Yes, three ways: the visual editor, a theme passed in code, or your own CSS. Or skip our screens entirely and use the API. **Does it work in a mobile app?** Yes, with the headless API. On the App Store and Google Play the final cancel button stays with Apple and Google, so NoChurn can show the reasons and offers before sending the user there. --- # Win-back: Bring back the customers who left, with a reason to return. Source: https://www.nochurn.sh/features/win-back/ People leave for a reason, and reasons change. NoChurn writes to former customers at 30, 60 and 90 days, starting from why they left, with a link that brings them back in one click. ## How it works 1. **A customer cancels.** NoChurn keeps the reason they gave in the cancel flow, their plan, and how long they stayed. 2. **The timing is set.** Day 30, 60 and 90 after they leave, by default. You can change the days or stop after one email. 3. **The email starts from the reason.** Left for a missing feature? The email says what shipped since. Too expensive? It can carry the offer you set up. Written by AI in your tone, checked before sending. 4. **One click to come back.** The link opens a checkout already filled in, with the offer if there is one. The customer is counted as won back in the dashboard. ## What you control - **Days and number of emails.** Three by default, at 30, 60 and 90 days. Change it per reason. - **What’s new.** Tell NoChurn what you shipped, and it will mention it to the people who asked for it. - **Offers.** A discount or a free month, only for the reasons you choose. Or none at all. - **Replies to your team.** Replies land in your team’s inbox, so a real person can answer. - **Preview and review.** See each email before it goes live, and ask for approval if you want a person to check. - **By segment.** Different emails for annual and monthly plans, or any attribute you send. ## Built in - **Unsubscribes are respected.** Every email has an unsubscribe link, and once used, NoChurn stops writing. - **No promise you didn’t make.** An email mentions a feature or an offer only if you set it up. - **Nothing leaves in test mode.** With a test key, emails are written and shown in the dashboard, never sent. ## API Know when a customer comes back, and send the reason yourself if they cancelled outside NoChurn. - `PATCH /v1/subscriptions/:id`: Report a cancellation from your billing - `POST /v1/cancel-flow/answers`: Send a cancel reason collected elsewhere - `webhook winback.reactivated`: A former customer came back ## FAQ **Isn’t emailing former customers spam?** They were your customers, the emails are few and spaced out, each one has an unsubscribe link, and NoChurn stops as soon as it is used. Check the rules that apply in your countries. **What if the customer never gave a reason?** NoChurn writes a general email from their plan and history. Reasons from the cancel flow make the emails much more specific. **Can I add an offer?** Yes, per reason. The link back opens a checkout with the offer already applied. **Does it work for app store subscriptions?** If your app sends NoChurn the customer’s email, yes. Apple and Google don’t share it, so NoChurn can only write to people you identified. --- # Churn score: See who is likely to leave, from the day they sign up. Source: https://www.nochurn.sh/features/churn-score/ A score from 0 to 100 for every new customer, with the reasons behind it. A prepaid card, a disposable card, a card removed just before renewal: you know before the payment fails. ## How it works 1. **A customer signs up.** NoChurn reads the payment method type, the card country, the signup source and any attributes you send. 2. **It gets a score.** From 0 to 100, with a level (low, medium, high) and the factors that moved it, each with its weight. 3. **It learns your business.** The first scores use sensible defaults. Once your account has enough history, the weights are learned from your own customers. 4. **It warns you early.** If a customer removes their card a few days before renewal, they are flagged and a save email can go out before the payment fails. ## What you control - **Risk by payment method.** Prepaid and disposable cards rank high, neobank cards medium, wallets, Link, bank cards and SEPA low. Adjusted to your history over time. - **Your signals.** Signup source, onboarding, seats, activity: anything you send as an attribute can weigh in. - **Suggested actions.** Ask for a second card, push onboarding, offer the annual plan, or alert your team. - **Early warning window.** Choose how many days before renewal a removed card should raise the flag. Seven by default. - **In every flow.** The score can pick the cancel offer, the tone of recovery emails, or the timing of win-back. - **In your tools.** Read the score from the API, or receive it by webhook as soon as it is computed. ## Built in - **Never a black box.** Every score comes with the factors that made it, so you can see why a customer is flagged. - **Shown with its sample.** Learned weights are shown with how many customers they are based on. Too few, and the defaults stay. - **Built without card numbers.** The score uses the card type, funding and country. Never the number. ## API Use the score in your own app: gate a trial, ask for a second card, or route a customer to your team. - `GET /v1/customers/:id/score`: Score, level and factors - `PATCH /v1/customers/:id`: Send attributes that feed the score - `webhook customer.scored`: A new or updated score - `webhook customer.flagged`: Card removed before renewal ## FAQ **Is this the same as a fraud score?** No. Fraud tools ask whether a payment is legitimate. The churn score asks whether a real customer is likely to leave or fail to pay, and why. **How does it know a card is prepaid?** Payment providers share the card’s funding type (credit, debit, prepaid) without the card number. NoChurn reads that field. **What can I do with a high score?** Ask for a second card, push onboarding, offer the annual plan, or alert your team. You choose which action runs for which level. **Does it work without Stripe?** Yes. Send the payment method type and your attributes through the API, and the score works the same way. --- # Headless API: Everything NoChurn does, available through the API. Source: https://www.nochurn.sh/features/headless-api/ Keep your billing and your screens. Send customers, payments and cancellations, run the cancel flow from your own interface, and get signed webhooks back. Web, desktop, iOS or Android. ## How it works 1. **Create a test key.** A key starting with nc_test_ works in a sandbox: nothing real is charged and no email leaves NoChurn. 2. **Send your data.** Customers, subscriptions, payments and cancellations, plus any attribute or usage event. With your own id, a Stripe id, or ours. 3. **Build your screens.** Fetch the cancel flow’s reasons and offers, show them your way, and post the answer back. The texts arrive translated. 4. **Listen to webhooks.** NoChurn tells your app what to do: retry this payment, apply this discount, this customer cancelled, this one came back. ## What you control - **Three ids per customer.** Use your own external id, the Stripe customer id, or the NoChurn id. All three resolve to the same customer. - **Signed webhooks.** Every webhook is signed (NoChurn-Signature) and retried with backoff until your endpoint answers. - **Idempotent writes.** Send an Idempotency-Key on any write, and a retried request never runs twice. - **Restricted keys.** Give each key none, read or write access per resource. A key can’t create a stronger key. - **Public keys for front ends.** pk_ keys plus a signed customer token let your web or mobile front end call the cancel flow directly. - **Errors that tell you the fix.** Every error has a code, a message, the fix and a link to the docs. ## Built in - **Test keys stay in test.** An nc_test_ key only sees test data and never sends a real email or moves real money. - **A cancel link in every session.** Each cancel session returns cancel_url_now, valid for the whole session, so cancelling stays one click away in your UI too. - **No secret in your front end.** Front ends use public keys and short-lived customer tokens. Secret keys stay on your server. ## API A few of the endpoints. The full reference is in the docs, and openapi.yaml is the source of truth. - `POST /v1/customers`: Create a customer with your own id - `POST /v1/subscriptions`: Send a subscription - `POST /v1/events`: Track a usage event - `POST /v1/cancel-sessions`: Start a cancel flow - `POST /v1/webhook-endpoints`: Subscribe to webhooks ## FAQ **Do I need Stripe to use NoChurn?** No. With the API, NoChurn works with in-house billing or any provider. Stripe and the other connectors just save you the integration work. **Can a coding agent do the integration?** That is the idea behind the NoChurn MCP server and llms.txt: point your agent at them with a test key, and it can wire the calls and webhooks in your codebase. **Which platforms can show the cancel flow?** Any of them. The API returns plain JSON: reasons, offers and texts. Render it on the web, in a desktop app, or natively on iOS and Android. **How do I keep my keys safe?** Secret keys stay on your server. Front ends use public pk_ keys with a signed customer token, and restricted keys limit what each key can touch. --- # NoChurn for B2B SaaS Source: https://www.nochurn.sh/use-cases/b2b-saas/ B2B SaaS churn rarely looks like one person changing their mind. A corporate card expires and nobody updates it. The person who signed up leaves the company. A team shrinks and the admin decides it is simpler to cancel than to remove seats. Each of these has a different fix, and NoChurn treats them separately. ## Where B2B SaaS loses customers ### Involuntary churn - **Company cards that expire or get replaced.** Cards are often issued to one employee. When that person leaves or the card is reissued, payments start failing, and the reminder emails go to someone who no longer reads them. - **Billing contacts who are not users.** The finance contact pays the invoice but does not use the product. They have no reason to act quickly on a failed payment. - **Approval delays.** Updating a payment method can require a manager or a purchasing step. A single reminder is not enough time. ### Voluntary churn - **Seat contraction that turns into a full cancel.** A team gets smaller and the admin cancels instead of adjusting the plan. - **Champion loss.** The person who chose the tool moves on and the team drifts away from it. - **Low activation.** Accounts that never finished setup are the easiest to cancel at renewal time. - **Budget reviews.** Tools get cut in bulk when finance looks at spend. ## How NoChurn handles it ### Failed payments NoChurn retries failed payments at times that match the customer's local time and likely paydays, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). Recovery emails are written by AI for each customer, sent by default on day 0, 3, 7 and 14, and reviewed before they go out. They can go to the billing contact and the account admin, so the person who can act gets the message. Each email links to a hosted card update page; card data stays with Stripe and NoChurn never sees card numbers. Replies are read and sorted, then answered or passed to your team, which matters when a customer writes back "our purchasing team needs an invoice first." See [failed payments](/#dunning). ### Churn score Every new account gets a score from 0 to 100 at signup, based on payment method, signup source and any custom data you send. NoChurn also flags customers who remove their card before a renewal and starts a save flow before the payment fails, instead of after. See [churn score](/#score). ### Cancel flow with offers that fit teams The cancel flow asks for a reason, then shows an offer that matches it: | Reason | Suitable offer | | --- | --- | | Team got smaller | Downgrade or fewer seats | | Too expensive | Discount through a Stripe coupon | | Not using it right now | Pause the subscription | | Missing a feature or unsure | Book a call with your team | A one-click "cancel now" button is visible on every step, so admins are never trapped. You can use the hosted modal with your colors, fonts and logo, or build the whole flow yourself with the headless API. See [cancel flows](/#cancel). ### Win-back Accounts that leave get win-back emails at 30, 60 and 90 days, written from the cancel reason. A team that left because of a missing feature gets a different message from one that left over budget. ### Custom data worth sending B2B accounts carry a lot of signal. Good attributes to start with: - `seats` and `company_size`: do small teams or single-seat accounts leave more? - `activated_at`: do accounts that never finished setup cancel at the first renewal? - `last_active_at`: how long does an account go quiet before it cancels? - `key_feature_usage`: which feature keeps teams, and which one nobody uses? - `signup_source`: do some channels bring accounts that churn more? - `plan` and `billing_interval`: do monthly plans leave more than annual ones? - `support_tickets` and `nps`: do unhappy accounts warn you first? - `industry` and `country` NoChurn computes which attributes go with churn (relative risk, sample size, confidence), and AI explains the results and suggests actions. This shows correlation, not cause: use it to decide who gets which offer, not as proof of why people leave. See [custom data](/#insights). ## Setup Connect Stripe in one click with Stripe Connect. NoChurn reads subscriptions and invoices and can run retries. If you bill outside Stripe, keep your billing and send subscriptions, payments and cancellations through the REST API instead. Chargebee, Recurly, Paddle, Braintree, Mollie and other billing platforms connect directly too. Start with the [quickstart](/docs/quickstart/). ## How NoChurn helps NoChurn gives B2B SaaS teams payment recovery that reaches the right contact, a cancel flow that offers fewer seats before a full cancel, and a view of which account attributes go with churn. Every feature is on every plan, and the price depends only on your MRR, never on a share of recovered revenue. See [pricing](/pricing/), or read about [AI and usage-based tools](/use-cases/ai-tools/) and [developer tools](/use-cases/developer-tools/). --- # NoChurn for consumer subscriptions Source: https://www.nochurn.sh/use-cases/consumer-subscriptions/ Consumer subscriptions run on volume: many customers, small monthly charges, and little direct contact. People sign up on impulse, pay with whatever card is in their wallet, and cancel when money is tight or when they stop using the product. NoChurn handles the payment side and the decision side with different tools. ## Where consumer subscriptions lose customers ### Involuntary churn - **Insufficient funds.** A charge that fails a few days before payday often succeeds a few days after it. - **Prepaid and disposable virtual cards.** Some customers sign up with a card that is designed to run out or be thrown away after a trial. - **Expired and replaced cards.** Consumers rarely update every subscription when they get a new card. - **Emails nobody opens.** A generic "your payment failed" message is easy to ignore. ### Voluntary churn - **Forgotten value.** People stop using the product and only notice it again on their bank statement. - **Seasonal or temporary use.** A customer needs the product for a few months, then not for a while. - **Price sensitivity.** A small monthly charge is still one of the first things cut from a budget. - **Hard-to-find cancel buttons** create chargebacks and complaints, not loyal customers. ## How NoChurn handles it ### Failed payments NoChurn times retries to likely paydays and to the customer's local time, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). Recovery emails are written by AI for each customer, in their language (English, German, French, Italian or Portuguese), sent by default on day 0, 3, 7 and 14, and reviewed before they go out. Each one links to a hosted card update page that works on a phone; card data stays with Stripe. Replies are read, sorted, and answered or sent to your team. See [failed payments](/#dunning). ### Churn score Each customer gets a score from 0 to 100 at signup. Payment method is a strong input: prepaid and disposable virtual cards start as high risk, neobank cards as medium, and Stripe Link, Apple Pay, Google Pay, regular bank cards and SEPA as low. These levels are then learned from your own account's history, not fixed. Signup source and custom data are added on top. If a customer removes their card before renewal, NoChurn flags it and starts a save flow before the payment fails. See [churn score](/#score) and [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ### Cancel flow with consumer-friendly offers The cancel flow asks why the customer is leaving and shows one matching offer: - **Not using it right now:** pause the subscription for a set period (Stripe supports [pausing payment collection](https://docs.stripe.com/billing/subscriptions/pause-payment)). - **Too expensive:** a discount through a Stripe coupon, or a cheaper plan. - **Found something else or no longer needed:** no offer, just a clean exit and a reason you can learn from. A one-click "cancel now" button is visible on every step. The hosted modal matches your brand (themes, colors, fonts, logo, custom CSS), or you can build your own screens on the headless API. See [cancel flows](/#cancel). ### Win-back Customers who cancel receive win-back emails at 30, 60 and 90 days, written from the reason they gave. Someone who paused for the summer and someone who said it was too expensive get different messages. ### Custom data worth sending - `signup_source`: do customers from paid social churn more than those from search or referrals? - `coupon_used`: do discount signups stay once the discount ends? - `trial_days`: do customers with a short trial, or none, leave sooner? - `last_active_at`: how many days of inactivity come before a cancel? - `key_feature_usage`: which habit keeps people subscribed? - `payment_method`: do some methods fail more often? - `country` NoChurn computes which attributes go with churn and AI explains the results. It is correlation, not cause. See [custom data](/#insights). ## Setup Connect Stripe in one click with Stripe Connect. If you bill elsewhere, keep your billing and send subscriptions, payments and cancellations through the REST API. Add the cancel flow with one script tag, or link to the hosted flow from your emails and account page. See the [quickstart](/docs/quickstart/). ## How NoChurn helps For consumer subscriptions, NoChurn combines payday-aware retries, a risk score that knows prepaid cards from bank cards, pause and discount offers with an honest cancel button, and win-back emails based on the cancel reason. Every feature is on every plan; you pay by MRR band, never a share of what is recovered. See [pricing](/pricing/), or the pages for [memberships and communities](/use-cases/memberships-communities/) and [mobile apps](/use-cases/mobile-apps/). --- # NoChurn for mobile apps Source: https://www.nochurn.sh/use-cases/mobile-apps/ Many mobile apps sell subscriptions on the web through Stripe, while customers spend their time in the app. That creates a gap: billing events happen on the web, but the moment someone decides to leave happens on a phone. NoChurn closes that gap with a headless API you can draw natively on iOS and Android. ## What NoChurn covers, and what it does not NoChurn works with subscriptions billed on the web, through Stripe or through your own billing system via the API. In-app subscriptions bought through the App Store or Google Play are managed by Apple and Google. Their billing, payment retries and cancellation happen inside those stores ([Apple subscriptions](https://developer.apple.com/app-store/subscriptions/), [Google Play Billing](https://developer.android.com/google/play/billing)). NoChurn connects to both stores: renewals, billing issues, cancellations and refunds land in the same customer timeline, scores and win-back as your web subscribers. Payment retries and the cancel button stay with Apple and Google, so for store subscribers NoChurn warns the customer and points them to the store instead of retrying or cancelling itself. ## Where mobile apps lose web subscribers ### Involuntary churn - **Cards saved once, on the web, months ago.** The customer has forgotten where they paid, so a failed payment email feels unfamiliar. - **Card updates on a small screen.** If the update page is hard to use on a phone, people give up. - **Prepaid and virtual cards** used to sign up for trials. ### Voluntary churn - **The app goes unopened.** Usage drops, and the subscription becomes something to cut. - **Cancel happens outside your flow.** If the in-app "manage subscription" button just opens a generic page, you miss the chance to ask why or to offer an alternative. - **Short-term needs.** Fitness, travel, learning and productivity apps often have seasonal use. ## How NoChurn handles it ### Failed payments NoChurn retries failed web payments at times that match the customer's local time and likely paydays, or you can keep Stripe Smart Retries. AI-written recovery emails go out by default on day 0, 3, 7 and 14, in the customer's language, reviewed before sending. They link to a hosted card update page that works on mobile and opens in the browser; card data stays with Stripe. See [failed payments](/#dunning). ### Churn score At signup each customer gets a score from 0 to 100, based on payment method, signup source and your custom data. If a customer removes their card before renewal, NoChurn flags it and starts a save flow before the payment fails. ### Native cancel flow with the headless API The headless API gives you the cancel reasons and offers for a customer, and you send back the answer. You draw every screen in SwiftUI, UIKit, Jetpack Compose or your cross-platform framework. The flow is the same as on the web: 1. The customer picks a reason. 2. They see a matching offer: pause, discount through a Stripe coupon, or a smaller plan. 3. They accept the offer or confirm the cancel. A one-click "cancel now" option stays visible on every step, on mobile too. If you prefer not to build screens, the hosted flow can open in a web view or the browser. Coding agents can also integrate it through the NoChurn [MCP server](/#mcp). See [cancel flows](/#cancel). ### Win-back Customers who cancel get win-back emails at 30, 60 and 90 days, written from the cancel reason. ### Custom data worth sending - `last_active_at`: last app open. How long does a subscriber stay inactive before canceling? - `key_feature_usage`: sessions, workouts, lessons, or whatever your core action is. - `signup_source`: app install campaign, web, referral. - `trial_days` and `coupon_used` - `country` - platform (for example `ios` or `android`), as your own attribute name NoChurn computes which attributes go with churn, and AI explains the result. Correlation, not cause. See [custom data](/#insights). ## Setup Connect the Stripe account that bills your web subscriptions in one click, or send subscriptions, payments and cancellations through the REST API if you bill elsewhere. Then call the headless API from your app to fetch reasons and offers and post the answer. See the [API reference](/docs/api/). ## How NoChurn helps For mobile apps with web billing, NoChurn recovers failed web payments, lets you build the cancel flow natively on iOS and Android with the same offers and one-click cancel as on the web, and shows which usage patterns go with churn. For App Store and Google Play subscribers, retries and cancellation stay with Apple and Google. See [pricing](/pricing/), or the pages for [consumer subscriptions](/use-cases/consumer-subscriptions/) and [online courses](/use-cases/online-courses/). --- # AI and usage-based tools Source: https://www.nochurn.sh/use-cases/ai-tools/ AI products and usage-based tools have a churn pattern of their own. Customers try many tools, compare them often, and stop using one long before they cancel it. At the same time, each active customer has a real cost behind it (model calls, compute, storage), so a blanket discount can cost more than it saves. NoChurn helps you see the drop early and make offers that fit the economics. ## Where AI and usage-based tools lose customers ### Involuntary churn - **Variable invoices.** When a bill depends on usage, a higher-than-usual charge is more likely to hit a card limit. - **Trial-era cards.** Customers often sign up with a virtual or prepaid card to test the tool, and that card fails at the first real charge. - **Card updates nobody prioritizes.** The tool is one of many on the card, and the failed payment email gets lost. ### Voluntary churn - **Usage decay.** The customer tried it for a project, the project ended, and the subscription keeps running unused. - **Switching.** New tools appear fast, and a customer can move with little effort. - **Cost surprises.** A large usage bill can push someone to cancel rather than adjust. - **Wrong plan size.** A customer on a plan bigger than their real use feels they are overpaying. ## How NoChurn handles it ### Failed payments NoChurn retries failed payments at times based on the customer's local time and likely paydays, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). AI-written recovery emails go out by default on day 0, 3, 7 and 14, reviewed before sending, and link to a hosted card update page where card data stays with Stripe. Replies such as "why was this bill so high?" are read and sorted, then answered or sent to your team. See [failed payments](/#dunning). ### Churn score and early alerts At signup each customer gets a score from 0 to 100 based on payment method, signup source and custom data. Disposable virtual and prepaid cards start as high risk; the levels are then learned from your own history. When a customer removes their card before renewal, NoChurn flags it and starts a save flow before the payment fails, not after. Combined with usage data, this lets you act before the renewal instead of reacting to a cancel. See [churn score](/#score). ### Offers by segment Because each customer has a cost, the right offer depends on who is leaving. With the cancel flow you can target offers using any attribute you send: | Segment | Offer that often fits | | --- | --- | | Low usage, on a large plan | Downgrade to a smaller plan | | Project ended, may come back | Pause the subscription | | Price-sensitive, still active | A one-off credit or discount through a Stripe coupon | | Heavy user with a problem | Book a call | A one-click "cancel now" button stays visible on every step. Use the hosted modal or the headless API for a flow drawn entirely in your own interface. See [cancel flows](/#cancel). ### Win-back Customers who leave get win-back emails at 30, 60 and 90 days, written from the reason they gave. Someone who left because a feature was missing can hear what has changed since; someone who left over price can hear about a smaller plan. ### Custom data worth sending Usage is the most useful signal for this kind of product: - `key_feature_usage`: generations, queries, runs, tokens or credits used in a period. - `last_active_at`: how long does usage go quiet before a cancel? - `activated_at`: did the customer reach their first useful result? - `plan` and `billing_interval` - `signup_source`: do some channels bring short-lived "try it once" customers? - `trial_days` and `coupon_used` - `seats`, if you sell team plans You can send attributes and usage events through the API, in batches, by CSV or with the SDK. NoChurn computes which attributes go with churn (relative risk, sample size, confidence), and AI explains the results and suggests actions. Treat it as correlation, not cause. See [custom data](/#insights) and [predicting churn with customer data](/blog/predict-churn-with-customer-data/). ## Setup Connect Stripe in one click with Stripe Connect. If you bill elsewhere, keep your billing and send subscriptions, payments and cancellations through the REST API. Send usage events from your backend as they happen. See the [quickstart](/docs/quickstart/). ## How NoChurn helps For AI and usage-based tools, NoChurn turns usage into an early warning, lets you pick offers by segment so a save does not cost more than it brings, and recovers failed payments on variable invoices. Every feature is on every plan, and the price depends only on MRR. See [pricing](/pricing/), or the pages for [developer tools](/use-cases/developer-tools/) and [B2B SaaS](/use-cases/b2b-saas/). --- # NoChurn for memberships and communities Source: https://www.nochurn.sh/use-cases/memberships-communities/ Paid memberships and communities sell belonging as much as content. Members join for a group, a creator, a club or a set of perks, and they often leave without complaint: they got busy, they stopped showing up, or money got tight for a month. NoChurn helps you keep the payment side from failing silently and gives members a better option than canceling when a break is all they need. ## Where memberships lose members ### Involuntary churn - **Small recurring charges on personal cards.** They fail for ordinary reasons (low balance, expired card) and members may not notice for weeks. - **Cards used only for this membership**, including prepaid and virtual cards that run out. - **Payment emails that look like spam.** A plain billing notice from a community the member rarely opens is easy to miss. ### Voluntary churn - **Fading participation.** The member stops attending events or reading posts, and the next charge feels like a waste. - **A temporary break.** Travel, a new job, a new baby: the member wants to step back, not leave for good. - **Tier mismatch.** A member on the top tier only uses the basics. - **Leaving with the creator or host.** If key people leave, members follow. That one needs a product answer, not a retention offer. ## How NoChurn handles it ### Failed payments NoChurn retries failed payments at times based on the member's local time and likely paydays, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). Recovery emails are written by AI for each member, in their language, sent by default on day 0, 3, 7 and 14, and reviewed before they go out, so the tone can match your community instead of sounding like a bank. Each email links to a hosted card update page; card data stays with Stripe. Replies are read and sorted, then answered or passed to you. See [failed payments](/#dunning). ### Churn score New members get a score from 0 to 100 at signup, based on payment method, signup source and any custom data you send. Members who remove their card before renewal are flagged, and a save flow starts before the payment fails. See [churn score](/#score). ### Cancel flow with a pause option Memberships are a natural fit for pausing. The cancel flow asks for a reason and shows a matching offer: - **Taking a break:** pause the membership for a month or more ([Stripe can pause payment collection](https://docs.stripe.com/billing/subscriptions/pause-payment)). - **Not using the full tier:** move to a lower tier. - **Too expensive right now:** a discount through a Stripe coupon. - **Something went wrong:** offer a call or a message from the host. A one-click "cancel now" button is always visible. Members who want to go can go, which is better for trust in a community than a maze. The hosted modal takes your colors, fonts and logo, or you can build your own screens with the headless API. See [cancel flows](/#cancel) and [pause vs discount offers](/blog/pause-vs-discount-retention-offers/). ### Win-back Former members receive win-back emails at 30, 60 and 90 days, written from their cancel reason. A member who left for a break can be invited back at the right time; one who left over price can hear about a cheaper tier. ### Custom data worth sending - `last_active_at`: last post, comment, login or event attended. - `key_feature_usage`: events attended, posts read, perks used. - `signup_source`: referral from another member, social, a launch campaign. - `plan` and `billing_interval`: tier, monthly or annual. - `coupon_used`: do launch-discount members stay after the discount ends? - `signup_date`: do some cohorts leave sooner? - `country` NoChurn computes which attributes go with churn and AI explains them. Correlation, not cause. See [custom data](/#insights). ## Setup If your membership is billed through your own Stripe account, connect it in one click with Stripe Connect. If you use another billing system, send subscriptions, payments and cancellations through the REST API. Add the cancel flow to your member account page with a script tag, or link to the hosted flow. If your membership platform controls the cancel page and you cannot change it, you can still use payment recovery and win-back. See the [quickstart](/docs/quickstart/). ## How NoChurn helps For memberships and communities, NoChurn recovers failed payments with emails in your own voice, offers a pause or lower tier before a cancel, keeps a one-click exit on every step, and invites former members back at 30, 60 and 90 days. Every feature is on every plan, priced by MRR. See [pricing](/pricing/), or the pages for [newsletters and media](/use-cases/newsletters-media/) and [online courses](/use-cases/online-courses/). --- # NoChurn for newsletters and digital media Source: https://www.nochurn.sh/use-cases/newsletters-media/ Paid newsletters and digital publications depend on readers who pay a small amount, month after month, for writing they value. Churn here is often quiet: a reader stops opening issues, or a card fails and nobody notices. Some readers only want a break, or a cheaper way to stay. NoChurn helps with each of these without getting in the way of readers who really want to leave. ## Where newsletters and media lose subscribers ### Involuntary churn - **Small charges that fail for ordinary reasons**: low balance, an expired card, a bank decline. - **Billing emails lost in a busy inbox.** A reader who gets many newsletters may never see the one about a failed payment. - **Annual renewals on old cards.** An annual plan bought a year ago can renew on a card that has since been replaced. ### Voluntary churn - **Reading less.** Open rates drop, and the subscription starts to feel like a backlog. - **Too many subscriptions.** Readers trim their list and keep only a few. - **A news cycle ends.** Some readers subscribe for a story or an election and leave when it is over. - **Price.** A monthly plan can feel expensive compared with an annual one. ## How NoChurn handles it ### Failed payments NoChurn retries failed payments based on the reader's local time and likely paydays, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). Recovery emails are written by AI, in the reader's language, sent by default on day 0, 3, 7 and 14 and reviewed before sending. They can be written in your publication's voice rather than a generic billing tone. Each email links to a hosted card update page; card data stays with Stripe. Replies are read and sorted, then answered or sent to you. See [failed payments](/#dunning) and [expiring cards](/blog/expiring-cards/). ### Churn score Each new subscriber gets a score from 0 to 100 at signup, based on payment method, signup source and custom data. If a reader removes their card before an annual renewal, NoChurn flags it and starts a save flow before the payment fails. See [churn score](/#score). ### Cancel flow with offers readers accept The cancel flow asks why the reader is leaving and shows one offer that fits: - **Reading less right now:** pause the subscription. - **Too expensive:** a discount through a Stripe coupon, or a switch to an annual or lower-priced plan. - **Too many emails:** a switch to a lighter plan, if you offer one. - **Not interested anymore:** no offer, a clean exit. A one-click "cancel now" button is visible on every step. The hosted modal matches your publication's design, with themes, fonts, colors, logo and custom CSS, or you can build it yourself on the headless API. See [cancel flows](/#cancel). ### Win-back Readers who cancel receive win-back emails at 30, 60 and 90 days, written from their cancel reason. A reader who left because of price hears a different message from one who left because they were not reading. ### Custom data worth sending - `last_active_at`: last issue opened or article read. - `key_feature_usage`: issues opened, articles read, podcast episodes played. - `signup_source`: a free-to-paid upgrade, a social post, a referral, a partner. - `plan` and `billing_interval`: monthly or annual. - `coupon_used`: do readers who joined on a promotion stay after it ends? - `signup_date`: do readers who joined around a big story leave sooner? - `country` NoChurn computes which attributes go with churn (relative risk, sample size, confidence) and AI explains the result. It is correlation, not cause. See [custom data](/#insights). ## Setup If your subscriptions are billed through your own Stripe account, connect it in one click with Stripe Connect. If your billing runs elsewhere, send subscriptions, payments and cancellations through the REST API. Whether you can add the cancel flow depends on whether you control your account or cancel page; if your publishing platform owns that page, you can still use payment recovery, the churn score and win-back. See the [quickstart](/docs/quickstart/). ## How NoChurn helps For newsletters and digital media, NoChurn recovers failed payments with emails that sound like your publication, offers a pause or a cheaper plan before a cancel, keeps a one-click exit visible, and shows which reading habits go with churn. Every feature is on every plan, priced by MRR, with no share of recovered revenue. See [pricing](/pricing/), or the pages for [memberships and communities](/use-cases/memberships-communities/) and [consumer subscriptions](/use-cases/consumer-subscriptions/). --- # NoChurn for online courses and edtech Source: https://www.nochurn.sh/use-cases/online-courses/ Online courses and edtech subscriptions sell progress. Learners join with a goal (a new skill, an exam, a language) and stay while they feel they are moving forward. When they stall, the subscription starts to look like a reminder of something they did not finish. Payment plans and monthly subscriptions also bring the usual card failures. NoChurn handles both. ## Where online courses and edtech lose learners ### Involuntary churn - **Payment plans and monthly fees on personal cards**, which fail for low balance, expiry or bank declines. - **Students and young learners** who use prepaid or virtual cards. - **Card updates nobody gets to.** A learner in the middle of a busy term may ignore a billing email. ### Voluntary churn - **Stalled progress.** The learner falls behind, stops logging in, then cancels. - **Goal reached.** They passed the exam or finished the course. That is a success, and the right move is a clean exit or a next step, not a discount. - **Busy periods.** Exams, holidays and work deadlines push study aside for a while. - **Wrong level.** The content feels too easy or too hard. ## How NoChurn handles it ### Failed payments NoChurn retries failed payments based on the learner's local time and likely paydays, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). Recovery emails are written by AI for each learner, in their language, sent by default on day 0, 3, 7 and 14 and reviewed before they go out. They link to a hosted card update page; card data stays with Stripe. Replies are read, sorted, and answered or sent to your team. See [failed payments](/#dunning). ### Churn score New learners get a score from 0 to 100 at signup, based on payment method, signup source and custom data such as the course they chose. Prepaid and disposable virtual cards start as high risk, and the levels are then learned from your own history. If a learner removes their card before renewal, NoChurn flags it and starts a save flow before the payment fails. See [churn score](/#score). ### Cancel flow with study-friendly offers The cancel flow asks for a reason and shows a matching offer: | Reason | Suitable offer | | --- | --- | | No time right now | Pause the subscription until after exams or holidays | | Too expensive | Discount through a Stripe coupon, or a lower plan | | Content not right for me | Book a call to find the right level | | I reached my goal | No offer, a clean exit | A one-click "cancel now" button is always visible. The hosted modal takes your brand, or the headless API lets you build the flow inside your learning app on web, iOS or Android. See [cancel flows](/#cancel) and [cancel flow best practices](/blog/cancel-flow-best-practices/). ### Win-back Learners who cancel receive win-back emails at 30, 60 and 90 days, written from their reason. A learner who paused for exams or left because they had no time can be invited back when things are calmer. ### Custom data worth sending - `activated_at`: first lesson completed. Do learners who never start cancel first? - `last_active_at`: last lesson or practice session. - `key_feature_usage`: lessons completed, quizzes taken, streak length. - `signup_source`: ads, search, a partner school, a referral. - `plan` and `billing_interval` - `trial_days` and `coupon_used` - the course or track, as your own attribute name NoChurn computes which attributes go with churn and AI explains what it finds. Correlation, not cause: a link between a stalled streak and canceling does not prove one causes the other. See [custom data](/#insights). ## Setup Connect Stripe in one click with Stripe Connect. Payment plans billed as Stripe subscriptions are handled like any other subscription. If you use another billing system, keep it and send subscriptions, payments and cancellations through the REST API. Send learning activity from your platform's backend. See the [quickstart](/docs/quickstart/). ## How NoChurn helps For online courses and edtech, NoChurn recovers failed payments, offers pauses around busy periods, keeps a one-click exit for learners who are done, and shows which learning habits go with churn. Every feature is on every plan; you pay by MRR band, never a share of recovered revenue. See [pricing](/pricing/), or the pages for [mobile apps](/use-cases/mobile-apps/) and [memberships and communities](/use-cases/memberships-communities/). --- # NoChurn for developer tools and API products Source: https://www.nochurn.sh/use-cases/developer-tools/ Developer tools and API products are bought by people who expect to integrate things themselves. They sign up fast, try the API, and either build on it or move on. Many accounts start as one developer on a personal card and grow into a team on a company card. NoChurn fits this: everything is available through a REST API, signed webhooks and an MCP server, and the churn signals come from the usage data you already have. ## Where developer tools lose customers ### Involuntary churn - **Personal cards on side projects.** A developer pays with a personal card, then the card expires or is replaced. - **Company cards that change owners.** The engineer who added the card leaves, and failed payment emails go to an inbox nobody reads. - **Usage-based invoices.** A traffic spike produces a larger charge that the card declines. ### Voluntary churn - **The integration never shipped.** The developer signed up, made a few test calls, and the project stalled. - **The project ended.** A hackathon, a prototype, a client job: usage stops with it. - **Switching or building in-house.** Developers can replace a tool quickly once they decide to. - **Plan too large.** A team pays for capacity it does not use. ## How NoChurn handles it ### Failed payments NoChurn retries failed payments based on the customer's local time and likely paydays, or you can keep [Stripe Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries). AI-written recovery emails go out by default on day 0, 3, 7 and 14, reviewed before sending, and link to a hosted card update page where card data stays with Stripe. Replies are read and sorted, then answered or sent to your team. See [failed payments](/#dunning). ### Churn score New accounts get a score from 0 to 100 at signup, based on payment method, signup source and custom data. Disposable virtual cards, common for trying tools, start as high risk; levels are then learned from your own history. When a customer removes their card before renewal, NoChurn flags it and starts a save flow before the payment fails. See [churn score](/#score). ### Headless cancel flow Developers often dislike modals. With the headless API you fetch the cancel reasons and offers for a customer and post back the answer, then render it in your own dashboard or desktop app. Offers that tend to suit developer tools: - **Project ended:** pause the subscription. - **Paying for more than I use:** downgrade to a smaller plan. - **Too expensive:** discount through a Stripe coupon. - **Integration problems:** book a call with an engineer. A one-click "cancel now" option stays on every step. If you prefer, the hosted modal works too, with custom CSS. See [cancel flows](/#cancel). ### Win-back Customers who cancel get win-back emails at 30, 60 and 90 days, written from their reason. A developer whose project ended can hear from you when they may be starting the next one. ### Custom data worth sending Usage is the strongest signal for API products: - `activated_at`: first successful API call or first deploy. Do accounts that never reach it cancel first? - `key_feature_usage`: API calls, builds, deploys, events, active projects. - `last_active_at`: last API call or dashboard login. - `seats`: how many developers on the account. - `signup_source`: docs, search, a community post, a marketplace. - `plan` and `billing_interval` - `support_tickets`: do accounts that open tickets stay or leave? Send them through the API, in batches, by CSV or with the SDK. NoChurn computes which attributes go with churn (relative risk, sample size, confidence), and AI explains the result. Correlation, not cause. See [custom data](/#insights). ## Setup Connect Stripe in one click with Stripe Connect, or keep your own billing and send subscriptions, payments and cancellations through the REST API. Signed webhooks keep your own systems in sync with what happens in NoChurn. You can also connect the NoChurn [MCP server](/#mcp) to a coding agent such as Claude Code or Cursor and let it add the cancel flow, webhooks and custom data to your app. See the [API reference](/docs/api/). ## How NoChurn helps For developer tools and API products, NoChurn offers an API-first way to recover failed payments, run a cancel flow in your own UI, and learn which usage patterns go with churn. Every feature is on every plan, and the price depends only on MRR. See [pricing](/pricing/), or the pages for [AI and usage-based tools](/use-cases/ai-tools/) and [B2B SaaS](/use-cases/b2b-saas/). --- # NoChurn for product-led SaaS Source: https://www.nochurn.sh/use-cases/plg-saas/ Product-led SaaS sells through the product itself. People sign up without talking to sales, start on a free plan or a trial, and upgrade with a card when the product proves itself. The same self-serve path works in reverse: they can downgrade, stop paying or cancel without anyone noticing until the MRR chart moves. NoChurn is built for that kind of business, where you have many small accounts and no account manager for each one. ## How people pay in product-led SaaS - **Card on file after a trial or a free plan.** Most paid accounts start with one person entering a card, often a personal card or a team lead's company card. - **Monthly first, annual later.** Self-serve buyers tend to try monthly billing before they commit to a year, so a large part of revenue renews every month. - **Seats or usage that move on their own.** Teams add and remove seats, or usage-based charges change from month to month, without a sales conversation. - **Trials with or without a card.** Some products ask for a card upfront, others let people try first. On Stripe, a trial without a payment method can be set to create an invoice, cancel or pause when it ends ([Stripe trials, accessed November 2026](https://docs.stripe.com/billing/subscriptions/trials/free-trials)). Each choice changes what "churn" means at the end of the trial. ## Why product-led accounts churn ### Involuntary churn - **The one card on the account fails.** A self-serve account usually has one payment method and one admin. If the card expires or is declined, the account lapses unless that person acts. See [expiring cards](/blog/expiring-cards/) and [involuntary churn](/blog/involuntary-churn/). - **Cards that were never meant to last.** Prepaid and virtual cards are common at signup, especially for trials. See [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). - **Authentication on renewals.** Some renewals in Europe ask the cardholder to confirm the payment, which an absent admin will not do. See [authentication on renewals](/blog/sca-authentication-required-renewals/). ### Voluntary churn - **Never reaching the moment that matters.** Accounts that upgraded early but never set up the core workflow are the easiest to lose at the next renewal. - **The champion leaves.** In a team account, the person who brought the product in moves on, and nobody else feels responsible for it. - **Paying for more than they use.** Seats or a tier chosen during an enthusiastic first week no longer match the team. - **A cheaper tool or the free plan is "enough".** Some accounts do not leave the product, they just stop paying for it. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). Recovery emails are written by AI for each account, and you can review them before they go out. Each email links to a hosted card update page, so the admin can fix the card in a minute without logging in to your billing settings. Card data stays with your payment provider; NoChurn never sees card numbers. If you bill with [Chargebee](/integrations/chargebee/), [Recurly](/integrations/recurly/) or [Paddle](/integrations/paddle/), the provider keeps its own dunning, and NoChurn adds the AI emails and the card update link next to it. See [failed payments](/#dunning). ### Churn score from the first signup Product-led funnels are wide: many signups, few conversations. NoChurn gives each customer a churn score from 0 to 100 at signup and updates it on every change, using payment method, signup source and any custom data you send. That lets you spend human attention on the accounts most likely to leave, instead of on whoever writes in first. When a customer removes their card before a renewal, the score goes up so you can act before the payment fails. See [churn score](/#score). ### A cancel flow inside the product Self-serve customers cancel from your settings page, so that is where the flow belongs. NoChurn shows a reason, then an offer that matches it: | Reason | Offer that fits | | --- | --- | | Too many seats or too much plan | Plan change to a smaller tier | | Too expensive | Discount | | Not using it right now | Pause | | Switching to another tool | Ask what is missing, then let them go | A one-click "cancel now" button stays visible on every step, so the customer is never stuck. Use the hosted modal with your colors and logo, or draw the screens yourself with the headless API so the flow looks like the rest of your product. Coding agents can wire it up through the NoChurn [MCP server](/#mcp). See [cancel flows](/#cancel), [cancel flow best practices](/blog/cancel-flow-best-practices/) and [pause vs discount](/blog/pause-vs-discount-retention-offers/). ### Win-back Accounts that cancel get win-back emails at 30, 60 and 90 days, written from their cancel reason. An account that left because a feature was missing can hear about it when it ships; an account that left over price can hear about a smaller plan. See [win-back](/#winback). ### Custom data worth sending Product-led companies already track product usage. Sending a handful of those attributes through the API is usually one call per change: - `activated_at`: did the account reach your activation milestone, and when? - `key_feature_usage`: the action that defines a healthy account in your product. - `last_active_at`: how long an account stays quiet before it cancels. - `seats` and `active_seats`: is the account paying for people who never log in? - `signup_source`: organic, paid ads, a template gallery, a referral. - `trial_days` and `had_card_at_trial`: does a trial with a card convert and stay differently? - `plan` and `billing_interval` NoChurn shows which attributes go with churn, with the sample size behind each result. This is correlation, not causation: use it to choose who gets which offer and where to improve onboarding, not as proof of why people leave. See [custom data](/#insights) and [predicting churn with customer data](/blog/predict-churn-with-customer-data/). ## Integrations that fit - [Stripe](/integrations/stripe/) in one click, the most common setup for self-serve billing. - [Paddle](/integrations/paddle/), [Lemon Squeezy](/integrations/lemon-squeezy/) or [Polar](/integrations/polar/) if a merchant of record bills for you. Disputes are then handled by the merchant of record and shown read only in NoChurn. - [Any billing by API](/integrations/api/) if you built your own. - [Intercom](/integrations/intercom/) or [Crisp](/integrations/crisp/) for in-app support conversations, read only, used in the score and in dispute evidence. ## What to watch out for - **Free plans are not churn.** Decide whether a paid account moving to your free plan counts as a cancel, and send it consistently so the numbers mean something. See [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). - **Do not hide the cancel button.** A self-serve customer who cannot find how to leave will leave angrier, and some rules require an easy cancel. See [click-to-cancel rules](/blog/click-to-cancel-rules/). - **Trial conversion is a separate problem.** NoChurn helps once there is a subscription. For converting trials, see [trial to paid conversion](/blog/trial-to-paid-conversion/). ## Pricing Every feature is on every plan, and the price depends only on your MRR: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the pages for [B2B SaaS](/use-cases/b2b-saas/) and [developer tools](/use-cases/developer-tools/). --- # NoChurn for recurring donations Source: https://www.nochurn.sh/use-cases/nonprofits-donations/ Monthly giving is a subscription in everything but name. A donor sets up a recurring gift once, and from then on it renews every month on a card or a direct debit. Most lapsed monthly gifts are not a decision to stop supporting you: a card expired, a bank account changed, or money was tight for a month. NoChurn helps organisations that bill recurring gifts on Stripe, GoCardless, Mollie or their own system keep those gifts going, with a tone that fits donors rather than customers. This page is about operations, not tax or legal matters. NoChurn does not issue tax receipts and does not advise on what you may or must tell donors in your country; check that with your own adviser. ## How donors pay - **Cards**, usually through a donation form on your site, billed as a monthly subscription. - **Direct debit** (for example SEPA in the eurozone or Bacs in the UK) through a provider such as [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/). Direct debit avoids card expiry, but a donor can cancel the mandate at their bank. See [mandate cancelled](/blog/gocardless-mandate-cancelled/). - **A donor CRM or fundraising platform** that holds the schedule and calls a payment provider. If that is your setup, you send gifts, payments and cancellations to NoChurn through the [REST API](/integrations/api/). ## Why recurring gifts lapse ### Failed gifts - **Expired or replaced cards.** A donor who gave two years ago has probably had a new card since. See [expiring cards](/blog/expiring-cards/). - **Insufficient funds near the end of the month.** Small gifts fail for ordinary reasons and the donor may not notice for weeks. - **Direct debit failures and cancelled mandates.** A bank switch or a tidy-up of standing payments can end a mandate without the donor meaning to stop. See [GoCardless failed payments](/blog/gocardless-failed-payments/) and [SEPA direct debit failures](/blog/mollie-sepa-direct-debit-failures/). ### Donors who choose to stop - **Money is tight.** The most common reason, and often temporary. - **They give elsewhere now.** A new cause or a one-off emergency appeal takes the budget. - **They lost touch with what the gift does.** No news, no sense of impact, and the charge starts to feel like a forgotten subscription. - **Something went wrong.** A wrong amount, a duplicated charge or an unwelcome phone call. ## How NoChurn handles it ### Failed gifts On Stripe, NoChurn retries failed card payments at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). On other providers, the provider's own retry rules stay in place and NoChurn adds emails and a link to update payment details next to them. Recovery emails are written by AI and can be reviewed before they go out. That review step matters here: a message to a donor should thank them first and explain plainly that the gift did not go through, not read like an overdue invoice. Each email links to a hosted page where the donor updates their card. Card data stays with your payment provider; NoChurn never sees card numbers. See [failed payments](/#dunning) and [dunning email templates](/blog/dunning-email-templates/). ### A cancel flow that respects donors Donors must be able to stop giving easily. NoChurn's cancel flow keeps a one-click "cancel now" button visible on every step, and a cancel that is asked for is carried out. Before that, it can ask why and offer something that fits: | Reason | Offer that fits | | --- | --- | | Money is tight right now | Pause the gift for a few months | | I want to give less | Lower the monthly amount (a plan change) | | I prefer to give once a year | Switch to an annual gift, if you offer one | | Something went wrong | Pass it to your supporter care team | A discount makes no sense for a donation, so you can leave that offer out. The hosted modal takes your colors, fonts and logo, or you can build the screens in your own donation pages with the headless API. See [cancel flows](/#cancel) and [pause vs discount](/blog/pause-vs-discount-retention-offers/). ### Win-back, gently Donors who stop get win-back emails at 30, 60 and 90 days, written from the reason they gave. A donor who paused because money was tight should hear something very different from one who was unhappy. You can review the AI drafts before they go out. Donors who asked not to be contacted must not receive them; keeping NoChurn in line with those preferences is your responsibility, not something NoChurn decides for you. See [win-back](/#winback). ### Chargebacks on donations A donor who does not recognise a charge on their statement may dispute it with their bank. On Stripe and Braintree, NoChurn gathers evidence automatically (the donor's cancel flow answers, emails sent, support conversations) and drafts a reply with AI, which is sent only after a person on your team has reviewed it. On Stripe, early fraud warnings show up with a one-click refund, which is usually the right move for a donation made with a stolen card. Disputes on other providers are shown read only. See [chargebacks](/#disputes) and [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/). ### Custom data worth sending The churn score (0 to 100 at signup and on every change) works with whatever you send. Keep it to giving behaviour; NoChurn does not need sensitive personal information about donors, and you should not send it. - `signup_source`: campaign, appeal, event, peer fundraising page. - `gift_amount` and `billing_interval` - `months_giving`: how long the donor has given. - `last_update_sent_at`: when they last received news of impact. - `upgraded_amount`: did they increase the gift after an appeal? - `country` NoChurn shows which attributes go with lapsed gifts. This is correlation, not causation: a campaign whose donors lapse sooner may simply reach a different audience. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/) for card donations, in one click. - [GoCardless](/integrations/gocardless/) and [Mollie](/integrations/mollie/) for direct debit. - [Any billing by API](/integrations/api/) for a donor CRM or fundraising platform. - [Zendesk](/integrations/zendesk/), [Help Scout](/integrations/help-scout/) or [HubSpot](/integrations/hubspot/) for supporter care conversations, read only. ## What to watch out for - **Tone over tactics.** Donors give, they do not buy. Review AI drafts until the voice is right, and keep messages short. - **Consent and contact preferences are yours to manage.** Send only to donors you may contact, and keep NoChurn in line with the preferences in your CRM. - **Tax receipts and gift declarations stay in your existing tools.** NoChurn does not produce them. - **When NoChurn is not the right tool.** If most of your income is one-off gifts rather than recurring ones, a donor CRM with good appeal tools will do more for you. ## Pricing Every feature is on every plan, and the price depends only on your monthly recurring revenue (here, the total of monthly gifts): free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered gifts. See [pricing](/pricing/), or the page for [memberships and communities](/use-cases/memberships-communities/). --- # NoChurn for fintech subscriptions Source: https://www.nochurn.sh/use-cases/fintech/ Fintech products increasingly sell subscriptions on top of the core service: a premium tier on a current account, a paid plan in a budgeting or investing app, a subscription for accounting, invoicing or expense software. The subscription side behaves like any other, but the setting is more sensitive. Customers read payment emails carefully, they expect cancellations to be clean, and a message that looks like phishing can damage trust in the whole product. NoChurn handles the subscription side. It is not a compliance tool, and this page makes no claim that using NoChurn meets any regulatory requirement in your market. Your own compliance team decides what you may send, store and offer. ## How fintech customers pay - **From a balance you hold.** Many apps charge the subscription fee from the customer's account or wallet inside the product. Billing then lives in your own ledger, and you send subscriptions, payments and cancellations to NoChurn through the [REST API](/integrations/api/). - **By card, through Stripe or Braintree,** common for finance software sold on the web. See [Stripe](/integrations/stripe/) and [Braintree](/integrations/braintree/). - **Through the App Store or Google Play,** for mobile-first apps. Apple and Google run billing, retries and cancellation; NoChurn reads those events. See [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/). - **By direct debit** for some European business tools, through [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/). ## Why fintech subscribers churn ### Involuntary churn - **Not enough balance when the fee is due.** When the fee comes from a balance you hold, a failed charge usually means the account is low, not that a card is broken. Retrying at the wrong time just fails again. - **Cards replaced after fraud alerts.** Finance-minded customers react quickly to suspicious activity and often get new cards. - **Store billing issues** on iOS and Android, handled by Apple and Google. See [App Store billing retry](/blog/app-store-billing-retry-grace-period/) and [Google Play grace period](/blog/google-play-grace-period-account-hold/). ### Voluntary churn - **The premium perk was a one-time need.** Travel insurance before a trip, higher limits for one large transfer, a tax-season feature. - **The customer moved their main account elsewhere.** The subscription goes when the salary stops landing in your app. - **Price sensitivity.** People who use a budgeting app are, by definition, watching their spending. - **Low engagement.** The app gets linked, then forgotten. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed card payments at times based on the decline reason and likely paydays, which suits customers who are short of funds until payday. On other billing tools the provider's own retries stay in place. If you bill from an internal balance, you decide when to retry and send the result to NoChurn; NoChurn then runs the emails. Recovery emails are written by AI and can be reviewed before they go out. In fintech, that review step is worth using: you can keep the wording close to your existing communications, avoid anything that looks like a request for credentials, and make sure each email points only to your own domain or NoChurn's hosted card update page. Card data stays with your payment provider; NoChurn never sees card numbers. See [failed payments](/#dunning). ### Cancel flow The flow asks for a reason and shows a matching offer: | Reason | Offer that fits | | --- | --- | | I only needed it for one thing | Pause until the next time they need it | | Too expensive | Move to a lower tier, or a discount | | I moved my main account | Ask what would bring it back, then let them go | | Something went wrong | Pass it to support | A one-click "cancel now" button is visible on every step, and a cancel that is asked for is carried out. For an app where the customer already trusts you with money, that matters more than any offer. Most fintech teams draw the flow natively with the headless API, in the app's own design; a hosted modal with your colors and logo also exists for web products. For subscriptions bought through Apple or Google, your app can show the NoChurn flow first, and the store's own cancel button always works. See [cancel flows](/#cancel) and [click-to-cancel rules](/blog/click-to-cancel-rules/). ### Churn score Each customer gets a score from 0 to 100 at signup and on every change, from payment method, signup source and the custom data you send. When a customer removes their card before a renewal, the score goes up so you can act before the charge fails. See [churn score](/#score). ### Chargebacks On Stripe and Braintree, NoChurn gathers evidence for each dispute automatically (cancel flow answers, emails sent, usage, support conversations) and drafts a reply with AI. Nothing is sent until a person has reviewed it. On Stripe, early fraud warnings appear with a one-click refund. Disputes on other providers are shown read only. See [chargebacks](/#disputes) and [winning Stripe chargebacks](/blog/win-chargebacks-stripe/). ### Win-back Customers who cancel get win-back emails at 30, 60 and 90 days, written from their cancel reason: someone who paused for a trip hears about the next one, someone who left over price hears about a cheaper tier. ### Custom data worth sending You hold a lot of financial data. NoChurn does not need it, and you should not send it: no balances, no transactions, no account numbers. Product behaviour is enough: - `last_active_at`: last app open or login. - `key_feature_usage`: how often the premium feature is used (count, not amounts). - `is_primary_account`: a yes/no flag you compute yourself, if salary deposits land in your product. - `signup_source` and `referral` - `plan` and `billing_interval` - `country` NoChurn shows which attributes go with churn, with sample sizes. Correlation, not causation. See [custom data](/#insights). ## Integrations that fit - [Any billing by API](/integrations/api/) when fees come from an in-app balance. - [Stripe](/integrations/stripe/) or [Braintree](/integrations/braintree/) for card billing on the web. - [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/) for in-app subscriptions. - [Intercom](/integrations/intercom/) or [Zendesk](/integrations/zendesk/) for support conversations, read only. ## What to watch out for - **Run every template past compliance.** AI drafts are reviewable for a reason; use that step. - **Keep data minimal.** Send behaviour and flags, never financial records. - **Store subscribers.** Retries and the cancel button stay with Apple and Google. - **When NoChurn is not the right tool.** If your revenue comes from transaction fees or interest rather than subscriptions, churn is an engagement problem, and a product analytics tool will serve you better. ## Pricing Every feature is on every plan, and the price depends only on your MRR: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the pages for [consumer subscriptions](/use-cases/consumer-subscriptions/) and [mobile apps](/use-cases/mobile-apps/). --- # NoChurn for streaming services Source: https://www.nochurn.sh/use-cases/streaming/ Streaming subscriptions are some of the easiest to start and the easiest to stop. A viewer signs up for one series, a fan subscribes for a sports season, a listener joins for a podcast network's back catalogue. When that reason runs out, so does the subscription. Billing is also spread across channels: some subscribers pay on your website, others through the App Store or Google Play, and NoChurn has to treat each one according to who actually runs their billing. ## How streaming subscribers pay - **On the web, by card,** usually through [Stripe](/integrations/stripe/) or [Braintree](/integrations/braintree/), sometimes with a merchant of record such as [Paddle](/integrations/paddle/). - **Inside iOS and Android apps,** through the App Store and Google Play. Apple and Google charge the customer, retry failed payments and own the cancel button ([Apple subscriptions](https://developer.apple.com/app-store/subscriptions/), [Google Play subscriptions](https://developer.android.com/google/play/billing/subscriptions), accessed November 2026). - **Through TV platforms or partner bundles** that bill on their own. NoChurn has no connector for those; you can send their subscriptions through the [REST API](/integrations/api/) if you receive the events. - **Monthly, annual and seasonal plans.** Sports and event services often sell a season pass next to a monthly plan. ## Why streaming subscribers churn ### Involuntary churn - **Small monthly charges on cards that expire.** The viewer barely notices the charge, so they also barely notice when it fails. See [expiring cards](/blog/expiring-cards/). - **Prepaid and virtual cards used for a free trial.** See [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). - **Store billing problems.** On iOS, Apple retries a failed renewal for up to 60 days and can keep access during an optional grace period ([Apple, accessed November 2026](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions/)). On Android, Google uses a grace period followed by account hold ([Android Developers, accessed November 2026](https://developer.android.com/google/play/billing/lifecycle/subscriptions)). See [App Store billing retry](/blog/app-store-billing-retry-grace-period/) and [Google Play grace period and account hold](/blog/google-play-grace-period-account-hold/). ### Voluntary churn - **The show ended.** The most predictable cancel in subscriptions: finish the series, cancel the plan. - **The season ended.** Sports and event streaming see subscribers leave in the off-season and come back for the next one. - **Too many services.** Viewers rotate subscriptions to keep their monthly total down. - **Price changes.** A price increase is a natural moment to reconsider every subscription at once. ## How NoChurn handles it ### Failed payments on the web On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). On other billing tools, the provider's own dunning stays in place and NoChurn adds AI-written emails and a card update link next to it. Emails can be reviewed before they go out. The hosted card update page works on a phone, which is where most streaming customers will open it. See [failed payments](/#dunning). ### App Store and Google Play subscribers NoChurn reads App Store and Google Play events: renewals, billing issues, cancellations and refunds land in the same customer timeline, score and win-back as your web subscribers. Payment retries, the grace period and the cancel button stay with Apple and Google. For a store subscriber with a billing issue, NoChurn tells them in your app or by email and points them to the store's subscription page; it does not retry or cancel itself. See [App Store](/integrations/app-store/), [Google Play](/integrations/google-play/) and [App Store server notifications](/blog/app-store-server-notifications-churn/). ### Cancel flow: pause beats goodbye Streaming is where a pause offer fits best. A viewer who just finished a series does not need a discount; they need a reason to come back when the next one arrives. | Reason | Offer that fits | | --- | --- | | I finished what I wanted to watch | Pause for one to three months | | The season is over | Pause until the next season, or a cheaper off-season plan | | Too expensive | Plan change to a cheaper tier, or a discount | | Technical problems | Pass it to support | A one-click "cancel now" button is visible on every step, and a cancel that is asked for is carried out. On the web, use the hosted modal with your colors and logo. On TV and mobile apps, draw the screens yourself with the headless API. For App Store and Google Play subscribers, your app can show the flow before linking to the store's subscription page, and the store's cancel button always works. See [cancel flows](/#cancel), [pause vs discount](/blog/pause-vs-discount-retention-offers/) and [App Store cancellation](/blog/app-store-cancellation-retention/). ### Win-back timed to your catalogue Subscribers who cancel get win-back emails at 30, 60 and 90 days, written from their cancel reason. Someone who left because the show ended can hear about a new season; someone who left over price can hear about a cheaper plan. You can review the AI drafts before they go out. See [win-back](/#winback) and [win-back email examples](/blog/win-back-email-examples/). ### Churn score Each subscriber gets a score from 0 to 100 at signup and on every change, from payment method, signup source and your custom data. A subscriber who removes their card before a renewal gets a higher score, so you can act before the payment fails. See [churn score](/#score). ### Custom data worth sending - `signup_title`: the show, event or playlist that brought them in. - `last_watched_at` or `last_played_at` - `hours_last_30_days` - `titles_started` and `titles_finished` - `signup_source` and `trial_days` - `platform`: web, iOS, Android, TV, as your own attribute - `plan` and `billing_interval` NoChurn shows which attributes go with churn, with sample sizes. Correlation, not causation: a title whose subscribers cancel quickly may simply be a short series. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/) for web billing, in one click. - [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/) for in-app subscribers. - [Any billing by API](/integrations/api/) for TV platforms and partner channels you receive events from. - [Zendesk](/integrations/zendesk/) or [Intercom](/integrations/intercom/) for playback and billing tickets, read only. ## What to watch out for - **Store subscribers are Apple's and Google's to bill.** NoChurn warns and points; it does not retry or cancel them. - **Matching across channels.** A subscriber who paid on the web and later in the app needs your own user ID on both, or NoChurn sees two customers. Google does not share the customer's email, so send the obfuscated account ID. - **Seasonal churn is normal.** Do not read the off-season as a failure; compare season to season. - **When NoChurn is not the right tool.** Ad-supported free streaming has no subscription to save; an engagement tool fits better there. ## Pricing Every feature is on every plan, and the price depends only on your MRR: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the pages for [newsletters and media](/use-cases/newsletters-media/) and [mobile apps](/use-cases/mobile-apps/). --- # NoChurn for health and fitness apps Source: https://www.nochurn.sh/use-cases/health-fitness-apps/ Health and fitness apps sell a habit: workouts, meditation, sleep, running plans, nutrition coaching. People subscribe at a moment of high motivation and cancel when that motivation fades, when they get injured, or when they decide they can do it on their own. Billing is often split between the web and the app stores. NoChurn helps keep the payment side working, gives members a pause instead of a cancel when they need a break, and predicts churn from usage, not from anything about their body. **NoChurn does not need health data, and you should not send it.** No weights, heart rates, diagnoses, cycles, moods or sleep scores. Usage counts such as "workouts completed this month" are enough for everything on this page. ## How subscribers pay - **Inside the app,** through the App Store and Google Play. Apple and Google charge, retry and own the cancel button. NoChurn reads those events. See [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/). - **On the web, by card,** often through [Stripe](/integrations/stripe/), sometimes with [Paddle](/integrations/paddle/) as merchant of record. - **Annual plans after a trial,** very common in this category, which makes the one renewal a year a big moment. See [annual renewal reminders](/blog/annual-plan-renewal-reminders/). - **Coaching and studio memberships** billed monthly by card or direct debit, through Stripe, [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/). ## Why health and fitness subscribers churn ### Involuntary churn - **The card used for the trial has changed** by the time the annual plan renews. See [expiring cards](/blog/expiring-cards/). - **Prepaid and virtual cards** used to try the app without commitment. See [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). - **Store billing issues.** On iOS and Android, Apple and Google retry and may hold access for a while; your app should tell the user. See [App Store billing retry](/blog/app-store-billing-retry-grace-period/) and [Google Play grace period](/blog/google-play-grace-period-account-hold/). ### Voluntary churn - **Motivation fades.** Sessions drop from four a week to one, then zero, and the renewal feels like a reminder of a broken resolution. - **A temporary break.** Injury, illness, travel, a new baby, exam season. The member wants to stop for a while, not forever. - **Reaching the goal.** Some people cancel because the plan worked, which is a different conversation from failure. - **"I can do it on my own now."** A free app or a routine they already know replaces the paid plan. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed web payments at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). On other billing tools, their own dunning stays and NoChurn adds AI emails and a card update link next to it. Emails can be reviewed before they go out, so the tone can stay encouraging rather than sound like a bill collector. The hosted card update page works on a phone. Card data stays with your payment provider. See [failed payments](/#dunning). For App Store and Google Play subscribers, NoChurn does not retry. It tells the user in your app or by email and points them to the store's subscription page. ### Cancel flow built around a break | Reason | Offer that fits | | --- | --- | | Injured, ill or taking a break | Pause for one to three months | | Not using it enough | Plan change to a cheaper tier with fewer features | | Too expensive | Discount | | Reached my goal | A lighter maintenance plan, or let them go with thanks | Wording matters here. A member who cancels because of an injury should never see a cheerful "are you sure?" screen. Write reason labels that let people say "taking a break" without explaining why; you do not need to know. A one-click "cancel now" button is visible on every step, and a cancel that is asked for is carried out. Most apps draw the flow natively with the headless API, in SwiftUI, Jetpack Compose or a cross-platform framework; the hosted modal suits web billing. For store subscribers, your app shows the flow first and the store's cancel button always works. See [cancel flows](/#cancel), [pause vs discount](/blog/pause-vs-discount-retention-offers/) and [Google Play cancellation survey](/blog/google-play-cancellation-survey/). ### Churn score from usage Each subscriber gets a score from 0 to 100 at signup and on every change, from payment method, signup source and your custom data. In fitness, a fall in sessions usually comes before a cancel, so sending a simple usage count gives the score something to work with. A subscriber who removes their card before a renewal also gets a higher score. See [churn score](/#score). ### Win-back Former members get win-back emails at 30, 60 and 90 days, written from their cancel reason. A member who paused for an injury can be invited back gently; one who left over price can hear about a cheaper plan. You can review every draft. See [win-back](/#winback). ### Custom data worth sending (and what to leave out) Send behaviour, not bodies: - `sessions_last_30_days`: workouts, meditations, lessons, as a count. - `last_session_at` - `streak_days`: the current streak, if your app has one. - `program_started` and `program_completed`: yes/no, or a date. - `signup_source`: paid social, app store search, a referral, a coach. - `trial_days` and `plan` - `platform`: web, iOS or Android, as your own attribute Leave out anything a person would consider health information. NoChurn shows which attributes go with churn, with sample sizes. Correlation, not causation: a cohort that churns more may just have signed up at a time of year when people try many apps. See [custom data](/#insights). ## Integrations that fit - [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/) for in-app subscriptions. - [Stripe](/integrations/stripe/) for web billing, in one click. - [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/) for studio or coaching memberships on direct debit. - [Intercom](/integrations/intercom/) or [Crisp](/integrations/crisp/) for in-app support, read only. Support messages can contain health details people chose to share; NoChurn treats message text as customer content and reads it only when needed, such as dispute evidence. ## What to watch out for - **No health data, ever.** It is not needed for any NoChurn feature. - **Store subscribers.** Retries, grace periods and the cancel button stay with Apple and Google. - **Pause should be a real pause.** Make sure your app actually stops charging and keeps the member's progress. - **When NoChurn is not the right tool.** For a gym billed at the front desk with one-off passes, a gym management system is the better fit. ## Pricing Every feature is on every plan, and the price depends only on your MRR: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the pages for [mobile apps](/use-cases/mobile-apps/) and [consumer subscriptions](/use-cases/consumer-subscriptions/). --- # NoChurn for marketplaces and platforms with seller subscriptions Source: https://www.nochurn.sh/use-cases/marketplaces/ Many marketplaces and platforms charge their sellers, hosts, vendors or professionals a subscription: a monthly plan to list products, a pro tier with better placement, a software fee for booking or shop tools. These customers are businesses, often small ones, and their decision to stay depends on one thing above all: whether the platform brings them enough revenue to justify the fee. NoChurn works on that seller subscription, not on the payments between buyers and sellers. ## What NoChurn covers on a platform - **Covered:** the subscription your sellers pay you. Plan payments, failed charges, cancellations, offers, win-back and the seller's churn score. - **Not covered:** buyer orders, payouts to sellers, and disputes between buyers and sellers. Those stay in your marketplace payment setup. On Stripe, platforms often run seller subscriptions with Stripe Billing next to Stripe Connect, charging connected accounts as customers ([Stripe, accessed November 2026](https://docs.stripe.com/connect/subscriptions)). NoChurn connects to the platform's own Stripe account where those subscriptions are billed. If your seller fees are deducted from payouts or billed by your own system, send subscriptions, payments and cancellations through the [REST API](/integrations/api/). ## How sellers pay - **A card on file**, often the owner's personal or business card. - **Deducted from the seller's balance or payout**, when the platform also handles their sales. Then a "failed payment" usually means the seller had no sales that month. - **Direct debit** for some European platforms, through [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/). - **Monthly tiers** with an annual option for established sellers. ## Why sellers churn ### Involuntary churn - **Business cards that expire or get cancelled** when a small business changes banks. See [expiring cards](/blog/expiring-cards/). - **Empty balances.** When fees come from payouts, a slow month means nothing to deduct. - **Failed direct debits** after a seller changes bank accounts. See [GoCardless failed payments](/blog/gocardless-failed-payments/). ### Voluntary churn - **Not enough sales.** The fee feels like a tax on a channel that is not working. - **Seasonality.** Holiday rentals, wedding vendors, tax preparers, garden services: many sellers have an off-season. - **The seller closes or pauses their business.** Not a reason you can argue with. - **Moving to another channel**, or selling directly. - **Paying for a tier they do not use.** Pro features bought at launch, never used since. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). On other billing tools, the provider's dunning stays and NoChurn adds AI-written emails and a card update link next to it. Emails can be reviewed before they go out. For sellers, it helps to speak business language: "your shop will be hidden on the 15th if the plan is not paid" is clearer than a generic billing notice. The hosted card update page keeps card data with your payment provider. See [failed payments](/#dunning). ### Cancel flow that follows the seller's business | Reason | Offer that fits | | --- | --- | | Not enough sales | Plan change to a lower tier, keeping listings live | | Off-season | Pause until the season starts | | Closing or pausing the business | Pause, or let them go with their data kept | | Too expensive | Discount for a few months | | Moving to another channel | Ask what is missing, then let them go | A one-click "cancel now" button is visible on every step, and a cancel that is asked for is carried out. Sellers talk to each other, and a platform that is hard to leave gets a reputation quickly. Use the hosted modal in your seller dashboard, or build the screens with the headless API. See [cancel flows](/#cancel) and [pause vs discount](/blog/pause-vs-discount-retention-offers/). ### Churn score with seller signals Each seller gets a score from 0 to 100 at signup and on every change, from payment method, signup source and the custom data you send. Seller data is the strongest signal you have: a seller whose orders drop for two months is far more likely to cancel than one whose orders are growing. When a seller removes their card before a renewal, the score goes up. See [churn score](/#score). ### Win-back Sellers who cancel get win-back emails at 30, 60 and 90 days, written from their cancel reason. A seasonal seller can be invited back before their season; one who left over sales can hear about what changed on the platform. See [win-back](/#winback). ### Chargebacks on seller fees Sellers sometimes dispute your subscription fee with their bank, often after a disagreement about the platform. On Stripe and Braintree, NoChurn gathers evidence (cancel flow answers, emails sent, usage, support conversations) and drafts a reply with AI, sent only after a person reviews it. Disputes on other providers are shown read only. This covers your fee only, not disputes on buyer orders. See [chargebacks](/#disputes). ### Custom data worth sending - `listings_active` - `orders_last_30_days` and `orders_trend`: up, flat or down, computed by you. - `seller_revenue_band`: a band you choose, rather than exact amounts. - `last_login_at`: last visit to the seller dashboard. - `reviews_count` or `rating` - `category` and `country` - `plan`, `billing_interval` and `signup_source` NoChurn shows which attributes go with churn, with sample sizes. Correlation, not causation: sellers with few listings may churn more because they were never serious, not because the listing limit pushed them out. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/), in one click, for seller subscriptions on Stripe Billing. - [Chargebee](/integrations/chargebee/) or [Recurly](/integrations/recurly/) if your seller plans run on a billing platform. - [Any billing by API](/integrations/api/) when fees come from payouts. - [Zendesk](/integrations/zendesk/), [HubSpot](/integrations/hubspot/) or [Intercom](/integrations/intercom/) for seller support, read only. ## What to watch out for - **Separate seller churn from buyer churn.** NoChurn works on the seller subscription. Buyer retention is a different problem. - **Fees from payouts.** If you deduct fees from earnings, a failed charge is a sales problem, not a card problem. Write the emails accordingly. - **Large sellers.** Your biggest sellers probably have an account manager. Use NoChurn's score to tell that person early, not to replace them. - **When NoChurn is not the right tool.** If your platform earns only a commission on each sale with no seller subscription, there is no recurring charge for NoChurn to work on. ## Pricing Every feature is on every plan, and the price depends only on your MRR from seller subscriptions: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the pages for [B2B SaaS](/use-cases/b2b-saas/) and [product-led SaaS](/use-cases/plg-saas/). --- # NoChurn for subscription boxes and ecommerce subscriptions Source: https://www.nochurn.sh/use-cases/subscription-boxes/ Subscription boxes and ecommerce subscriptions (coffee, pet food, skincare, meal kits, razors, vitamins) sell a physical product on a schedule. Churn here is shaped by things a software subscription never has to deal with: a shipping cutoff, a pantry that is still full, a product the customer did not like, a parcel that went missing. NoChurn helps with the recurring billing side: renewals that fail, customers who want a break rather than an exit, and disputes over charges. ## Check the fit first NoChurn works with subscriptions billed through [Stripe](/integrations/stripe/), the other billing and payment providers it connects to, or your own system through the [REST API](/integrations/api/). Many stores run subscriptions through an app inside their ecommerce platform. NoChurn has no direct connector for those apps; if the app can send you webhooks or you can export its events, you can forward subscriptions, payments and cancellations to NoChurn by API. If you cannot get those events out, NoChurn is not the right tool for your store yet. ## How subscribers pay - **A card saved at the first order,** charged on every renewal (weekly, monthly or every few weeks). - **Wallets** at checkout, saved for future charges where the provider supports it. - **Prepaid plans:** three, six or twelve boxes paid upfront, often given as gifts. - **Direct debit** for some European subscriptions, through [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/). ## Why subscribers churn ### Involuntary churn - **The renewal fails right before the shipping cutoff.** A retry that succeeds two days late can mean a box that misses its slot. - **Cards saved at the first order expire** months later. See [expiring cards](/blog/expiring-cards/). - **Prepaid and virtual cards** used for an introductory offer. See [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ### Voluntary churn - **Too much product.** The cupboard is full; the customer wants to skip, not quit. - **Did not like the last box.** One bad box can end a subscription. - **Delivery problems.** A late, damaged or missing parcel. - **The introductory discount ended.** The first boxes were cheap; the full price feels different. - **Gift subscriptions end** and nobody renews. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed renewals at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). On other billing tools, the provider's own dunning stays and NoChurn adds AI-written emails and a card update link next to it. You can review emails before they go out, and mention what matters to the customer: their next box and when it ships. The hosted card update page works on a phone and keeps card data with your payment provider. See [failed payments](/#dunning). ### Cancel flow: skip and pause first Most "cancel" clicks in ecommerce subscriptions are really "not now". The cancel flow asks why and offers the matching alternative: | Reason | Offer that fits | | --- | --- | | I have too much product | Pause for one or two cycles (a skip) | | I am travelling or moving | Pause until a date they choose | | It is too expensive | Plan change to a smaller box or less frequent delivery, or a discount | | I did not like the last box | Plan change to another variant, or pass it to support | | Delivery problems | Pass it to support | On Stripe, a pause can stop payment collection while the subscription stays in place ([Stripe, accessed November 2026](https://docs.stripe.com/billing/subscriptions/pause-payment)). A one-click "cancel now" button is visible on every step, and a cancel that is asked for is carried out. Use the hosted modal on your account page, or build the screens yourself with the headless API. See [cancel flows](/#cancel), [pause vs discount](/blog/pause-vs-discount-retention-offers/) and [Stripe pause](/blog/stripe-pause-subscription/). ### Gorgias and support tickets Ecommerce teams often run support in [Gorgias](/integrations/gorgias/), which connects to stores and shows order data next to each ticket ([Gorgias, accessed November 2026](https://docs.gorgias.com/en-US/connect-shopify-to-gorgias-81814)). NoChurn reads Gorgias tickets (read only), matches them to customers by email, and uses them in the churn score, in churn drivers and in dispute evidence. A customer who opened two "where is my order" tickets this month is a customer at risk, and the score can show it. See [Gorgias subscription cancellations](/blog/gorgias-subscription-cancellations/) and [Gorgias refund requests](/blog/gorgias-refund-requests/). [Zendesk](/integrations/zendesk/), [Help Scout](/integrations/help-scout/) and [Crisp](/integrations/crisp/) work the same way. ### Chargebacks Physical products bring disputes that software rarely sees: "item not received", "not as described", or "I cancelled and was still charged". On Stripe and Braintree, NoChurn gathers evidence automatically: cancel flow answers (including when the customer chose to skip instead of cancel), emails sent, and support conversations from Gorgias or another help desk. AI drafts the reply, and it is sent only after a person on your team reviews it. Shipping and tracking proof stays in your fulfilment tools; NoChurn does not collect it. Add it during the review step, before the response goes out, so the reply covers delivery as well as the subscription history. On Stripe, early fraud warnings also appear with a one-click refund, which is often cheaper than shipping a box to a stolen card. Disputes on other providers are shown read only. See [chargebacks](/#disputes), [Gorgias chargeback evidence](/blog/gorgias-chargeback-evidence/) and [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/). ### Win-back Customers who cancel get win-back emails at 30, 60 and 90 days, written from their cancel reason. "Too much product" can come back with a less frequent plan; "did not like the box" can hear about a new range. See [win-back](/#winback). ### Custom data worth sending - `boxes_received` - `skips_last_90_days` - `last_rating`: the customer's rating of the last box, if you collect one. - `delivery_issues_count` - `first_order_discount` and `coupon_used` - `is_gift` - `frequency` and `box_size` - `signup_source` The churn score (0 to 100 at signup and on every change) uses these with the payment method and signup source. NoChurn shows which attributes go with churn, with sample sizes. Correlation, not causation: customers who skip a lot may be your most loyal ones. See [custom data](/#insights). ## What to watch out for - **The shipping cutoff.** Line up your retry and email timing with it, and pause shipments while a payment is being recovered. - **Gifts are not churn.** A prepaid gift that ends is a win-back opportunity, not a failure. - **One-off ecommerce is out of scope.** NoChurn works on recurring charges. For single orders and abandoned carts, an ecommerce marketing tool is the better fit. ## Pricing Every feature is on every plan, and the price depends only on your MRR: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the page for [consumer subscriptions](/use-cases/consumer-subscriptions/). --- # NoChurn for agencies and service retainers Source: https://www.nochurn.sh/use-cases/agencies-services/ Agencies, studios and service businesses increasingly sell on a recurring basis: a monthly design or development retainer, an SEO or content package, managed IT, bookkeeping, a productized service with a fixed scope and price. That makes them subscription businesses, with subscription churn. The difference is that a retainer client usually has a relationship with a person on your team, and the decision to leave builds over weeks of fewer requests, slower replies and a budget review you never heard about. ## Check the fit first NoChurn works best for service businesses with **many clients on standard plans**, billed automatically by card or direct debit: productized services, packages, small retainers. If you have a handful of large clients on custom contracts paid by bank transfer, your account managers and a CRM will do more for you than any automation; NoChurn can still help with the score and win-back, but there is little payment recovery to do. ## How retainer clients pay - **Card on file, charged monthly** through [Stripe](/integrations/stripe/), common for productized services. - **Direct debit** through [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/), common for UK and European retainers. - **Invoices paid by bank transfer.** NoChurn cannot retry a bank transfer; it can only see that an invoice is unpaid if your billing tool tells it. - **A billing platform** such as [Chargebee](/integrations/chargebee/) or [Zuora](/integrations/zuora/) for larger service firms, or your own invoicing sent through the [REST API](/integrations/api/). ## Why retainer clients churn ### Involuntary churn - **The company card on file expires,** and the person who entered it is not the one who reads billing emails. See [expiring cards](/blog/expiring-cards/). - **A direct debit mandate is cancelled** when the client changes banks or tidies up their payments. See [mandate cancelled](/blog/gocardless-mandate-cancelled/). - **Invoices sit in someone's inbox.** The client means to pay, nobody does, and the relationship sours over a late-payment conversation. ### Voluntary churn - **The project phase ended.** The website launched; the client no longer sees why they pay every month. - **Budget cuts.** Retainers are an easy line to remove in a cost review. - **Fewer requests over time.** The client stops using the hours they pay for, then decides they do not need them. - **The contact changes.** Your champion leaves, and the new person brings their own agency. - **Bringing the work in-house.** The client hires someone to do what you did. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed card payments at times based on the decline reason and likely paydays, or you can keep [Stripe Smart Retries](/blog/stripe-smart-retries/). On other billing tools, including direct debit providers, their own retry rules stay and NoChurn adds AI-written emails and a link to update payment details next to them. You can review every email before it goes out, which matters when the client knows your team by name: edit the draft until it sounds like the account lead. The hosted card update page keeps card data with your payment provider. See [failed payments](/#dunning) and [dunning email templates](/blog/dunning-email-templates/). ### Cancel flow for self-serve plans Clients on productized plans can cancel themselves; the flow asks why and offers an alternative: | Reason | Offer that fits | | --- | --- | | The project is done | Plan change to a smaller maintenance retainer | | Budget cut | Plan change to fewer hours, or a discount for a few months | | We do not need it right now | Pause for a month or two | | We are moving it in-house | Offer a handover or support plan, then let them go | | Unhappy with the work | Book a call with the account lead | A one-click "cancel now" button is visible on every step, and a cancel that is asked for is carried out. If your clients usually cancel by email, put the flow on their account page anyway, so reasons are recorded and offers stay consistent. See [cancel flows](/#cancel) and [cancellation reasons survey](/blog/cancellation-reasons-survey/). ### Churn score from the relationship Each client gets a score from 0 to 100 at signup and on every change, from payment method, signup source and the custom data you send. For services, the useful signals come from how the client works with you. Connect your help desk or CRM ([HubSpot](/integrations/hubspot/), [Help Scout](/integrations/help-scout/), [Zendesk](/integrations/zendesk/), [Intercom](/integrations/intercom/), read only) and NoChurn matches conversations to clients and uses them in the score. A client who used to send ten requests a month and now sends two is a client to call. When a client removes their card before a renewal, the score goes up too. See [churn score](/#score) and [HubSpot churn signals](/blog/hubspot-churn-signals/). ### Chargebacks Service disputes are rare but painful: "services not provided" is hard to argue without records. On Stripe and Braintree, NoChurn gathers evidence automatically (cancel flow answers, emails sent, usage you report, support conversations) and drafts a reply with AI, sent only after a person reviews it. Add your own delivery records, such as reports and signed-off work, during that review. Disputes on direct debit and other providers are shown read only. See [chargebacks](/#disputes). ### Win-back Clients who cancel get win-back emails at 30, 60 and 90 days, written from their cancel reason. A client whose project ended can hear about a new service; one who cut budget can be offered a smaller package when the next quarter starts. For larger clients, you will probably want the account lead to write these personally; review and edit the AI drafts before they go out. See [win-back](/#winback) and [HubSpot win-back sequences](/blog/hubspot-win-back-sequences/). ### Custom data worth sending - `hours_used` and `hours_included`: the share of the retainer actually used. - `requests_last_30_days` - `last_meeting_at`: last call or review with the client. - `deliverables_last_30_days` - `account_lead`: who manages the client, as an ID. - `months_as_client` and `contract_end_date` - `service_line`, `plan` and `signup_source` NoChurn shows which attributes go with churn, with sample sizes. Correlation, not causation: clients with fewer meetings may churn more, or may simply need less help. With few clients, samples are small, so treat results as hints. See [custom data](/#insights). ## What to watch out for - **Small samples.** Thirty clients do not make statistics. Use the score and drivers as prompts for a conversation. - **Contracts and notice periods.** If your retainers have a minimum term or notice period, the cancel flow should state it clearly. Keep the "cancel now" button honest about what happens next. - **Bank transfers.** NoChurn cannot recover what it cannot charge. Moving clients to card or direct debit is the bigger win. ## Pricing Every feature is on every plan, and the price depends only on your MRR: free up to $300, then from $9 a month in small steps up to $399 at $500k, custom above. NoChurn never takes a share of recovered revenue. See [pricing](/pricing/), or the pages for [B2B SaaS](/use-cases/b2b-saas/) and [online courses](/use-cases/online-courses/). --- # NoChurn for healthcare software Source: https://www.nochurn.sh/use-cases/healthcare-saas/ Practice management, scheduling, telehealth and clinic software is sold to businesses: independent practitioners, small clinics, therapy groups, dental and physiotherapy practices. The software holds sensitive records, but the subscription itself is ordinary B2B billing. A card on file, a monthly or annual plan, a billing contact who may not be the clinician. That is the part NoChurn works on. ## NoChurn never needs patient data Say it plainly first, because it is the first question a healthcare team should ask. NoChurn works on **your customers**, the practices and clinicians who pay you, not on their patients. It reads subscriptions, invoices, payment attempts and cancellations from your billing tool, plus any attributes you choose to send about the practice account. None of that requires patient names, appointments, diagnoses, notes or anything else about a patient's health. Do not send it. When you choose custom attributes, keep them at the account level: number of seats, number of locations, feature usage counts, last login of the account. Aggregated counts such as "appointments booked this month" describe how much the practice uses your product; they do not need to identify anyone. NoChurn makes no claim about HIPAA or any other health privacy regime. Rules on health data differ by country and by how your product is built, so before connecting any new vendor, check with your counsel what may and may not leave your system. The safe default is simple: billing data and account-level usage only. ## Where healthcare software loses customers ### Involuntary churn - **Cards held by one person.** A solo practitioner or practice manager pays with a personal or company card. When it expires or is replaced, payments fail and the reminders reach an inbox that is busy with clinical work. - **Billing contacts who are not users.** An office manager or outside bookkeeper pays the invoice. The clinicians who depend on the software never see the failed payment notice. - **Direct debit in some markets.** Clinics in Europe or the UK often prefer bank debits. These fail differently from cards (closed accounts, cancelled mandates) and need a different message. ### Voluntary churn - **Practice changes.** A clinician retires, a practice is sold, two practices merge onto one system. Some of this churn cannot be saved, and it should not be fought. - **Seasonal or part-time practice.** A practitioner on leave or working fewer days wants to stop paying for a while, not leave for good. - **Tool consolidation.** A group buys a larger platform and drops the specialised tools around it. - **Switching cost felt too late.** Practices that never finished migrating their data or configuring templates are the most likely to leave at renewal. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays. Recovery emails are written by AI for each practice and you can review them before they go out, so the tone fits a clinic rather than a collections notice. Each email links to a hosted card update page; card data stays with your payment provider. On Chargebee, Recurly, Maxio, Zuora, GoCardless and the other supported tools, NoChurn adds AI emails and a card update link next to the provider's own dunning. See [failed payments](/#dunning) and [involuntary churn](/blog/involuntary-churn/). ### Churn score Each new practice gets a score from 0 to 100 at signup and again on every change, based on payment method, signup source and any custom data you send. A practice that removes its card before a renewal is flagged early, before the payment fails. See [churn score](/#score). ### Cancel flow The cancel flow asks why the practice is leaving and shows an offer that fits: | Reason | Suitable offer | | --- | --- | | On leave or fewer patients for now | Pause the subscription | | Fewer clinicians | Move to a smaller plan | | Too expensive | A discount | | Missing a feature or migration stuck | Offer a call with your team | | Practice closing or sold | No offer: let them go cleanly | A one-click "cancel now" button stays visible on every step. Use the hosted modal with your branding, or build the screens yourself with the headless API inside your admin settings. See [cancel flows](/#cancel) and [cancel flow best practices](/blog/cancel-flow-best-practices/). ### Win-back Practices that leave get win-back emails at 30, 60 and 90 days, written from their cancel reason. A practitioner who paused for leave hears from you around their return; one who left for a missing feature hears when it ships. ### Chargebacks Disputes are rarer in B2B software, but they happen, often when a practice forgets a renewal. On Stripe and Braintree, NoChurn gathers evidence automatically (cancel flow answers, emails sent, account usage, support conversations) and drafts a reply that is sent only after a person on your team reviews it. Keep patient information out of that evidence too: account usage counts are enough. ### Custom data worth sending - `seats` and `locations`: do single-practitioner accounts leave more than groups? - `specialty`: does churn differ by type of practice? - `activated_at`: did the practice finish onboarding and data migration? - `last_active_at`: last login of any user on the account. - `key_feature_usage`: counts only, for example online booking turned on, reminders sent per month. - `billing_interval`: monthly or annual. - `support_tickets`: from your help desk. - `country` NoChurn shows which attributes go with churn, with sample sizes, and AI explains them. Correlation, not cause. See [custom data](/#insights) and [predicting churn with customer data](/blog/predict-churn-with-customer-data/). ## Integrations that fit - [Stripe](/integrations/stripe/) for most self-serve clinic software, connected in one click. - [Chargebee](/integrations/chargebee/), [Recurly](/integrations/recurly/), [Maxio](/integrations/maxio/) or [Zuora](/integrations/zuora/) if you sell larger plans with invoicing. - [GoCardless](/integrations/gocardless/) or [Mollie](/integrations/mollie/) for practices paying by bank debit. - [Any billing, by API](/integrations/api/) if your billing is built in house. - Help desks such as [Zendesk](/integrations/zendesk/) or [Intercom](/integrations/intercom/), read only, for support signals. Make sure the conversations NoChurn can read are about your product and accounts, not about patients. ## What to watch out for - **Data minimisation.** Decide with your counsel which fields may be shared with a vendor, and keep NoChurn's inputs to billing and account-level usage. - **Contract terms.** Annual contracts with notice periods are common in this sector. Make the cancel flow follow your actual terms, and keep the cancel button working: a cancellation that is asked for gets executed. - **Cancellation rules.** Rules on online cancellation vary by country; see our overview of [click to cancel rules](/blog/click-to-cancel-rules/) and check with your counsel for your markets. ## How NoChurn helps For healthcare software, NoChurn recovers failed practice payments, offers a pause or smaller plan before a cancel, wins back practices with a message that fits why they left, and does all of it on billing and account data alone. Every feature is on every plan, priced only by MRR and never by a share of recovered revenue. See [pricing](/pricing/), or the pages for [B2B SaaS](/use-cases/b2b-saas/) and [vertical SaaS](/use-cases/vertical-saas/). --- # NoChurn for edtech platforms Source: https://www.nochurn.sh/use-cases/edtech/ Edtech subscriptions cover a wide range: homework help and tutoring platforms, language learning apps, test prep, coding clubs for kids, tools that teachers or tutors pay for themselves. What they share is a learning rhythm. People sign up around the start of term, an exam, a move abroad or a new year's resolution, and they reconsider when the term ends or the goal is reached. This page is about ongoing learning subscriptions. If you sell courses, cohorts or a course library, see [online courses](/use-cases/online-courses/) instead. ## Where edtech loses subscribers ### Involuntary churn - **The payer is not the user.** A parent's card pays for a child's account. When the card expires, the failed payment email goes to a parent who does not open the app, while the child simply loses access. - **Small charges on personal cards.** Monthly learning plans are often a modest line on a family budget. They fail on low balances and expired cards, and get noticed late. - **App store billing.** Language and learning apps sold through the App Store or Google Play are billed by Apple or Google, which run their own retries and grace periods. ### Voluntary churn - **Seasonality.** Summer holidays, exam season ending, the end of a school year. Many families do not want to cancel, they want to stop paying until term starts again. - **Goal reached.** The exam is passed, the trip is over, the child moved up a level. This is success churn, and the right move is a good exit and a well-timed invitation back. - **Low engagement.** A learner who stopped practising makes the next charge feel wasted, and the parent notices. - **Price at renewal.** Annual plans bought with a launch discount come up for renewal at full price. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays. Recovery emails are written by AI for each family, in their language, and you can review them before they go out. They can name what the learner keeps by updating the card (progress, streaks, a tutor's schedule) instead of reading like a bank notice. Each email links to a hosted card update page; card data stays with your payment provider. See [failed payments](/#dunning) and [dunning email templates](/blog/dunning-email-templates/). On the App Store and Google Play, retries and the grace period stay with Apple and Google. NoChurn reads the store notifications, so it can tell the learner or parent in your app or by email and link to the store's subscription settings. See [App Store billing retry and grace period](/blog/app-store-billing-retry-grace-period/). ### Churn score Each new subscriber gets a score from 0 to 100 at signup and again on every change, based on payment method, signup source and any custom data you send. A subscriber who removes their card before renewal is flagged before the payment fails. See [churn score](/#score). ### Cancel flow built for the school year | Reason | Suitable offer | | --- | --- | | Summer or holidays | Pause until term starts | | Exam done, goal reached | No offer, or a lower plan to keep progress | | Too expensive | A discount or a cheaper plan | | Child or learner stopped using it | A pause, or a call with a tutor | | Switching to a school-provided tool | Let them go cleanly | A one-click "cancel now" button stays visible on every step, so a parent who wants to stop can stop. On web billing, use the hosted modal with your branding or the headless API in your own account pages. For App Store and Google Play subscriptions, your app can show the flow through the headless API before linking to the store's own cancel page, which always works. See [cancel flows](/#cancel) and [pause vs discount offers](/blog/pause-vs-discount-retention-offers/). ### Win-back Families who leave get win-back emails at 30, 60 and 90 days, written from their cancel reason. For edtech, timing matters more than discounts: a family that left for the summer is best invited back before term starts, and one that left after an exam may come back for the next level. ### Custom data worth sending - `learner_age_band` or `level`: a band or level is enough; see below on children's data. - `last_active_at`: last lesson, practice or session. - `key_feature_usage`: lessons completed, sessions booked, streak length. - `goal` or `exam_date`: when the learner expects to be done. - `signup_source`: school referral, social, search, a back-to-school campaign. - `payer_is_learner`: does churn differ when the person paying also learns? - `plan`, `billing_interval` and `coupon_used` - `country` NoChurn shows which attributes go with churn, with sample sizes, and AI explains them. Correlation, not cause. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/) for web subscriptions, connected in one click. - [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/) for mobile learning apps. - [Paddle](/integrations/paddle/), [Lemon Squeezy](/integrations/lemon-squeezy/) or [Polar](/integrations/polar/) if a merchant of record sells for you; disputes are handled by the merchant of record and shown read only. - [Mollie](/integrations/mollie/) or [Razorpay](/integrations/razorpay/) for local payment methods. - [Any billing, by API](/integrations/api/) for school or district contracts billed by invoice in your own system. - Help desks such as [Intercom](/integrations/intercom/) or [Crisp](/integrations/crisp/), read only. ## What to watch out for - **Children's data.** If some of your users are children, rules on collecting and sharing their data may apply in your markets. NoChurn works on the paying account and does not need anything about the child. Send bands and counts, not names or birth dates, and check with your counsel. - **Who you write to.** Recovery and win-back emails should go to the payer, not to a child's login email. - **Cancellation and renewal rules.** Annual renewals and online cancellation are regulated differently by country; see [click to cancel rules](/blog/click-to-cancel-rules/) and [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/), then check with your counsel. - **School contracts.** Plans bought by schools usually follow a purchasing process, not a cancel button. Keep those out of the consumer cancel flow. ## How NoChurn helps For edtech, NoChurn reaches the parent who pays when a card fails, offers a summer pause instead of a cancel, keeps a one-click exit on every step, and invites families back when the next term or level comes around. Every feature is on every plan, priced only by MRR and never by a share of recovered revenue. See [pricing](/pricing/), or the pages for [online courses](/use-cases/online-courses/) and [mobile apps](/use-cases/mobile-apps/). --- # NoChurn for vertical SaaS Source: https://www.nochurn.sh/use-cases/vertical-saas/ Vertical SaaS is software built for one kind of business: booking for salons and studios, member management for gyms, ordering and reservations for restaurants, quoting and scheduling for plumbers, electricians and landscapers. The buyer is usually the owner or a manager, not an IT team. They pay with whatever card is to hand, they are rarely at a desk, and their own business has good and bad months. That shapes churn. A lot of it is involuntary, a lot of the voluntary part is seasonal, and some of it is simply businesses closing, which no offer will change. ## Where vertical SaaS loses customers ### Involuntary churn - **The owner's card, on the owner's phone.** Payments run on a business or personal card that gets replaced, maxed out or frozen. The failed payment email lands in an inbox full of supplier invoices and booking notifications. - **Cash flow in small businesses.** A slow month for a café or a contractor can mean a declined charge that would succeed a week later, after their own customers have paid. - **Bank debits in some countries.** Small businesses in Europe and the UK often pay software by direct debit. Those fail for different reasons (insufficient funds, a cancelled mandate) and settle over days, not seconds. ### Voluntary churn - **Off-season.** Landscapers in winter, ski rentals in summer, a beach restaurant out of season. They want to stop paying for a few months, not lose their setup. - **Business closes or is sold.** Small businesses close and change hands. A new owner may bring their own tools. - **Staff turnover.** The manager who set the software up leaves, and nobody else knows how it works. - **Price sensitivity.** A monthly fee is weighed against thin margins, especially when the business shrinks. - **Bundled competitors.** Payment terminals and point-of-sale systems increasingly include software that overlaps with yours. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays, which suits businesses that get paid at the end of a week or month. Recovery emails are written by AI for each business, in its language, and you can review them before they go out. They can say what stops working if the payment does not go through (online bookings, reminders to clients, the ordering page) in plain words. Each email links to a hosted card update page; card data stays with your payment provider. On GoCardless, NoChurn times its emails for direct debit and, when a mandate is cancelled, links to set up a new one. On Chargebee, Recurly and the other billing tools, NoChurn adds AI emails and an update link next to the provider's own dunning. See [failed payments](/#dunning), [expiring cards](/blog/expiring-cards/) and [GoCardless failed payments](/blog/gocardless-failed-payments/). ### Churn score Each new business gets a score from 0 to 100 at signup and again on every change, based on payment method, signup source and any custom data you send. A business that removes its card before renewal is flagged before the payment fails. See [churn score](/#score). ### Cancel flow with an off-season pause | Reason | Suitable offer | | --- | --- | | Off-season or temporarily closed | Pause the subscription | | Fewer staff or locations | Move to a smaller plan | | Too expensive | A discount | | Hard to use, setup person left | A call or a guided session with your team | | Business closed or sold | No offer: let them go cleanly | A one-click "cancel now" button stays visible on every step. Use the hosted modal with your branding, or build the screens with the headless API inside your back office or mobile app. See [cancel flows](/#cancel) and [pause vs discount offers](/blog/pause-vs-discount-retention-offers/). ### Win-back Businesses that leave get win-back emails at 30, 60 and 90 days, written from their cancel reason. For seasonal trades, the useful message is "your season starts soon, your setup is still here", sent before the season, not a generic discount. ### Chargebacks Small business owners sometimes dispute a charge they do not recognise, or one they meant to cancel. On Stripe and Braintree, NoChurn gathers evidence automatically (cancel flow answers, emails sent, usage, support conversations) and drafts a reply that is sent only after a person on your team reviews it. On Stripe, early fraud warnings are shown with a one-click refund. See [winning chargebacks on Stripe](/blog/win-chargebacks-stripe/). ### Custom data worth sending - `business_type`: salon, gym, restaurant, plumber; does churn differ by trade? - `locations` and `staff_count` - `activated_at`: did the business take its first booking, order or quote? - `last_active_at`: last login or last transaction processed through your product. - `key_feature_usage`: bookings, orders or jobs per month. - `seasonal`: does the business say it is seasonal at signup? - `signup_source`: a partner, a trade association, ads, a sales rep. - `plan`, `billing_interval` and `country` NoChurn shows which attributes go with churn, with sample sizes, and AI explains them. Correlation, not cause. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/), connected in one click. - [GoCardless](/integrations/gocardless/) and [Mollie](/integrations/mollie/) for direct debit and local methods in Europe. - [Razorpay](/integrations/razorpay/) for businesses in India. - [Chargebee](/integrations/chargebee/), [Recurly](/integrations/recurly/) or [Maxio](/integrations/maxio/) if you run multi-location plans with more complex billing. - [Braintree](/integrations/braintree/) if you already process there. - [Any billing, by API](/integrations/api/) if billing is part of your own platform. - Help desks such as [HubSpot](/integrations/hubspot/), [Intercom](/integrations/intercom/) or [Zendesk](/integrations/zendesk/), read only. ## What to watch out for - **Business or consumer?** Some sole traders are treated like consumers by local cancellation and renewal rules. See [click to cancel rules](/blog/click-to-cancel-rules/) and check with your counsel for your markets. - **Payments you process for them.** If your platform also processes payments for the business's own customers, keep that money flow separate from the subscription NoChurn works on. - **Don't fight closures.** Offering discounts to a business that has shut down wastes their time and yours. Let the reason decide. ## How NoChurn helps For vertical SaaS, NoChurn recovers failed payments from busy owners at times that match how they get paid, offers an off-season pause before a cancel, keeps a one-click exit on every step, and brings seasonal businesses back before their season starts. Every feature is on every plan, priced only by MRR and never by a share of recovered revenue. See [pricing](/pricing/), or the pages for [B2B SaaS](/use-cases/b2b-saas/) and [healthcare software](/use-cases/healthcare-saas/). --- # NoChurn for dating apps Source: https://www.nochurn.sh/use-cases/dating-apps/ Dating apps have a churn pattern unlike most subscriptions. Plans are short (a week, a month, three months), purchases are often made on impulse after a good or bad evening, and the happiest outcome for a user is to stop needing the app. Most subscriptions run through the App Store and Google Play, with a growing share sold on the web. NoChurn can't change why people date. It can make sure payment problems don't end subscriptions by accident, that users who want a break get one, and that people who leave hear from you at a sensible time. ## Where dating apps lose subscribers ### Involuntary churn - **Store billing problems.** When a renewal fails on the App Store or Google Play, Apple and Google retry and may give a grace period. Users often do not notice until features disappear. - **Prepaid and virtual cards on web plans.** Some users prefer cards they control closely for this kind of purchase. They run out or expire, and renewals fail. - **Short plans mean more renewals.** A weekly plan renews four times as often as a monthly one, so payment failures come around more often. ### Voluntary churn - **Success.** The user met someone. This is churn you want, and it deserves a graceful exit. - **Fatigue.** Too few matches, too many dead conversations. The user wants a break, not to delete their account. - **Buyer's remorse.** An impulse upgrade the user regrets, sometimes followed by a refund request. - **Price.** Premium tiers are compared against free use of the same app and against competitors. ## How NoChurn handles it ### Failed payments On the App Store and Google Play, retries, grace periods and account hold stay with Apple and Google. NoChurn reads the store notifications, tells the user in your app or by email, and links to the store's subscription settings so they can fix the payment. See [App Store billing retry and grace period](/blog/app-store-billing-retry-grace-period/) and [Google Play grace period and account hold](/blog/google-play-grace-period-account-hold/). For web plans on Stripe, NoChurn retries at times based on the decline reason and likely paydays, and sends AI-written recovery emails you can review, with a link to a hosted card update page. Keep the tone discreet: subject lines should not reveal what the subscription is to anyone glancing at a shared screen. ### Refund requests and chargebacks On the App Store, Apple decides refunds. When Apple asks for context on a refund request, NoChurn sends the customer's real usage from your data, which you control. On Google Play, refunds and voided purchases are read and shown on the customer's timeline. See [App Store refund requests](/blog/app-store-refund-requests/). For web plans on Stripe or Braintree, NoChurn gathers chargeback evidence automatically (cancel flow answers, emails sent, usage, support conversations) and drafts a reply that is sent only after a person on your team reviews it. On Stripe, early fraud warnings are shown with a one-click refund, which can be the better answer for a charge the cardholder does not recognise. ### Churn score Each new subscriber gets a score from 0 to 100 at signup and again on every change, based on payment method, signup source and any custom data you send. Turning off auto-renew in the store, or removing a card on the web, is a strong early signal and raises the score before the subscription ends. See [churn score](/#score) and [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ### Cancel flow Apple's and Google's cancel buttons always work and stay in the store. Inside your app, you can show NoChurn's flow through the headless API before linking to the store page; for web plans, use the hosted modal or the API. A one-click "cancel now" stays visible on every step. | Reason | Suitable offer | | --- | --- | | Met someone | No offer: congratulate them and let them go | | Need a break | Pause, on plans you bill yourself | | Not enough matches | A lower tier, or tips to improve the profile | | Too expensive | A discount or a shorter plan | On store subscriptions, offers have to use what the store supports (Apple's and Google's own offer types), not a NoChurn discount. See [app store cancellation and retention](/blog/app-store-cancellation-retention/). ### Win-back Former subscribers get win-back emails at 30, 60 and 90 days, written from their cancel reason. Someone who left after meeting a partner should get nothing pushy, or nothing at all; someone who left from fatigue may welcome a note about new features after a few weeks. On the App Store, Apple's own win-back offers can be used alongside. See [App Store win-back offers](/blog/app-store-win-back-offers/). ### Custom data worth sending - `matches_last_7d` and `conversations_started`: counts, never message content. - `last_active_at` - `profile_completeness`: does a thin profile go with early churn? - `signup_source`: which campaigns bring users who stay? - `plan_length`: weekly, monthly, quarterly. - `platform`: iOS, Android, web. - `country` NoChurn shows which attributes go with churn, with sample sizes, and AI explains them. Correlation, not cause. See [custom data](/#insights). ## Integrations that fit - [App Store](/integrations/app-store/) and [Google Play](/integrations/google-play/) for in-app subscriptions. - [Stripe](/integrations/stripe/) or [Braintree](/integrations/braintree/) for web subscriptions. - [Paddle](/integrations/paddle/) if a merchant of record sells your web plans; its disputes are handled by Paddle and shown read only. - Help desks such as [Zendesk](/integrations/zendesk/) or [Intercom](/integrations/intercom/), read only. ## What to watch out for - **Sensitive data.** Dating profiles can reveal things like sexual orientation. Send NoChurn counts and dates, not profile fields or messages, and check with your counsel which data you may share with vendors in your markets. - **Store rules.** Apple and Google set their own rules on how you can link to web purchases and present offers. Follow their current guidelines. - **Renewal and cancellation rules.** Short auto-renewing plans sold to consumers are regulated differently by country; see [click to cancel rules](/blog/click-to-cancel-rules/) and check with your counsel. ## How NoChurn helps For dating apps, NoChurn follows store billing problems and refunds, recovers web payments discreetly, keeps cancellation one click away, and lets people who found someone leave in peace while inviting others back when it makes sense. Every feature is on every plan, priced only by MRR and never by a share of recovered revenue. See [pricing](/pricing/), or the pages for [mobile apps](/use-cases/mobile-apps/) and [consumer subscriptions](/use-cases/consumer-subscriptions/). --- # NoChurn for gaming subscriptions Source: https://www.nochurn.sh/use-cases/gaming-subscriptions/ Gaming subscriptions sold directly to players take many forms: membership tiers for an online game, a season or battle pass bought on your website, premium server access, a paid community around a game or a creator, perks for supporters. Players pay with whatever they have: their own card, a parent's card, a prepaid card, a wallet. Two things set gaming apart from most subscriptions. Engagement follows content: players arrive with a new season or update and drift away between them. And disputes are a real risk, from family members who did not know about a charge to players who dispute after being banned. This page is about subscriptions you bill yourself on the web. Purchases made inside console or mobile stores are billed by those platforms; for mobile, see [mobile apps](/use-cases/mobile-apps/). ## Where gaming subscriptions lose players ### Involuntary churn - **Prepaid, gift and virtual cards.** Common among younger players and anyone who keeps gaming spend separate. They run out and renewals fail. - **Cards that belong to someone else.** A parent's card gets replaced or the parent notices the charge and removes it. - **Wallets and local methods.** Players in different countries pay in different ways, each with its own failure modes. ### Voluntary churn - **Between seasons.** The season ends, the pass is done, and there is nothing new for a few weeks. - **Burnout or a new game.** Players move on, often for a while rather than for good. - **Community changes.** A favourite server, guild or creator goes quiet, and members follow. - **Price and value.** A premium tier is compared against free play. ### Disputes - **Friendly fraud.** A family member made the purchase, or the player forgot about a renewal, and the bank is asked to reverse it. - **Disputes after enforcement.** A player banned for breaking your rules disputes the subscription. - **Stolen cards.** Gaming goods resell easily, which makes them a target for card testing and fraud. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays. Recovery emails are written by AI for each player, in their language, and you can review them before they go out. They can name what the player keeps by updating their payment (rank, cosmetics, server access) in your game's voice. Each email links to a hosted card update page; card data stays with your payment provider. See [failed payments](/#dunning) and [Stripe decline codes](/blog/stripe-decline-codes/). ### Chargebacks This is where gaming businesses need the most help. On Stripe and Braintree, NoChurn gathers evidence automatically: cancel flow answers, emails sent, usage you send (logins, play time, items used) and support conversations. It drafts a reply with AI, and nothing is sent to the processor until a person on your team reviews it. On Stripe, early fraud warnings appear with a one-click refund. Refunding a charge flagged as fraud before it turns into a dispute is often the cheaper choice. Card networks run [dispute and fraud monitoring programs](https://docs.stripe.com/disputes/monitoring-programs) that enroll merchants above their thresholds (Stripe docs, accessed November 2026), so keeping disputes low matters beyond each individual case. See [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/) and [winning chargebacks on Stripe](/blog/win-chargebacks-stripe/). If you sell through Paddle, Lemon Squeezy or Polar, the merchant of record handles disputes and NoChurn shows them read only. ### Churn score Each new subscriber gets a score from 0 to 100 at signup and again on every change, based on payment method, signup source and any custom data you send. Prepaid and virtual cards raise the score, as does a card removed before renewal. A high score is a reason to watch an account, not a fraud verdict. See [churn score](/#score) and [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ### Cancel flow | Reason | Suitable offer | | --- | --- | | Waiting for the next season | Pause until it launches | | Playing less | A lower tier | | Too expensive | A discount | | Did not know about the charge | Cancel, and offer a refund if your policy allows | | Leaving the game | No offer | A one-click "cancel now" button stays visible on every step. A player who can cancel easily is less likely to ask their bank to do it for them. Use the hosted modal styled like your game, or build the screens in your launcher or site with the headless API. See [cancel flows](/#cancel). ### Win-back Former players get win-back emails at 30, 60 and 90 days, written from their cancel reason. Gaming has a natural hook: the next season, update or event. Time your custom data so a player who left between seasons hears about the new one. ### Custom data worth sending - `last_played_at` and `hours_played_30d` - `season_progress`: how far did they get in the current pass? - `community_member`: are they in a guild, clan or server? - `banned` or `enforcement_action`: needed so the right evidence goes into disputes. - `signup_source`: a streamer, an ad campaign, a referral. - `age_band`: a band, not a birth date; see below. - `plan`, `billing_interval` and `country` NoChurn shows which attributes go with churn, with sample sizes, and AI explains them. Correlation, not cause. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/) for web memberships and passes, with chargebacks and early fraud warnings. - [Braintree](/integrations/braintree/) if you take PayPal and cards through it, with dispute evidence. - [Paddle](/integrations/paddle/), [Lemon Squeezy](/integrations/lemon-squeezy/) or [Polar](/integrations/polar/) if a merchant of record sells for you. - [Any billing, by API](/integrations/api/) if your store is your own. - Help desks such as [Zendesk](/integrations/zendesk/), [Intercom](/integrations/intercom/) or [Gorgias](/integrations/gorgias/), read only, for support history in disputes. ## What to watch out for - **Young players.** If minors use your service, rules on their data and on purchases made without a parent's consent may apply. Check with your counsel, and send NoChurn age bands at most. - **Platform rules.** Console and mobile platforms have their own rules on selling outside their stores. Follow their current terms. - **Bans and refunds.** Write down your refund and enforcement policy and show it at checkout; evidence is only as good as the policy behind it. - **Cancellation rules.** Consumer subscriptions are regulated differently by country; see [click to cancel rules](/blog/click-to-cancel-rules/) and check with your counsel. ## How NoChurn helps For gaming subscriptions, NoChurn recovers failed payments in your game's voice, prepares dispute evidence for your team to review, surfaces early fraud warnings with a one-click refund, keeps cancellation easy, and brings players back when the next season starts. Every feature is on every plan, priced only by MRR and never by a share of recovered revenue. See [pricing](/pricing/), or the pages for [memberships and communities](/use-cases/memberships-communities/) and [consumer subscriptions](/use-cases/consumer-subscriptions/). --- # NoChurn for hosting and infrastructure Source: https://www.nochurn.sh/use-cases/hosting-infrastructure/ Hosting and infrastructure covers VPS and cloud providers, managed hosting, databases, object storage, CDNs, email delivery and other services that run someone else's product. Customers range from a hobbyist with one server to companies with large monthly bills. Pricing is often usage-based, or a base plan plus metered overages. Churn here has higher stakes on both sides. A failed payment can mean suspending a customer's production service. A fraudulent signup can mean resources used and never paid for, followed by a chargeback. ## Where hosting loses customers ### Involuntary churn - **Bills that change every month.** Usage-based invoices can be larger than the customer's card limit or their bank's usual pattern, and get declined. - **Cards that expire on long-running accounts.** A server set up years ago keeps running long after the card on file was replaced. - **The person who signed up has left.** Billing emails go to a former employee or a personal address of a freelancer who built the site. ### Voluntary churn - **Migration to a bigger cloud** as the customer grows, or to a cheaper host when they shrink. - **Project ends.** A client site is taken down, a side project is abandoned, a test environment is no longer needed. - **Price changes and bill shock.** An unexpected overage triggers a review of the whole account. - **Reliability incidents.** An outage sends customers shopping. ### Fraud and abuse - **Stolen cards** used to run resources for spam, mining or attacks. - **Card testing** against signup and billing forms. - **Chargebacks** after the resources have been consumed. ## How NoChurn handles it ### Failed payments On Stripe, NoChurn retries failed payments at times based on the decline reason and likely paydays, which matters when a decline is due to a temporary limit on a large usage invoice. Recovery emails are written by AI for each customer and you can review them before they go out. They should say plainly what happens and when (for example, the date your own policy suspends services), so the customer can act before anything goes down. Each email links to a hosted card update page; card data stays with your payment provider. NoChurn does not suspend or delete anything: your platform keeps that decision. See [failed payments](/#dunning), [Stripe decline codes](/blog/stripe-decline-codes/) and [card account updater and network tokens](/blog/network-tokens-card-account-updater/). If you bill usage through [Stripe billing meters](https://docs.stripe.com/billing/subscriptions/usage-based/implementation-guide) (Stripe docs, accessed November 2026), NoChurn reads the resulting invoices like any other Stripe invoice. ### Chargebacks and early fraud warnings On Stripe and Braintree, NoChurn gathers dispute evidence automatically: cancel flow answers, emails sent, usage you send (instances run, bandwidth, requests served) and support conversations. It drafts a reply with AI, and nothing goes to the processor until a person on your team reviews it. On Stripe, early fraud warnings appear with a one-click refund. For a hosting provider, refunding a charge flagged as fraud, and shutting down the resources on your side, is often better than waiting for the dispute. Visa and Mastercard run [dispute and fraud monitoring programs](https://docs.stripe.com/disputes/monitoring-programs) with fines for merchants above their thresholds, and Stripe notes that Visa's program counts early fraud warnings (Stripe docs, accessed November 2026). See [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/) and [winning chargebacks on Stripe](/blog/win-chargebacks-stripe/). ### Churn score at signup Each new customer gets a score from 0 to 100 at signup and again on every change, based on payment method, signup source and any custom data you send. Disposable, virtual and prepaid cards score higher than cards from established banks or wallets. A card removed before renewal raises the score too. The score is a signal for your own checks (a lower starting limit, manual review, a deposit), not a fraud verdict on its own. See [churn score](/#score) and [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ### Cancel flow | Reason | Suitable offer | | --- | --- | | Project ended | No offer, or a cheaper plan to keep backups | | Bill too high | A smaller plan, or a call to review usage | | Moving to another provider | Ask why; a call for larger accounts | | Reliability | A note from your team on what changed | | Not using it right now | Pause, if your platform supports it | A one-click "cancel now" button stays visible on every step. Use the hosted modal in your control panel, or build the screens with the headless API. Your platform decides what happens to data and resources after cancellation; tell customers clearly in the flow. See [cancel flows](/#cancel). ### Win-back Customers who leave get win-back emails at 30, 60 and 90 days, written from their cancel reason. A customer who left after an outage hears what you changed; one whose project ended may have a new one. ### Custom data worth sending - `monthly_usage` and `usage_trend`: shrinking usage often comes before a cancel. - `resources_running`: servers, databases, domains. - `last_deploy_at` or `last_login_at` - `support_tickets` and `incidents_affected` - `account_age_days` and `verified`: whether your own verification passed. - `signup_source` and `country` NoChurn shows which attributes go with churn, with sample sizes, and AI explains them. Correlation, not cause. See [custom data](/#insights). ## Integrations that fit - [Stripe](/integrations/stripe/) for most usage-based and prepaid billing, with chargebacks and early fraud warnings. - [Braintree](/integrations/braintree/) for PayPal and cards, with dispute evidence. - [Chargebee](/integrations/chargebee/), [Recurly](/integrations/recurly/), [Maxio](/integrations/maxio/) or [Zuora](/integrations/zuora/) for complex plans and invoicing. - [Any billing, by API](/integrations/api/) if your billing engine is your own, which is common in hosting. - Help desks such as [Zendesk](/integrations/zendesk/), [Help Scout](/integrations/help-scout/) or [Intercom](/integrations/intercom/), read only. ## What to watch out for - **Suspension and deletion.** Set your own timelines for suspending services and deleting data, publish them, and make recovery emails match them. - **Abuse handling is yours.** NoChurn flags risk and handles payments; blocking accounts and investigating abuse stay with your team. - **Cancellation rules.** Consumers and small businesses may be covered by online cancellation rules in some countries; see [click to cancel rules](/blog/click-to-cancel-rules/) and check with your counsel. ## How NoChurn helps For hosting and infrastructure, NoChurn recovers failed payments before services go down, prepares dispute evidence for your review, surfaces early fraud warnings with a one-click refund, scores risky signups, and wins back customers with a message that fits why they left. Every feature is on every plan, priced only by MRR and never by a share of recovered revenue. See [pricing](/pricing/), or the pages for [developer tools](/use-cases/developer-tools/) and [AI and usage-based tools](/use-cases/ai-tools/). --- # Churnkey alternative: NoChurn vs Churnkey Source: https://www.nochurn.sh/compare/churnkey/ Churnkey is one of the best-known retention tools for subscription businesses. It covers cancel flows, failed payment recovery and reactivation, and it works with several billing systems. NoChurn covers the same three jobs for teams on Stripe, or on any billing system through a REST API, with one flat price that depends only on your MRR. This page compares the two as of November 2026, based on Churnkey's public pages. If something has changed since, the sources at the bottom are the place to check. ## At a glance | | NoChurn | Churnkey | |---|---|---| | Pricing model | Flat monthly price by MRR band | Based on your average monthly churned revenue, price fixed for 12 months | | Starting price | Free until $300 MRR, then from $9/month | Starter plan, around $250/month billed yearly or $300 billed monthly, for under $5k of monthly churn [À VÉRIFIER] | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe, Chargebee, Maxio, Paddle, Braintree, plus a custom integration framework | | Failed payments | Smart retries, AI-written emails, hosted card update page | Recovery campaigns, failed payment wall, A/B testing | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Yes, customizable cancel flows | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Reactivation campaigns | | Custom data / AI | Send any attribute or event; statistics find churn drivers, AI explains them; churn score at signup | Retention analytics; see their plans for which insights are included | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Open-source React SDK with headless mode; read-only MCP server | | Contract | Self-serve up to $399/month | Monthly or annual billing, annual discounted | ## Where Churnkey is a good fit Churnkey has been around for years and it shows in the breadth of the product. A few cases where it is a strong choice: - **You want billing integrations with years of production behind them.** Churnkey lists native support for Chargebee, Maxio, Paddle and Braintree and has run them for years. NoChurn supports these platforms too, but it is newer. - **You want a React component you can drop in.** Churnkey's SDK is open source and offers a ready-made cancel flow component, a headless hook and a core state machine. - **You run many experiments on recovery emails.** A/B testing is part of their payment recovery tooling. - **Your churned revenue is small relative to your MRR.** Because Churnkey prices on churned revenue rather than total revenue, a business with high MRR and very low churn may find the math works in its favor. ## Where NoChurn is different **Price follows your size, not your churn.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR. Above that, we quote. Your bill does not go up in a bad churn month, and it is easy to forecast. See [pricing](/pricing/). **Every feature on every plan.** There are no feature tiers. The free plan has the same cancel flows, recovery emails, win-back, custom data and API as Scale. **Never a cut of recovered revenue.** We do not charge a percentage of what we recover, now or later. **Stripe in one click, or any billing through the API.** If you are not on Stripe, you keep your own billing and send subscriptions, payments and cancellations to the REST API. Retries and card updates depend on what your billing system lets you do; the cancel flow, emails, scoring and win-back work the same. **Headless and MCP for writing integrations.** The cancel flow can be our hosted modal (themes, fonts, colors, logo, custom CSS) or fully headless: you fetch reasons and offers from the API and render them in your own web, desktop, iOS or Android UI. Our MCP server lets a coding agent such as Claude Code or Cursor wire NoChurn into your app, webhooks and custom data. See [headless and MCP](/#mcp). **Churn score at signup.** Every new customer gets a 0 to 100 score based on payment method, signup source and your custom data. Prepaid and disposable virtual cards score as high risk, neobank cards as medium, and Stripe Link, wallets, bank cards and SEPA as low; the levels adjust to your own history. If a customer removes their card before renewal, NoChurn raises the score and starts a save flow before the payment fails. See [churn score](/#score). **Click-to-cancel built in.** A one-click "cancel now" stays visible on every step of the flow. Offers are shown, never forced. **Churn drivers from your own data.** Send any customer attribute or usage event by API, batch, CSV or SDK. Statistics computed in code show which attributes go with churn, with sample size and confidence, and the AI explains the results and suggests actions. Correlation, not cause. NoChurn is new. We have no customer results to show yet, and Churnkey has years of production use. Weigh that honestly. ## Switching from Churnkey There is no automated import from Churnkey, so plan a short, controlled switch: 1. **Connect Stripe.** It takes a few minutes with Stripe Connect. Follow the [quickstart](/docs/quickstart/). 2. **Recreate your cancel reasons and offers.** List your current reasons and the offer tied to each, then set them up in NoChurn. Offers map to Stripe coupons, pauses, downgrades or a call booking. 3. **Rewrite your emails, or let the AI draft them.** Recovery emails go out on days 0, 3, 7 and 14 by default, in the customer's language, and you review them before they send. 4. **Run both during a test period.** For example, send a share of cancel clicks to the NoChurn flow and keep the rest on Churnkey. For failed payments, make sure only one tool emails a given customer, so nobody gets two sequences. 5. **Compare and decide.** Look at save rate, recovered payments and complaints for the same period, then turn one off. Keep in mind that Churnkey prices are fixed for 12 months on their side; check your renewal date before you switch. ## How NoChurn helps NoChurn recovers failed payments with smart retries and AI-written emails, keeps cancelling customers with an honest, reason-based flow, and wins back churned ones at 30, 60 and 90 days. It costs a flat amount based on your MRR, with every feature included. Start with [failed payments](/#dunning), the [cancel flow](/#cancel) or the [pricing](/pricing/) page, or read [cancel flow best practices](/blog/cancel-flow-best-practices/). --- # Churn Buster alternative: NoChurn vs Churn Buster Source: https://www.nochurn.sh/compare/churn-buster/ Churn Buster has focused on failed payment recovery for a long time, and it has grown a cancel flow product alongside it. It is especially at home with e-commerce subscription brands running on Shopify-based subscription apps. NoChurn is built for SaaS and subscription businesses on Stripe, or on any billing system through a REST API, and charges one flat price based on MRR. This comparison reflects Churn Buster's public pages and docs as of November 2026. Check the sources below for anything that may have changed. ## At a glance | | NoChurn | Churn Buster | |---|---|---| | Pricing model | Flat monthly price by MRR band | Scales with subscription volume | | Starting price | Free until $300 MRR, then from $9/month | From $249/month, according to Churn Buster's own article [À VÉRIFIER on their pricing page] | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe, Braintree, Recharge, Loop, Skio, Stay.ai, Ordergroove, Smartrr, Seal, Subbly, Shopify via custom app and others, plus an API | | Failed payments | Smart retries, AI-written emails reviewed before sending, hosted card update page | Per-payment campaigns with retries, emails and optional SMS | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Cancel Flows with skips, pauses, discounts or plan changes | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Not covered in the pages we reviewed [À VÉRIFIER] | | Custom data / AI | Send any attribute or event; statistics find churn drivers, AI explains them; churn score at signup | Free Measure mode to baseline recovery results | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | API integration for unsupported platforms | | Contract | Self-serve up to $399/month | See their pricing page [À VÉRIFIER] | ## Where Churn Buster is a good fit - **You run an e-commerce subscription brand.** Churn Buster integrates with many Shopify-ecosystem subscription apps such as Recharge, Skio, Loop, Stay.ai, Ordergroove and Seal. NoChurn does not have native connectors for these; you would use our API. - **Failed payments are your main problem and you want a specialist.** Churn Buster has spent years on recovery campaigns. On many platforms it controls retry timing and adapts it to decline codes, and on Stripe and Braintree it charges an updated card right away. - **You want SMS in the recovery sequence.** Churn Buster offers optional SMS. NoChurn recovery runs over email. - **You want to measure before you pay.** Their free Measure mode lets you baseline recovery results before switching on the paid product. ## Where NoChurn is different **Flat price by MRR.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with custom pricing above. Details on the [pricing](/pricing/) page. **Every feature on every plan.** Recovery, cancel flows, win-back, custom data, churn score and API are all included from the free plan. **Never a cut of recovered revenue.** You pay for your size, not for what we recover. **Stripe, or any billing through the API.** Stripe connects in one click. Without Stripe, you keep your billing and send subscriptions, payments and cancellations to our REST API. Chargebee, Recurly, Paddle, Braintree, Mollie, the App Store, Google Play and more connect directly too. **AI-written recovery emails you approve.** Emails go out on days 0, 3, 7 and 14 by default, in the customer's language (English, German, French, Italian or Portuguese). Retries can be timed to likely paydays and the customer's local time, or you can keep Stripe Smart Retries. Replies are read, sorted, and answered or sent to your team. The card update page is hosted, and card data stays with Stripe. **Churn score at signup.** Each new customer gets a 0 to 100 score from their payment method, signup source and your custom data. Prepaid and disposable virtual cards count as high risk; neobank cards as medium; Stripe Link, Apple Pay, Google Pay, bank cards and SEPA as low. When a customer removes their card before renewal, NoChurn starts a save flow before the payment fails. See [churn score](/#score). **Click-to-cancel built in.** The cancel flow goes reason, matching offer, confirm, and a one-click "cancel now" is visible at every step. **Headless and MCP.** Use the hosted modal with your theme and custom CSS, or go fully headless and render reasons and offers in your own web, desktop, iOS or Android UI. Coding agents can integrate NoChurn through our MCP server. See [headless and MCP](/#mcp). **Churn drivers from your data.** Send attributes like signup source, plan or key usage, and NoChurn shows which ones go with churn, with sample size and confidence. Correlation, not cause. See [custom data](/#insights). NoChurn is new and has no customer results to cite yet. Churn Buster has a long track record in recovery. ## Switching from Churn Buster There is no import tool, so switch in steps: 1. **Connect Stripe** in a few minutes with the [quickstart](/docs/quickstart/). If you are on another platform, plan the API integration first. 2. **Check your Stripe retry settings.** Churn Buster asks Stripe users to set specific failed payment settings. Review them before NoChurn takes over, and decide whether NoChurn times retries or you keep Stripe Smart Retries. 3. **Avoid double emails.** During a test period, run both tools on separate customer groups so nobody receives two recovery sequences. Make sure Stripe's own failed payment emails are off if a tool is emailing. 4. **Rebuild your cancel flow.** Copy your reasons and offers into NoChurn and add the win-back emails for each reason. 5. **Compare the same weeks.** Look at recovered payments, saves and replies, then keep one tool. ## How NoChurn helps NoChurn recovers failed payments with smart retries and AI-written emails, offers a fair cancel flow with click-to-cancel, and sends win-back emails at 30, 60 and 90 days. One flat price by MRR, every feature included. Read about [failed payments](/#dunning), see [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/), or check [consumer subscriptions](/use-cases/consumer-subscriptions/). --- # ProsperStack alternative: NoChurn vs ProsperStack Source: https://www.nochurn.sh/compare/prosperstack/ ProsperStack started as a cancellation flow tool and added revenue recovery and win-back campaigns over time. Its pricing is built around the number of cancel sessions you get each month. NoChurn covers failed payments, cancel flows and win-back for teams on Stripe, or on any billing through a REST API, and its price depends only on MRR. This page is based on ProsperStack's public pages as of November 2026. See the sources at the bottom for the current details. ## At a glance | | NoChurn | ProsperStack | |---|---|---| | Pricing model | Flat monthly price by MRR band | Tiers by monthly cancel sessions | | Starting price | Free until $300 MRR, then from $9/month | Grow from $200/month for 50 cancel sessions; extra blocks of 50 sessions at $75, up to 500 | | Higher tiers | $49 to $75k MRR, $149 to $200k, $399 to $500k, custom above | Prosper at $750/month for 500+ sessions; Enterprise on quote | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe, Chargebee, Recurly, Braintree, Paddle, Maxio, Recharge, Zuora, Bold and more; feature support varies by platform | | Failed payments | Smart retries, AI-written emails, hosted card update page | Revenue recovery included | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Customizable cancellation flows; multiple flows and A/B testing on Prosper | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Winback campaigns | | Custom data / AI | Send any attribute or event; statistics find churn drivers, AI explains them; churn score at signup | Cancellation reason reporting [À VÉRIFIER for AI features] | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | [À VÉRIFIER] | | Contract | Self-serve up to $399/month | Monthly billing listed by third parties [À VÉRIFIER] | ## Where ProsperStack is a good fit - **Your billing is not on Stripe.** ProsperStack lists a long set of billing integrations, including Chargebee, Recurly, Braintree, Paddle, Maxio and Zuora. If you want a native connector for one of these today, that is a real advantage. NoChurn works with those through our API for now. - **Your cancellation volume is low compared to your revenue.** Session-based pricing can cost less than MRR-based pricing when you have high revenue and few cancel attempts. - **You want to test many cancel flows against each other.** Multiple flows and A/B testing are part of their Prosper plan. - **You want a team that has focused on cancel flows for years.** ProsperStack has built its product around this moment in the customer lifecycle. ## Where NoChurn is different **Price depends on MRR, not on how many people click cancel.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR. A spike in cancel attempts does not raise your bill. See [pricing](/pricing/). **Every feature on every plan.** There is no "upgrade to unlock A/B tests" step. The free plan and Scale have the same product. **Never a cut of recovered revenue.** That will not change as you grow. **Stripe in one click, or any billing through the API.** Without Stripe, you keep your own billing and send subscriptions, payments and cancellations to our REST API. **Click-to-cancel built in.** Every step shows a one-click "cancel now." Customers see an offer that matches their reason (a Stripe coupon, a pause, a downgrade or a call), and they can always leave. Rules around easy cancellation are changing in several places; read our overview of [click-to-cancel rules](/blog/click-to-cancel-rules/). **Headless or hosted.** Use the hosted modal (themes, colors, fonts, borders, logo, custom CSS, visual editor) or fetch reasons and offers from the API and render the flow yourself on web, desktop, iOS or Android. An MCP server lets coding agents do the integration work. See [cancel flows](/#cancel). **Churn score at signup.** NoChurn scores each new customer from 0 to 100 using payment method, signup source and custom data, and flags customers who remove their card before renewal so a save flow can start before the payment fails. See [churn score](/#score). **Failed payments in depth.** Retries can be timed to likely paydays and the customer's local time, or you can keep Stripe Smart Retries. AI-written emails go out on days 0, 3, 7 and 14 by default, in the customer's language, after your review. Replies are read and answered or routed to your team. **Churn drivers.** Send any customer attribute or usage event, and NoChurn computes which ones go with churn, with sample size and confidence, then explains the results in plain language. Correlation, not cause. NoChurn is a new product without customer results yet. ProsperStack has been in production for years. ## Switching from ProsperStack No import tool exists, so a switch is manual but short: 1. **Connect Stripe** with the [quickstart](/docs/quickstart/). It takes a few minutes. 2. **Export your current setup by hand.** Write down each cancel reason, its offer and the copy you use, and recreate them in NoChurn. 3. **Split traffic for a test period.** Route part of your cancel clicks to NoChurn and keep the rest on ProsperStack. If both tools handle failed payments, assign each customer to one tool only so nobody gets duplicate emails. 4. **Add win-back.** Set the 30, 60 and 90 day emails for each reason. 5. **Compare the same period**, then keep one setup. ## How NoChurn helps NoChurn recovers failed payments, keeps cancelling customers with honest, reason-based offers, and wins back churned customers at 30, 60 and 90 days. One flat price by MRR, every feature on every plan. Read [cancel flow best practices](/blog/cancel-flow-best-practices/), compare [pause vs discount offers](/blog/pause-vs-discount-retention-offers/), or see [B2B SaaS](/use-cases/b2b-saas/). --- # Chargebee Retention alternative: NoChurn vs Chargebee Retention Source: https://www.nochurn.sh/compare/chargebee-retention/ Chargebee Retention is the cancel experience product that Chargebee built on its acquisition of Brightback. It focuses on what happens when a customer clicks cancel: the page they see, the offers they get and the reasons they give. In Chargebee's current docs it sits within Chargebee Growth. NoChurn covers that moment too, along with failed payments and win-back, for teams on Stripe or any billing through a REST API. This page reflects Chargebee's public docs and third-party listings as of November 2026. Prices change; check the sources below. ## At a glance | | NoChurn | Chargebee Retention | |---|---|---| | Pricing model | Flat monthly price by MRR band | Base plans (Essentials, Performance, Enterprise) with a monthly allotment of cancel sessions, plus overage fees | | Starting price | Free until $300 MRR, then from $9/month | Essentials from $250/month for 50 sessions, according to Brightback and G2 [À VÉRIFIER current price] | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Chargebee Billing, Stripe, Recurly; a setup without billing integration is documented | | Failed payments | Smart retries, AI-written emails, hosted card update page | Not part of the Retention docs we reviewed; Chargebee Billing has its own dunning [À VÉRIFIER] | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Personalized cancel page with discount, pause, extension and plan change offers | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | [À VÉRIFIER] | | Custom data / AI | Send any attribute or event; statistics find churn drivers, AI explains them; churn score at signup | Billing data enrichment to target offers; retention reporting | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | JavaScript install and a precancel API | | Contract | Self-serve up to $399/month | Plan bought in-app; Enterprise on quote [À VÉRIFIER] | ## Where Chargebee Retention is a good fit - **You already bill with Chargebee.** Retention is part of the same vendor, the configuration adapts to your billing integration, and you deal with one company for billing and retention. NoChurn's one-click Chargebee connector is planned but not available yet; until then it is our API. - **You are a larger team with a dedicated retention owner.** The product has years of use in companies that run structured cancel experiences, with targeting based on billing data. - **You want offers applied directly in Stripe or Recurly.** Retention can apply pauses, discounts, extensions and plan changes to the matching subscription, with options like proration on Stripe. ## Where NoChurn is different **Price by MRR, not by cancel sessions.** You do not count sessions, watch a rolling 30-day limit or pay per extra session. NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR. See [pricing](/pricing/). **Every feature on every plan.** Cancel flows, failed payments, win-back, custom data, churn score, API and MCP are included from the free plan. **Never a cut of recovered revenue.** **Failed payments and cancellations in one tool.** NoChurn retries failed payments at times tied to likely paydays and the customer's local time (or you keep Stripe Smart Retries), sends AI-written emails on days 0, 3, 7 and 14 that you review first, and hosts a card update page where card data stays with Stripe. See [failed payments](/#dunning). **Click-to-cancel built in.** A one-click "cancel now" is visible on every step. Offers are a choice, not a wall. **Headless and MCP.** Use the hosted modal with your theme, fonts, logo and custom CSS, or build the flow yourself on web, desktop, iOS or Android with the API. Coding agents can wire it in with our MCP server. See [headless and MCP](/#mcp). **Churn score at signup.** A 0 to 100 score from payment method, signup source and custom data, plus an alert and save flow when a customer removes their card before renewal. See [churn score](/#score). **Churn drivers from your data.** Send any attribute or usage event. Statistics computed in code show which attributes go with churn; AI explains the results. Correlation, not cause. NoChurn is new, with no customer results yet. Chargebee is an established billing company. ## Switching from Chargebee Retention 1. **Connect Stripe** with the [quickstart](/docs/quickstart/), or plan an API integration if you bill with Chargebee or Recurly. 2. **Rebuild your cancel page.** List each reason, its targeting and its offer. In NoChurn, offers map to a Stripe coupon, a pause, a downgrade or a call. 3. **Run both for a test period.** Send part of your cancel clicks to NoChurn and the rest to your current page, then compare saves for the same weeks. 4. **Check your session plan dates** so you do not pay for a period you no longer need. 5. **Add win-back and recovery emails** once the cancel flow is live. ## How NoChurn helps NoChurn handles failed payments, cancel flows with click-to-cancel, and win-back at 30, 60 and 90 days, for one flat price based on MRR. See the [cancel flow](/#cancel), learn about [Stripe customer portal cancellation](/blog/stripe-customer-portal-cancellation/), or read [cancel flow best practices](/blog/cancel-flow-best-practices/). --- # Paddle Retain alternative: NoChurn vs Paddle Retain Source: https://www.nochurn.sh/compare/paddle-retain/ Paddle Retain began life as ProfitWell Retain. Paddle acquired ProfitWell in 2022 and folded Retain into its platform. Today it handles failed payment recovery and, for Paddle Billing customers, cancellation flows. NoChurn does the same jobs plus win-back for teams on Stripe, or any billing through a REST API, and charges one flat price based on MRR. This page reflects Paddle's public pages as of November 2026. Paddle has been moving Retain features between products, so check the sources below. ## At a glance | | NoChurn | Paddle Retain | |---|---|---| | Pricing model | Flat monthly price by MRR band | Included at no extra cost on Paddle Billing; on other platforms, a monthly commission on revenue recovered | | Starting price | Free until $300 MRR, then from $9/month | Free with Paddle Billing; standalone commission rate not published | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Paddle Billing and Paddle Classic; Stripe, Chargebee, Recurly and Braintree for standalone use | | Failed payments | Smart retries, AI-written emails, hosted card update page | Recovery emails and retry timing, up to 7 retries | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Cancellation flows launched from the Paddle customer portal; Paddle Billing only | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | [À VÉRIFIER] | | Custom data / AI | Send any attribute or event; statistics find churn drivers, AI explains them; churn score at signup | Not found in the pages we reviewed [À VÉRIFIER]; term optimization (annual plan offers) on Paddle Billing | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Paddle developer docs for Retain [À VÉRIFIER headless support] | | Contract | Self-serve up to $399/month | Part of your Paddle agreement; standalone terms on request | ## Where Paddle Retain is a good fit - **You already bill with Paddle Billing.** Retain is included at no extra cost, and the customer portal can launch cancellation flows automatically. Adding another paid tool on top only makes sense if you need something Retain does not cover. - **You want Paddle as merchant of record.** Paddle bundles billing, tax and retention in one vendor. NoChurn is not a billing system or a merchant of record. - **You prefer to pay only when something is recovered.** On other billing platforms, Retain is priced as a commission on what it recovers each month. Some teams like that model because the cost tracks results. ## Where NoChurn is different **A flat price, never a commission.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR. We never take a share of recovered revenue, so the more we recover, the cheaper each recovered dollar gets. See [pricing](/pricing/). **Every feature on every plan.** Cancel flows, win-back, custom data and API are not reserved for one billing platform or tier. **Stripe first, any billing through the API.** Stripe connects in one click. Without Stripe, you keep your billing and send subscriptions, payments and cancellations to our REST API. A one-click Paddle connector is planned, with no date yet. **Recovery you can read before it goes out.** Retries can be timed to likely paydays and the customer's local time, or you keep Stripe Smart Retries. AI-written emails on days 0, 3, 7 and 14 are reviewed before sending and written in the customer's language. Replies are read and answered or sent to your team. See [failed payments](/#dunning). **Click-to-cancel built in.** A one-click "cancel now" is visible on every step of the flow. **Headless and MCP.** Use the hosted modal (themes, fonts, custom CSS) or render the flow yourself on web, desktop, iOS or Android through the API. Coding agents can integrate it with our MCP server. See [headless and MCP](/#mcp). **Churn score at signup.** A 0 to 100 score from payment method, signup source and custom data. Customers who remove their card before renewal are flagged so a save flow can start before the payment fails. See [churn score](/#score). **Churn drivers.** Send any attribute or usage event and see which ones go with churn, with sample size and confidence. Correlation, not cause. NoChurn is new and has no customer results to cite. Paddle has run Retain at scale for years. ## Switching from Paddle Retain 1. **If you are on Stripe**, connect it in a few minutes with the [quickstart](/docs/quickstart/). If you are on Paddle Billing, use our API until the Paddle connector ships, and weigh that against Retain being included in your plan. 2. **Pick one owner for retries and emails.** During a test period, split customers so each failed payment is handled by one tool only. 3. **Set up your cancel reasons and offers**, and the win-back emails for each reason. 4. **Compare cost and results** for the same weeks: your Retain commission against NoChurn's flat price, and recovered payments in each group. ## How NoChurn helps NoChurn recovers failed payments, runs an honest cancel flow and sends win-back emails at 30, 60 and 90 days, for one flat price by MRR with every feature included. Read about [Stripe Smart Retries](/blog/stripe-smart-retries/), [involuntary churn](/blog/involuntary-churn/), or see [pricing](/pricing/). --- # Baremetrics Recover alternative: NoChurn vs Baremetrics Source: https://www.nochurn.sh/compare/baremetrics/ Baremetrics is best known for subscription analytics: MRR, churn, LTV and the dashboards around them. Two add-ons cover retention. Recover handles failed payments, and Cancellation Insights collects cancel reasons and, more recently, shows retention offers. NoChurn is a retention tool only. It covers failed payments, cancel flows and win-back for teams on Stripe, or any billing through a REST API. This page reflects Baremetrics' public pages as of November 2026. Check the sources at the bottom for current prices. ## At a glance | | NoChurn | Baremetrics | |---|---|---| | Pricing model | Flat monthly price by MRR band | Analytics plans priced on ARR tracked, plus add-ons | | Starting price | Free until $300 MRR, then from $9/month | Analytics from $69/month (Growth); Recover add-on $129/month or 10% of recovered revenue; Cancellation Insights add-on $129/month | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe confirmed for Recover and retention offers; other platforms for analytics [À VÉRIFIER for Recover] | | Failed payments | Smart retries, AI-written emails, hosted card update page | Email, SMS, in-app banner and paywall in one sequence; works alongside Stripe Smart Retries for retries | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Cancellation widget with reason-based retention offers applied as Stripe discounts; behind a feature flag as of June 2026 | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | [À VÉRIFIER] | | Custom data / AI | Send any attribute or event; statistics find churn drivers, AI explains them; churn score at signup | Full subscription analytics and segmentation; Stripe cancel reasons as customer attributes | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Baremetrics API for metrics [À VÉRIFIER headless cancel flow] | | Contract | Self-serve up to $399/month | Monthly; Cancellation Insights also $1,290/year [À VÉRIFIER] | ## Where Baremetrics is a good fit - **You want analytics and retention from one vendor.** If your finance or growth team already lives in Baremetrics dashboards, adding Recover or Cancellation Insights keeps everything in one place. NoChurn shows retention results, but it is not a full subscription metrics tool. - **You want SMS, in-app banners or a paywall for failed payments.** Recover combines these with email in one sequence. NoChurn recovery runs over email and a hosted card update page. - **You are happy with Stripe Smart Retries and want better emails on top.** That is how Baremetrics describes Recover working with Stripe. - **You prefer to pay on results for recovery.** Baremetrics offers Recover at a percentage of recovered revenue as an alternative to the flat add-on. ## Where NoChurn is different **One price for everything, by MRR.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR. Failed payments, cancel flows and win-back are all included, with no add-ons. See [pricing](/pricing/). **Never a cut of recovered revenue.** There is no percentage option, now or later. **Recovery that can also handle retries.** Retries can be timed to likely paydays and the customer's local time, or you can keep Stripe Smart Retries. AI-written emails on days 0, 3, 7 and 14 are reviewed before sending, in the customer's language. Replies are read and answered or routed to your team. See [failed payments](/#dunning). **A complete cancel flow with click-to-cancel.** Reason, matching offer (Stripe coupon, pause, downgrade or call), confirm, with a one-click "cancel now" on every step. Available to every account, not behind a flag. **Headless and MCP.** Use the hosted modal with your theme and custom CSS, or build the flow in your own web, desktop, iOS or Android UI through the API. Coding agents can integrate it with our MCP server. See [headless and MCP](/#mcp). **Churn score at signup.** Each new customer gets a 0 to 100 score from payment method, signup source and custom data. Customers who remove their card before renewal trigger a save flow before the payment fails. See [churn score](/#score). **Churn drivers, not just churn charts.** Send any customer attribute or usage event. Statistics computed in code show which attributes go with churn, with sample size and confidence, and AI explains what to try. Correlation, not cause. See [custom data](/#insights). NoChurn is new, with no customer results to cite. Baremetrics has years of production use. ## Switching from Baremetrics You do not have to drop Baremetrics analytics to use NoChurn for retention. 1. **Connect Stripe** with the [quickstart](/docs/quickstart/). It takes a few minutes. 2. **Turn off overlapping emails.** If you move recovery to NoChurn, switch off Recover's sequence for the customers NoChurn handles, so nobody gets two sets of emails. 3. **Recreate your cancel reasons and offers** in NoChurn, and add win-back emails for each reason. 4. **Run both during a test period** on separate customer groups, then compare recovered payments and saves for the same weeks. 5. **Keep Baremetrics for metrics** if you like it, and cancel only the add-ons you no longer need. ## How NoChurn helps NoChurn recovers failed payments, keeps cancelling customers with honest offers, and wins back churned customers at 30, 60 and 90 days, for one flat price by MRR. Read [how to calculate churn rate](/blog/how-to-calculate-churn-rate/), [predict churn with customer data](/blog/predict-churn-with-customer-data/), or see [pricing](/pricing/). --- # Stripe's built-in retention tools vs NoChurn Source: https://www.nochurn.sh/compare/stripe-billing/ If you bill with Stripe, you already have a set of retention tools: Smart Retries, failed payment emails, automatic card updates and a customer portal that can ask for a cancel reason and show an offer. Many teams should start there. NoChurn is not a replacement for Stripe Billing. It connects to your Stripe account and adds the parts Stripe does not cover, or covers only lightly. This page is based on Stripe's docs as of November 2026. Stripe ships often; check the linked docs for the current behavior. ## At a glance | | NoChurn (on top of Stripe) | Stripe Billing built-in tools | |---|---|---| | Pricing model | Flat monthly price by MRR band | Included in Stripe Billing; pay-as-you-go Billing is 0.7% of billing volume, on top of payment processing fees | | Starting price | Free until $300 MRR, then from $9/month | No extra cost beyond Billing | | Billing platforms | Stripe (one click); any billing via REST API | Stripe only | | Failed payments | Payday and local-time retries or keep Smart Retries; AI-written emails on days 0, 3, 7, 14, reviewed before sending; replies handled | Smart Retries (machine-learned timing) or a custom schedule of up to 3 retries; automatic emails for failed payments, expiring cards and payment methods needing an update; automatic card updates | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step; hosted or headless | Customer portal cancellation with reasons and retention rules (conditional offers, for example by reason) | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Not a built-in feature | | Custom data / AI | Churn drivers from your own attributes; churn score at signup | Retention performance reporting; cancel reasons via webhooks and Sigma | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Full Stripe API; portal is Stripe-hosted | | Contract | Self-serve up to $399/month | Part of your Stripe account | ## What Stripe already does well **Smart Retries.** Stripe recommends Smart Retries, which choose retry times using data across its network. You can also set a custom schedule with up to three retries. Settings live under Billing, Revenue recovery, Retries. See our guide to [Stripe Smart Retries](/blog/stripe-smart-retries/). **Customer emails.** Stripe can email customers automatically when a payment fails, when a card is about to expire, or when a payment method needs an update. **Automatic card updates.** Stripe works with card networks to update saved cards when a bank issues a replacement. Coverage is wide in the United States and varies by country, and Stripe itself advises keeping a way for customers to update their card. Read more about [expiring cards](/blog/expiring-cards/). **Cancellation reasons and offers in the customer portal.** The portal can collect a cancel reason. Retention rules, which replace the older retention coupon setting, let you show an offer under conditions such as a specific reason or how long someone has subscribed. Stripe also reports on retention performance. See [Stripe customer portal cancellation](/blog/stripe-customer-portal-cancellation/). **Where Stripe alone is enough.** If your volume is small, your customers are mostly on cards with good updater coverage, and you only need one offer at cancel time, Stripe's tools may be all you need for now. NoChurn is free until $300 MRR, so you can try both, but there is no reason to add a tool you do not need. ## Where NoChurn adds to Stripe **Recovery emails that read like you wrote them.** NoChurn writes recovery emails with AI for each failed payment, in the customer's language (English, German, French, Italian or Portuguese), and you review them before they send. Replies are read, sorted, and answered or routed to your team. The hosted card update page keeps card data with Stripe; NoChurn never sees card numbers. **Retry timing, your choice.** Keep Smart Retries, or let NoChurn time retries to likely paydays and the customer's local time. **A full cancel flow.** Reason, matching offer (a Stripe coupon, `pause_collection`, a downgrade or a call), confirm. A one-click "cancel now" is visible on every step. Use the hosted modal with your colors, fonts, logo and custom CSS, or go fully headless and render it in your own web, desktop, iOS or Android app. See [cancel flows](/#cancel). **Win-back.** Emails at 30, 60 and 90 days after cancellation, written from the reason the customer gave. See [win-back](/#winback). **Churn score at signup.** NoChurn reads the payment method Stripe already knows about. Prepaid and disposable virtual cards score as high risk; neobank cards as medium; Stripe Link, Apple Pay, Google Pay, bank cards and SEPA as low. Levels adjust to your own history. If a customer removes their card before renewal, NoChurn starts a save flow before the payment fails. See [churn score](/#score). **Churn drivers from your data.** Send attributes like signup source, plan or key usage. NoChurn computes which ones go with churn, with sample size and confidence, and explains the results. Correlation, not cause. **MCP and API.** Coding agents can integrate NoChurn through our MCP server; everything is available over a REST API with signed webhooks. **Pricing.** Every feature on every plan, priced by MRR: free until $300, then from $9/month up to $399/month at $500k. Never a share of recovered revenue. See [pricing](/pricing/). NoChurn is new and has no customer results to cite yet. ## Adding NoChurn to your Stripe setup 1. **Connect Stripe** in a few minutes with Stripe Connect. See the [quickstart](/docs/quickstart/). 2. **Decide who sends failed payment emails.** If NoChurn handles recovery emails, turn off Stripe's failed payment emails for those customers so nobody gets both. 3. **Decide who times retries.** Keep Smart Retries or switch to NoChurn timing; do not run two retry schedules. 4. **Choose your cancel entry point.** Keep the Stripe portal for billing details and send the cancel button to the NoChurn flow, or test the two side by side for a period. 5. **Compare results** for the same weeks before you settle on a setup. ## How NoChurn helps NoChurn works alongside Stripe Billing: it adds reviewed, AI-written recovery emails, a full cancel flow with click-to-cancel, win-back at 30, 60 and 90 days, and a churn score at signup, for one flat price by MRR. Start with [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/) or [failed payments](/#dunning). --- # Recurly Engage alternative: NoChurn vs Recurly Engage Source: https://www.nochurn.sh/compare/recurly-engage/ Recurly Engage is Recurly's retention and lifecycle product. It shows targeted prompts on your website and in your apps (cancel saves, payment failure reminders, upsells, resubscribe offers) and can act on the billing record in one click. NoChurn covers the retention side of that list for subscription businesses on Stripe, or on any billing system through a REST API, with a flat price based on your MRR. The two products are built for different buyers. Engage is a marketing and lifecycle platform sold on annual terms, with many connectors and A/B testing. NoChurn is a self-serve tool focused on four jobs: failed payments, cancel flows, win-back and churn scoring, plus chargebacks. This page compares them as of November 2026, from Recurly's public pricing page and Engage documentation. ## At a glance | | NoChurn | Recurly Engage | |---|---|---| | What it is | Subscription retention: failed payments, cancel flows, win-back, churn score, chargebacks | Low-code platform for in-app and web prompts across the subscriber lifecycle: cancel save, payment failure, onboarding, upsell, resubscribe | | Pricing model | Flat monthly price by MRR band | Annual contract based on prompt volume and capabilities | | Starting price | Free until $300 MRR, then from $9/month | "As low as $1,600 per month, billed annually" on Recurly's pricing page | | Self-serve | Yes, sign up and connect in minutes | Free sandbox for Recurly customers; production through Recurly's team | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Recurly (native), plus connectors listed for Stripe, Chargebee, Zuora, Braintree, Chargify, Vindicia, Piano, Cleeng, Evergent, Ordergroove, Shopify and others; also sold standalone, without Recurly billing | | Failed payments | Smart retries, AI-written emails reviewed before sending, hosted card update page | In-app and web prompts that ask the customer to update payment details; retries stay in your billing system | | Cancel flow | Reason, matching offer, confirm; one-click cancel visible on every step; hosted or headless | Multi-step cancel save survey with tailored offers and 1-Click billing actions | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | 1-Click resubscribe prompts for churned users who visit your site or app | | Churn prediction | Churn score from 0 to 100 at signup; churn drivers from your own attributes | Propensity-to-churn model listed in the Engage plan | | Experiments | Compare results over the same period | A/B testing of prompts against custom goals | | Channels | Hosted modal, headless API, email, in-app wall or banner after a failed payment | JavaScript tag (web and CTV), Android, React Native and Roku SDKs, push prompts | Recurly figures come from its pricing page and Engage documentation, accessed November 7, 2026. ## Where Recurly Engage is a better fit - **You want one platform for the whole subscriber journey.** Engage covers onboarding, feature adoption, upsell and cross-sell prompts as well as retention. NoChurn does not do onboarding guides or upsell campaigns. - **You run many experiments.** A/B testing of prompts against your own goals is built into Engage. NoChurn has no built-in A/B testing. - **You have a marketing team and a large audience.** Engage connects to tools such as Braze, Iterable, Salesforce Marketing Cloud, Segment, Amplitude and Mixpanel, and its prompts are built in a low-code console. That suits a lifecycle team running campaigns at volume. - **You ship on TV and streaming devices.** Engage lists SDKs for Roku and CTV browsers, and in-app purchase flows on Roku, Apple and Google devices. NoChurn has no TV SDK. - **You are already on Recurly and will negotiate an annual bundle.** Recurly's pricing page says the more of its products you use, the better the deal, and Engage is available in Hosted Account Management and Recurly Checkout without extra tagging. ## Where NoChurn is different **Price follows your size, from zero.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with a quote above that. No annual commitment, no prompt volume to forecast. See [pricing](/pricing/). **Self-serve, in minutes.** Connect Stripe in one click, or send subscriptions, payments and cancellations from your own billing through the API. A test mode lets you try everything without touching real customers. **Every feature on every plan.** Failed payment recovery, cancel flows, win-back, churn score, custom data, chargebacks and the API are all on the free plan too. **Recovery emails, not only prompts.** A prompt only reaches a customer who comes back to your product. NoChurn also writes recovery emails with AI for each failed payment, in the customer's language, and you review them before they go out. Logged-in customers can see an in-app wall or banner with a link to pay. See [failed payments](/#dunning). **Click-to-cancel built in.** A one-click "cancel now" stays visible on every step of the NoChurn flow. Offers are shown, never forced. See [cancel flows](/#cancel). **Headless when you want your own UI.** Use the hosted modal (themes, fonts, colors, logo, custom CSS) or fetch reasons and offers from the API and render them in your web, desktop, iOS or Android app. An MCP server lets a coding agent wire it in. See [headless API](/features/headless-api/). **Chargebacks included.** When a dispute opens on Stripe or Braintree, NoChurn gathers the evidence it already has and drafts a reply for a person on your team to review. See [chargebacks](/#disputes). NoChurn is new and has no customer results to show. Recurly has run subscription billing for years and Engage is a mature lifecycle product. Weigh that honestly. ## Using both, or switching If you bill with Recurly, you do not have to choose between Recurly's tools and NoChurn. Recurly keeps retries, dunning and invoicing; NoChurn connects with a Recurly API key and adds recovery emails, the cancel flow, win-back and the churn score. See [NoChurn + Recurly](/integrations/recurly/) and our guide to [dunning in Recurly](/blog/recurly-dunning/). If you use Engage today and want to move retention to NoChurn: 1. **Connect your billing** in test mode first: Stripe in one click, Recurly or another provider with an API key, or the REST API. Follow the [quickstart](/docs/quickstart/). 2. **List your cancel save prompts.** Write down each reason and the offer tied to it, then recreate them in NoChurn as a coupon, a pause, a plan change or a call. 3. **Pick one owner for payment failure messages.** If NoChurn sends recovery emails, turn off overlapping Engage payment failure prompts, or keep them for in-app reminders only, so nobody gets two sequences. 4. **Keep what NoChurn does not do.** Onboarding, upsell and push campaigns can stay in Engage. 5. **Compare the same weeks** (save rate, recovered payments, complaints) before you decide, and check your Engage renewal date, since it is billed annually. ## FAQ ### How much does Recurly Engage cost? Recurly's pricing page lists Engage "as low as $1,600 per month, billed annually", based on prompt volume and capability needs, as of November 2026. The exact price comes from Recurly's sales team. ### Does Recurly Engage require Recurly billing? No. Recurly's docs say Engage is also available as a standalone platform, with connectors for Stripe, Chargebee, Zuora, Braintree and other billing systems. Recurly asks you to contact its team for standalone pricing. ### Does NoChurn work with Recurly? Yes. NoChurn connects with a Recurly private API key, imports accounts and subscriptions, follows Recurly webhooks and applies offers such as coupons, pauses or plan changes to the Recurly subscription. ### Does NoChurn do A/B testing? Not as a built-in feature. You can compare save rates and recovered payments over the same period, but there is no split-testing engine. ## How NoChurn helps NoChurn recovers failed payments with smart retries and reviewed, AI-written emails, keeps cancelling customers with an honest, reason-based flow where "cancel now" is always one click away, and wins back churned ones at 30, 60 and 90 days. It works with Stripe in one click or with any billing through the API, for one flat price by MRR. Start with the [cancel flow](/#cancel), [failed payments](/#dunning) or [pricing](/pricing/). --- # Raaft alternative: NoChurn vs Raaft Source: https://www.nochurn.sh/compare/raaft/ Raaft is a no-code tool for building cancellation flows in SaaS products. You design a flow, show it when a customer clicks cancel, and offer a coupon, a pause, a plan switch, a custom link or a callback before they leave. NoChurn has a cancel flow too, but it also recovers failed payments, sends win-back emails, scores churn risk and helps with chargebacks, for one flat price based on your MRR. This page reflects Raaft's public pricing page and help center as of November 2026. Check the sources at the bottom for anything that may have changed. ## At a glance | | NoChurn | Raaft | |---|---|---| | Pricing model | Flat monthly price by MRR band | By sessions per month (a session is one unique user, one unique outcome, one day) | | Starting price | Free until $300 MRR, then from $9/month | Free plan with up to 20 sessions per month; Basic at $79/month; extra sessions at $3 each; Enterprise on quote | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe, Braintree, Recurly, Chargebee and Paddle on Basic; custom payment integrations on Enterprise; Zapier | | Cancel flow | Reason, matching offer (discount, pause, plan change), confirm; one-click cancel on every step; hosted modal or headless API | No-code flows with coupons, pauses, plan switches, custom links or callback requests | | Cancellation handling | Executed in your billing system, or sent to you by API and webhook | Automatic when a payment processor is connected, otherwise an email to your support team | | Failed payments | Smart retries, AI-written emails you can review, hosted card update page | Not covered on the pages we reviewed | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Not covered on the pages we reviewed | | Chargebacks | Evidence gathered automatically, AI-drafted reply sent after human review (Stripe, Braintree) | Not covered on the pages we reviewed | | Reporting | Churn score at signup, churn drivers from your own data | Churn reporting filterable by plan, segment, flow and period | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Not covered on the pages we reviewed | ## Where Raaft is a good fit - **You only need a cancel flow.** If failed payments are already handled elsewhere and you want a simple, visual flow builder, Raaft does that one job without extra moving parts. - **You have few cancellations a month.** The free plan covers up to 20 sessions per month, which can be enough for an early product. - **You want someone to build the flow for you.** Raaft's Enterprise plan lists done-for-you flows and a dedicated account manager. - **You want to test flows without touching real data.** Raaft has a demo mode where outcomes are not recorded. ## Where NoChurn is different **Price follows your size, not your traffic.** Raaft's price depends on how many sessions you use. NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with custom pricing above. A busy cancellation month does not change your bill. See [pricing](/pricing/). **Every feature on every plan.** Cancel flows, failed payment recovery, win-back, churn score, custom data, chargebacks and the API are all on the free plan. **Never a cut of recovered revenue.** We do not charge a percentage of what we save or recover. **Failed payments in the same tool.** On Stripe, NoChurn times retries to the decline reason and to likely paydays. It sends AI-written recovery emails you can review and a link to a hosted card update page. On other billing tools, NoChurn adds the emails and card update link next to the provider's own dunning. See [failed payments](/#dunning). **Win-back after the cancel.** Customers who leave get emails at 30, 60 and 90 days, chosen from the reason they gave in the cancel flow. See [win-back](/#winback). **Click-to-cancel built in.** A one-click "cancel now" stays visible on every step. Offers are shown, never forced. **Headless and MCP.** Use the hosted modal, or fetch reasons and offers from the API and render them in your own web, desktop, iOS or Android UI. A coding agent can wire it up through our MCP server. See [headless and MCP](/#mcp). **Churn score and chargebacks.** Every customer gets a 0 to 100 score at signup and on every change. Disputes on Stripe and Braintree get evidence gathered automatically and a reply drafted by AI, sent only after a person on your team reviews it. NoChurn is new and has no customer results to show yet. Weigh that against a tool that has been running in production for longer. ## Switching from Raaft 1. **Connect your billing.** Stripe takes a few minutes with the [quickstart](/docs/quickstart/); other billing tools connect directly or through the API. 2. **Copy your reasons and offers.** List each Raaft flow, its reasons and the offer tied to each, then recreate them in NoChurn. Make sure the coupons you use exist in your billing system. 3. **Decide who executes the cancel.** If Raaft was emailing your support team instead of cancelling, decide whether NoChurn cancels in your billing system or sends you a webhook. 4. **Run both on separate groups for a while**, then compare saves and complaints for the same weeks and keep one. ## How NoChurn helps NoChurn runs an honest, reason-based cancel flow with click-to-cancel, recovers failed payments and wins back churned customers at 30, 60 and 90 days, all for one flat price by MRR. See the [cancel flow](/#cancel), [pricing](/pricing/) or the [quickstart](/docs/quickstart/). --- # Recurflux alternative: NoChurn vs Recurflux Source: https://www.nochurn.sh/compare/recurflux/ Recurflux is a young retention tool built around a failed payment queue. It sends recovery emails, offers a cancellation flow with pauses and discounts, and runs win-back emails after a cancel. Like NoChurn, it charges a flat monthly fee rather than a share of recovered revenue. The two products overlap a lot, so the differences are in billing coverage, what each plan includes and how much of it you can drive by API. This comparison is based on Recurflux's own pages as of November 2026. Some of those pages disagree with each other on price and plan contents; we flag those cells below. ## At a glance | | NoChurn | Recurflux | |---|---|---| | Pricing model | Flat monthly price by MRR band, every feature on every plan | Flat monthly price by MRR tier; some features depend on the tier | | Starting price | Free until $300 MRR, then from $9/month | From $20/month up to $10k MRR on its home page; other pages state $59/month [À VÉRIFIER] | | Higher tiers | $49/month to $75k MRR, $149/month to $200k MRR, $399/month to $500k MRR, custom above | $59/month to $75k MRR, $159/month to $200k MRR, custom above, per its home page [À VÉRIFIER] | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe, Paddle, Razorpay, Cashfree, RevenueCat (App Store and Google Play) | | Failed payments | Smart retries timed to decline reason and payday (Stripe), AI-written emails you can review, hosted card update page | Failed payment queue, recovery email sequences chosen by failure code | | Cancel flow | Reason, matching offer (discount, pause, plan change), confirm; one-click cancel on every step | Reason survey with pause or discount offers; basic or full builder depending on tier [À VÉRIFIER] | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Win-back sequence after cancellation, stopped on reactivation | | Chargebacks | Evidence gathered automatically, AI-drafted reply sent after human review (Stripe, Braintree) | Not covered on the pages we reviewed | | Churn score / custom data | Score 0 to 100 at signup and on every change; churn drivers from your own data | Not covered on the pages we reviewed | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Not covered on the pages we reviewed | ## Where Recurflux is a good fit - **You bill through Cashfree.** Recurflux lists Cashfree; NoChurn does not have a native connector for it and you would use our REST API. - **You sell mostly through mobile apps on RevenueCat.** Recurflux has a dedicated RevenueCat offering with its own, lower tiers. - **You want a failed payment queue with owners.** Recurflux is built around assigning failed payments and tracking next actions. ## Where NoChurn is different **Every feature on every plan.** NoChurn has no feature tiers. The free plan has the same cancel flow, recovery, win-back, churn score, chargebacks and API as Scale. You only move up a plan when your MRR grows. See [pricing](/pricing/). **Never a cut of recovered revenue.** Like Recurflux, we never charge a percentage of what we recover. **Wider billing coverage.** Besides Stripe, Paddle, Razorpay, the App Store and Google Play, NoChurn connects to Chargebee, Recurly, Maxio, Zuora, Lemon Squeezy, Polar, Braintree, Mollie and GoCardless, and to anything else through the REST API. On billing tools other than Stripe, NoChurn adds AI emails and a card update link next to the provider's own dunning. **Chargebacks.** On Stripe and Braintree, NoChurn gathers evidence (cancel flow answers, emails sent, usage, support conversations) and drafts a reply that is sent only after a person reviews it. On Stripe, early fraud warnings come with a one-click refund. Disputes on merchants of record such as Paddle are handled by the merchant of record and shown read only. **Churn score and churn drivers.** Every customer gets a 0 to 100 score at signup and on every change. Send your own attributes by API and see which ones go with churn. Correlation, not causation. See [churn score](/#score). **Headless and MCP.** The cancel flow can be our hosted modal or fully headless through the API, and coding agents can integrate NoChurn through our MCP server. See [headless and MCP](/#mcp). NoChurn is new too, and neither of us has years of production history. We publish no customer results because we have none yet. ## Switching from Recurflux 1. **Connect your billing** with the [quickstart](/docs/quickstart/). If you bill on Cashfree, plan the API integration first. 2. **Avoid double emails.** Run the two tools on separate customer groups during a test period so nobody gets two recovery sequences. 3. **Rebuild your cancel reasons and offers**, then set the win-back emails for each reason. 4. **Compare the same weeks**, then keep one tool. ## How NoChurn helps NoChurn recovers failed payments, runs a click-to-cancel flow with fair offers, wins back churned customers and handles chargeback evidence, for one flat price by MRR with every feature included. See [failed payments](/#dunning), [chargebacks](/#disputes) or [pricing](/pricing/). --- # Churn Solution alternative: NoChurn vs Churn Solution Source: https://www.nochurn.sh/compare/churn-solution/ Churn Solution is a retention tool that covers cancel flows, failed payment recovery and win-back. It stands out for its support of WordPress-based billing such as WooCommerce and Paid Memberships Pro, and for a pricing option where you pay a share of the revenue it helps keep. NoChurn covers the same jobs for teams on Stripe, other billing platforms or any billing through a REST API, and charges a flat price by MRR. This page is based on Churn Solution's public pages and docs as of November 2026. ## At a glance | | NoChurn | Churn Solution | |---|---|---| | Pricing model | Flat monthly price by MRR band | Either 25% of "boosted revenue" with a $50/month minimum, or a fixed price based on MRR | | Starting price | Free until $300 MRR, then from $9/month | $50/month minimum on the revenue share option; fixed prices shown as an estimate on their pricing page | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe, Braintree, Paddle, WooCommerce, Paid Memberships Pro, RecurPay | | Failed payments | Smart retries timed to decline reason and payday (Stripe), AI-written emails you can review, hosted card update page | Its own retry layer on top of Stripe's, recovery discounts, in-app banners, pop-ups and card update modal | | Cancel flow | Reason, matching offer (discount, pause, plan change), confirm; one-click cancel on every step | Segmented flows with pause, discount, period extension or cancel; Stripe coupons created beforehand | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Win-back campaigns | | Chargebacks | Evidence gathered automatically, AI-drafted reply sent after human review (Stripe, Braintree) | Not covered on the pages we reviewed | | Churn score / custom data | Score 0 to 100 at signup and on every change; churn drivers from your own data | Not covered on the pages we reviewed | | API / headless | REST API, signed webhooks, headless cancel flow, MCP server | Not covered on the pages we reviewed | | Trying it first | Free plan up to $300 MRR | Money-back guarantee; length differs between their pages [À VÉRIFIER] | ## Where Churn Solution is a good fit - **You bill through WooCommerce or Paid Memberships Pro.** Churn Solution supports these directly. NoChurn does not have native connectors for them; you would use our REST API. - **You prefer to pay only when it works.** Its revenue share option ties the fee to the revenue it helps keep, with a $50/month minimum. - **You want in-app payment walls and banners.** Churn Solution prompts customers inside your app to update a failed card. - **Customers hold several subscriptions.** Churn Solution treats each subscription separately by its own ID. ## Where NoChurn is different **Never a share of recovered revenue.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with custom pricing above. When recovery goes well, your bill stays the same. See [pricing](/pricing/). **Every feature on every plan.** Recovery, cancel flows, win-back, churn score, custom data, chargebacks and the API are all on the free plan. **Failed payments.** On Stripe, NoChurn times retries to the decline reason and to likely paydays, sends AI-written recovery emails you can review and links to a hosted card update page. On other billing tools, it adds those emails and the card update link next to the provider's own dunning. See [failed payments](/#dunning). **Click-to-cancel built in.** A one-click "cancel now" stays visible on every step of the flow. Offers are shown, never forced. See [cancel flows](/#cancel). **Chargebacks.** On Stripe and Braintree, NoChurn gathers evidence automatically (cancel flow answers, emails sent, usage, support conversations) and drafts a reply that is sent only after human review. Early fraud warnings on Stripe come with a one-click refund. **Headless, API and MCP.** Use the hosted modal or render reasons and offers in your own UI through the API. Signed webhooks and an MCP server help your team or a coding agent wire it up. See [headless and MCP](/#mcp). NoChurn is new and has no customer results to cite yet. ## Switching from Churn Solution 1. **Connect your billing** with the [quickstart](/docs/quickstart/). On WooCommerce or Paid Memberships Pro, plan an API integration. 2. **Recreate your segments, reasons and offers**, and check that the coupons you need exist in your billing system. 3. **Make sure only one tool retries.** Two retry layers on the same invoice can confuse customers and your reports. 4. **Check your billing terms** with Churn Solution before you turn it off, then compare results over the same weeks. ## How NoChurn helps NoChurn runs a click-to-cancel flow with fair offers, recovers failed payments, wins back churned customers and prepares chargeback replies, for a flat price by MRR. See [cancel flows](/#cancel), [win-back](/#winback) or [pricing](/pricing/). --- # Butter Payments alternative: NoChurn vs Butter Payments Source: https://www.nochurn.sh/compare/butter-payments/ Butter Payments focuses on one problem: failed payments. It replaces your billing system's native retries with its own retry decisions, and it is paid through a share of the revenue it recovers. NoChurn also recovers failed payments, but it covers cancel flows, win-back, churn score and chargebacks too, for a flat price based on MRR. This page reflects Butter's public pages and documentation as of November 2026. ## At a glance | | NoChurn | Butter Payments | |---|---|---| | Pricing model | Flat monthly price by MRR band | Revenue share: a percentage of each invoice recovered; no retainer | | Starting price | Free until $300 MRR, then from $9/month | Not public; quoted after a free payment health analysis | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Turnkey: Stripe Billing, Braintree, Recharge; in-house billing through its APIs and webhooks | | Setup | Stripe in one click; other billing directly or by API | API key for turnkey platforms, then a data ingestion period before retries start; native retries turned off | | Failed payments | Smart retries timed to decline reason and payday (Stripe), AI-written emails you can review, hosted card update page | Retry decisions made by its own models; customer outreach after a failure | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Not part of the Recover product | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Not part of the Recover product | | Chargebacks | Evidence gathered automatically, AI-drafted reply sent after human review (Stripe, Braintree) | Not covered on the pages we reviewed | | Reporting | Churn score, churn drivers from your own data | Quarterly performance reviews with dedicated support | ## Where Butter Payments is a good fit - **Failed payments are your largest churn source and your volume is high.** Butter is a specialist that works on retry decisions only, with dedicated support and quarterly reviews. - **You want to pay only for results.** A revenue share means no fixed fee when nothing is recovered. - **You run an in-house billing system.** Butter documents an API and webhook integration for that case. - **You sell e-commerce subscriptions on Recharge.** Butter supports Recharge as a turnkey integration; NoChurn does not have a native Recharge connector. ## Where NoChurn is different **A flat price, never a share.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with custom pricing above. The better recovery goes, the more a revenue share costs; a flat price does not move. See [pricing](/pricing/). **Self-serve.** You can connect Stripe and start without a sales call, up to $399/month. **More than retries.** NoChurn also runs a cancel flow with click-to-cancel, sends win-back emails at 30, 60 and 90 days by cancel reason, and scores every customer from 0 to 100 at signup and on every change. See [cancel flows](/#cancel) and [churn score](/#score). **Recovery emails you can read.** Alongside retries timed to the decline reason and to likely paydays, NoChurn writes recovery emails with AI that you can review, and sends customers to a hosted card update page. See [failed payments](/#dunning). **Chargebacks.** On Stripe and Braintree, evidence is gathered automatically and a reply is drafted by AI, then sent only after a person reviews it. On Stripe, early fraud warnings come with a one-click refund. See [chargebacks](/#disputes). **API and MCP.** REST API, signed webhooks, a headless cancel flow and an MCP server for coding agents. NoChurn is new and has no recovery results to show. Butter has a longer track record with retry models. If retry performance at large volume is all you care about, a specialist may suit you better. ## Switching from Butter Payments 1. **Check your contract** with Butter for notice terms before you switch. 2. **Connect your billing** with the [quickstart](/docs/quickstart/). 3. **Make sure only one system retries.** Butter's docs ask merchants to turn off native retries; when you leave, decide whether NoChurn times retries or you go back to your billing tool's own. 4. **Compare the same weeks** of recovered payments before you fully switch. ## How NoChurn helps NoChurn recovers failed payments, keeps cancelling customers with a fair flow, wins back churned ones and prepares chargeback replies, for one flat price by MRR. See [failed payments](/#dunning) or [pricing](/pricing/). --- # Gravy alternative: NoChurn vs Gravy Source: https://www.nochurn.sh/compare/gravy/ Gravy, run by Gravy Solutions at gravysolutions.io, is a failed payment recovery service rather than a software tool. Its retention specialists contact your customers whose payments failed, in your brand's name, and work to bring the payment back. NoChurn is self-serve software: smart retries, AI-written emails, a hosted card update page, cancel flows and win-back, for a published price by MRR. These are different kinds of products. This page compares them as of November 2026, based on Gravy's public pages. ## At a glance | | NoChurn | Gravy | |---|---|---| | Type | Self-serve software | Done-for-you service with human retention specialists | | Pricing model | Flat monthly price by MRR band, published | Custom flat fee, no percentage of revenue | | Starting price | Free until $300 MRR, then from $9/month | Not public; quoted after a free audit of your failed payment data | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Lists Stripe, Braintree, Recurly, Keap, Ontraport, SamCart and Teachable [À VÉRIFIER: list taken from older pages] | | Failed payments | Smart retries timed to decline reason and payday (Stripe), AI-written emails you can review, hosted card update page | Personal outreach by retention specialists over a set period | | Cancel flow | Reason, matching offer, confirm; one-click cancel on every step | Not covered on the pages we reviewed | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Restarting lapsed subscriptions is part of the outreach | | Chargebacks | Evidence gathered automatically, AI-drafted reply sent after human review (Stripe, Braintree) | Not covered on the pages we reviewed | | Setup | Connect your billing, then configure | Gravy's team works from access to your payment platform or CRM | ## Where Gravy is a good fit - **You want people, not software.** If you would rather a team talk to your customers for you, a done-for-you service is the better fit. NoChurn does not call or personally message your customers. - **Your customers respond to a human.** Courses, coaching and membership businesses with high-ticket plans may prefer person-to-person outreach. - **You sell through Keap, Ontraport, SamCart or Teachable.** Gravy lists these; NoChurn does not have native connectors for them and you would use our REST API. - **You want a free audit before deciding.** Gravy starts with an audit of your live failed payment data. ## Where NoChurn is different **A published price.** NoChurn is free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with custom pricing above. Never a share of recovered revenue. See [pricing](/pricing/). **Software you control.** You see every retry, every email and every customer in your own dashboard, and you can review AI-written emails before they go out. Nobody outside your team needs access to your CRM. **Before and after the failure.** On Stripe, retries are timed to the decline reason and to likely paydays. Customers get a link to a hosted card update page, and card data stays with your payment provider. On other billing tools, NoChurn adds emails and the card update link next to the provider's own dunning. See [failed payments](/#dunning). **Cancel flow and win-back.** A click-to-cancel flow with fair offers, and win-back emails at 30, 60 and 90 days by cancel reason. See [cancel flows](/#cancel). **Churn score and chargebacks.** Every customer gets a 0 to 100 score at signup and on every change. On Stripe and Braintree, chargeback evidence is gathered automatically and replies are sent only after human review. NoChurn is new and has no customer results yet. Gravy has run its service for years. ## Switching from Gravy 1. **Check your agreement** with Gravy for notice terms. 2. **Connect your billing** with the [quickstart](/docs/quickstart/). 3. **Tell customers what changes.** If Gravy's specialists were in touch with some customers, let open conversations finish before NoChurn emails them. 4. **Compare the same weeks** of recovered payments, then keep one approach. ## How NoChurn helps NoChurn automates failed payment recovery with smart retries and AI emails, adds a click-to-cancel flow and win-back, and costs a flat price by MRR. See [failed payments](/#dunning) or [pricing](/pricing/). --- # Stunning alternative: NoChurn vs Stunning Source: https://www.nochurn.sh/compare/stunning/ Stunning is one of the oldest failed payment recovery tools for Stripe. It replaces Stripe's failed payment emails with its own sequence, adds SMS and backup cards, and can run recovery for you through a managed service. Like NoChurn, it charges a flat fee based on MRR and never takes a share of what it recovers. This comparison reflects Stunning's public pages as of November 2026. ## At a glance | | NoChurn | Stunning | |---|---|---| | Pricing model | Flat monthly price by MRR band, every feature on every plan | Flat monthly price by MRR, every feature on every plan | | Price examples | Free until $300 MRR; $19/month to $10k; $49/month to $75k; $399/month to $500k | $60/month at $8k MRR and $120/month at $40k MRR on its pages; 15-day free trial | | Done-for-you option | No | Managed Recovery, priced by MRR on top of the software, after a paid one-time audit | | Billing platforms | Stripe, Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, App Store, Google Play; any other billing via REST API | Stripe (full feature set), Subbly and Foxy (smaller feature set) | | Failed payments | Smart retries timed to decline reason and payday (Stripe), AI-written emails you can review, hosted card update page | Up to 8 dunning emails, SMS, backup cards and pre-dunning on Stripe, alongside Stripe's own retries | | Cancel flow | Reason, matching offer (discount, pause, plan change), confirm; one-click cancel on every step | Cancellation emails; no cancel flow with offers on the pages we reviewed | | Win-back | Emails at 30, 60 and 90 days, based on the cancel reason | Win-back emails after a subscription goes unpaid | | Chargebacks | Evidence gathered automatically, AI-drafted reply sent after human review (Stripe, Braintree) | Not covered on the pages we reviewed | | Churn score / custom data | Score 0 to 100 at signup and on every change; churn drivers from your own data | Not covered on the pages we reviewed | ## Where Stunning is a good fit - **You want SMS in your dunning.** Stunning sends SMS on Stripe. NoChurn recovery runs over email. - **You want backup cards.** Stunning asks customers to add a second card, with a discount you choose, and charges it when the first one fails. - **You want someone to run recovery for you.** Its Managed Recovery service rewrites your emails, watches results and follows up with customers personally. - **You bill through Subbly or Foxy.** Stunning supports both; NoChurn does not have native connectors for them. - **You value a long track record.** Stunning has been doing Stripe dunning for many years. ## Where NoChurn is different **More than dunning, for a similar model.** Both tools charge flat by MRR with every feature on every plan. NoChurn's plans also include a cancel flow, win-back by cancel reason, churn score, custom data and chargebacks. See [pricing](/pricing/). **Retries timed by NoChurn on Stripe.** NoChurn can time retries to the decline reason and to likely paydays, instead of only adding emails around Stripe's own schedule. Recovery emails are written by AI and you can review them. See [failed payments](/#dunning). **Cancel flow with click-to-cancel.** Reason, matching offer, confirm, with a one-click "cancel now" on every step. Hosted modal or headless through the API. See [cancel flows](/#cancel). **Win-back by reason.** Customers who cancel get emails at 30, 60 and 90 days chosen from the reason they gave. See [win-back](/#winback). **Chargebacks.** On Stripe and Braintree, evidence is gathered automatically and replies are drafted by AI, then sent only after human review. On Stripe, early fraud warnings come with a one-click refund. See [chargebacks](/#disputes). **More billing tools and an API.** Beyond Stripe, NoChurn connects to Chargebee, Recurly, Paddle, Braintree, Mollie, the App Store, Google Play and more, or to any billing through the REST API, with signed webhooks and an MCP server. NoChurn is new and has no customer results to show. Stunning has years of production use on Stripe. ## Switching from Stunning 1. **Connect Stripe** with the [quickstart](/docs/quickstart/). 2. **Avoid double emails.** Run the tools on separate customer groups during a test period, and keep Stripe's own failed payment emails off if a tool is emailing. 3. **Decide on retries.** Choose whether NoChurn times retries or you keep Stripe's schedule. 4. **Set up your cancel flow and win-back**, then compare the same weeks and keep one tool. ## How NoChurn helps NoChurn recovers failed payments, runs a fair cancel flow, wins back churned customers and prepares chargeback replies, for one flat price by MRR. See [failed payments](/#dunning), [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/) or [pricing](/pricing/). --- # Build vs buy: NoChurn vs building churn tools in-house Source: https://www.nochurn.sh/compare/build-it-yourself/ Most teams on Stripe ask the same question at some point: why pay for a churn tool when Stripe already retries cards and can show a cancel page? It is a fair question. Stripe gives you good building blocks, and some teams should build. This page lists what Stripe gives you, what you would build on top, the work that tends to be underestimated, and when building is the better choice. We do not put a number of weeks or dollars on it. That depends on your team and your product, and any figure we gave would be a guess. ## At a glance | Job | What Stripe gives you | What you build on top | NoChurn | |---|---|---|---| | Failed payment retries | Smart Retries or a custom retry schedule; no automatic retry on hard declines such as lost or stolen cards | Your own timing logic if you want something other than Stripe's, plus reporting | Retries timed to the decline reason and to likely paydays, or keep Smart Retries | | Recovery emails | An email after each failed payment, with a link to update the payment method | Your own templates, sequence, languages, reply handling | AI-written emails you can review; hosted card update page | | Cancel flow | A cancellation page in the customer portal with a reason survey and a retention coupon; retention rules in private preview | Your own UI if you want custom offers, pauses, plan changes, branching by reason, analytics | Reason, matching offer (discount, pause, plan change), confirm; one-click cancel on every step; hosted or headless | | Win-back | Billing automations can email a customer when a subscription is canceled | Sequences over weeks, tied to the cancel reason, stopped on reactivation | Emails at 30, 60 and 90 days by cancel reason | | Chargebacks | Disputes API to upload evidence and stage or submit a response; dispute webhooks; early fraud warnings with webhooks | Collecting evidence from your app, emails and help desk; writing the reply | Evidence gathered automatically; AI-drafted reply sent after human review (Stripe, Braintree); one-click refund on early fraud warnings | | Churn risk | Payment method details on each customer | A scoring model and the data pipeline to feed it | Churn score 0 to 100 at signup and on every change; churn drivers from your own data | ## What Stripe already does well **Smart Retries.** Stripe can pick retry times with machine learning, or follow a custom schedule. Some decline codes, such as lost or stolen cards, are never retried automatically: the customer has to add a new payment method. After the last retry, your settings decide whether the subscription is canceled, marked unpaid, left past due or paused. **Failed payment emails.** Stripe can email the customer after each failed payment, with a link to update their payment method. It can also email customers when a payment needs authentication. **A cancellation page.** The Stripe customer portal can collect a cancellation reason and offer a retention coupon. Stripe is also previewing retention rules that target offers by reason, tenure, spend or metadata, and a retention performance dashboard. **Disputes API.** You can upload evidence files, set text evidence and stage a response before submitting it, and you receive dispute events by webhook. Early fraud warnings from card networks also arrive by webhook. If these cover your needs, you may not need any tool, ours included. ## The hidden work The building blocks are the easy part. The work that tends to take longer: **Decline codes.** Stripe documents dozens of decline codes, plus network decline codes and advice codes that differ by card brand. Choosing what to do for each one (retry, wait, ask for a new card, stop) is ongoing work, not a one-time mapping. **Payments that need authentication.** Under Strong Customer Authentication, a renewal can fail because the customer must confirm it, not because the card is bad. Stripe documents the states and events involved; your emails and UI have to bring the customer back to complete it, and your access rules have to handle subscriptions that are not yet active. **Idempotency.** Retries, webhooks and background jobs run more than once. Every write to Stripe should carry an Idempotency-Key, and every webhook should be deduplicated, or you risk double charges, double coupons or double emails. **Cancellation rules.** In the United States, the FTC's 2024 click-to-cancel rule was vacated by the Eighth Circuit in July 2025, but state laws still apply. California's automatic renewal law, for example, requires that customers who signed up online can cancel online, and allows a retention offer only alongside a clear way to cancel. Other states and countries have their own rules. A homemade cancel flow needs someone to keep up with this. This page is not legal advice. **Email delivery and replies.** Recovery emails have to land in the inbox, be translated, respect unsubscribes and handle the replies customers send back. **Testing.** Failed payments, authentication, disputes and early fraud warnings are hard to reproduce. Stripe provides test cards for many declines, but you still need test scenarios for each branch of your logic, and a way to make sure tests never email a real customer or move real money. **Chargeback evidence.** The disputes API accepts evidence, but it does not know what your customer did in your app, which emails they received or what they told your support team. Gathering that per dispute, before the deadline, is the slow part. **Measurement.** To know whether any of this works, you need recovery and save rates you trust, by cohort and over time. ## When building makes sense - **Stripe's built-in features are enough.** Smart Retries, failed payment emails and the portal's cancellation page cover many early products well. - **Retention is core to your product.** If your cancel experience is part of what you sell, or deeply tied to in-app state no tool can see, owning it can be worth it. - **You have unusual billing.** Custom contracts, invoicing by bank transfer or usage you settle by hand may not fit any tool's model. - **You have the team.** If you already have engineers who own billing and want to keep everything in-house, building avoids another vendor. ## When buying makes sense - **You want all of it now**, not a roadmap: retries, emails, cancel flow, win-back, chargebacks and scoring. - **Your engineers should work on your product**, not on decline codes and email deliverability. - **You bill outside Stripe too.** NoChurn connects to Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, the App Store and Google Play, or to anything through the REST API. You can also do both. NoChurn's cancel flow can run headless: you keep your own UI and fetch reasons and offers from the API. Signed webhooks tell your app what happened, and coding agents can wire it up through the MCP server. See [headless and MCP](/#mcp). ## What NoChurn costs Every feature on every plan. Free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, with custom pricing above. Never a share of recovered revenue. See [pricing](/pricing/). NoChurn is new and has no customer results to show yet. Building in-house is a real alternative, and for some teams the better one. ## How NoChurn helps NoChurn recovers failed payments, runs a click-to-cancel flow with fair offers, wins back churned customers, scores churn risk and prepares chargeback replies, on Stripe or any billing through the API. Start with the [quickstart](/docs/quickstart/), read about [failed payments](/#dunning), or see [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). --- # Chargeflow alternative: NoChurn vs Chargeflow Source: https://www.nochurn.sh/compare/chargeflow/ Chargeflow is a chargeback specialist. It automates dispute responses, offers pre-dispute alerts and fraud prevention, and much of its product is built for online stores. NoChurn is something different: a retention tool for subscription businesses, where chargebacks are one feature next to failed payment recovery, cancel flows, win-back and churn scoring. If disputes are your main problem, read this page as a guide to which kind of tool you need, not only which brand. It reflects Chargeflow's public pages as of November 2026; check the sources at the bottom for anything that may have changed. ## At a glance | | NoChurn | Chargeflow | |---|---|---| | What it is | Subscription retention: failed payments, cancel flows, win-back, churn score, chargebacks | Chargeback management: automated responses, alerts, prevention, insights | | Pricing model | Flat monthly price by MRR band, never a share of recovered revenue | Automation: 25% of recovered chargebacks, nothing if nothing is recovered; Alerts: $29 per deflected chargeback; Prevent: $0.10 per scanned transaction; Insights: free | | Starting price | Free until $300 MRR, then from $9/month | No setup fee, contract or monthly minimum on standard plans; enterprise is custom | | Dispute responses | Evidence gathered automatically (cancel flow answers, emails sent, usage, support conversations); AI drafts the reply; a person reviews it before it is sent | Automated evidence and submission | | Pre-dispute alerts (Ethoca, Verifi RDR) | No | Yes, Mastercard Ethoca and Visa Verifi RDR | | Early fraud warnings | Stripe early fraud warnings, with one-click refund | Prevent product scores transactions | | Guarantee | None | 4x ROI guarantee on Automation, terms set in the merchant agreement | | Processors for disputes | Stripe and Braintree; disputes on Paddle, Lemon Squeezy and Polar are handled by the merchant of record and shown read only; other providers read only | Shopify Payments, Stripe, PayPal, Braintree, plus an API | | Failed payments, cancel flow, win-back | Yes, all included | Not the focus | Chargeflow figures come from its AI info page, Automation page and docs, accessed November 2026. ## Where Chargeflow is a better fit - **You sell physical or one-off goods online.** Chargeflow covers Shopify Payments and PayPal and has a dedicated ecommerce offer. NoChurn is built around subscriptions and has no Shopify or PayPal dispute handling. - **You want pre-dispute alerts.** Chargeflow resells Ethoca and Verifi RDR alerts, which can stop a dispute before it becomes a chargeback. NoChurn has no alert network. - **You want no work on your side.** Chargeflow automates the response end to end. NoChurn always asks a person to review the drafted reply before it goes to Stripe or Braintree. - **You want a guarantee.** Chargeflow advertises an ROI guarantee on Automation. NoChurn offers none. - **Disputes are rare and you only want to pay when you win.** With a success fee, a month with no wins costs nothing on Chargeflow Automation. ## Where NoChurn is different **One tool for the whole subscription lifecycle.** Many chargebacks on subscriptions start as a customer who could not find how to cancel, forgot a renewal, or had a card fail. NoChurn handles those moments directly: [failed payments](/#dunning), a [cancel flow](/#cancel) with one-click cancel always visible, and [win-back](/#winback). **Evidence from what already happened.** When a dispute opens, NoChurn gathers what it already knows: the customer's cancel flow answers, the emails they were sent, their usage and their support conversations. The AI drafts the reply, and nothing is sent until someone on your team approves it. See [chargebacks](/#disputes). **Flat price, never a percentage.** Free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, custom above. Winning a large dispute does not change your bill. See [pricing](/pricing/). **Every feature on every plan.** Chargebacks, recovery, cancel flows, win-back, churn score and the API are on the free plan too. NoChurn is new and has no customer results to show. Chargeflow is an established specialist. Weigh that honestly. ## Using both, or switching Many teams do not need to choose. If you rely on Chargeflow alerts or its ecommerce coverage, you can keep it for disputes and use NoChurn for recovery, cancel flows and win-back. If you do that, turn off chargeback drafting in NoChurn so a dispute is never answered twice. If you are a Stripe or Braintree subscription business and want to move disputes to NoChurn: 1. **Connect Stripe or Braintree** with the [quickstart](/docs/quickstart/). 2. **Set up the cancel flow and emails first.** They create the evidence a dispute reply needs later. 3. **Decide who reviews replies.** Every drafted reply waits for a person on your team. 4. **Move disputes over on a fixed date.** Let disputes opened before that date finish in Chargeflow, so no dispute has two responders. 5. **Check any alert enrolment.** If you were enrolled in alerts through Chargeflow, ask them how ending the service affects it. ## FAQ ### Does NoChurn offer Ethoca or Verifi alerts? No. NoChurn reads Stripe early fraud warnings and offers a one-click refund, but it is not connected to any alert network. ### Does NoChurn guarantee a win rate or ROI? No. NoChurn drafts replies with the evidence it has and a person on your team decides whether to send them. ### Does NoChurn take a share of won disputes? No. The price depends only on your MRR band. ## How NoChurn helps NoChurn keeps subscription customers from leaving for the wrong reasons: it recovers failed payments, runs an honest cancel flow, wins back churned customers and, when a dispute does open on Stripe or Braintree, drafts a reply from evidence it already has for you to review. One flat price by MRR, every feature included. See [chargebacks](/#disputes) and [pricing](/pricing/). --- # Justt alternative: NoChurn vs Justt Source: https://www.nochurn.sh/compare/justt/ Justt is a chargeback specialist. It fights disputes for merchants across many industries, connects to dozens of payment providers and adds pre-dispute alerts. It says it charges only when it wins. NoChurn is a retention tool for subscription businesses; chargebacks are one feature, next to failed payment recovery, cancel flows, win-back and churn scoring. This page reflects Justt's public pages as of November 2026. Justt quotes its pricing on request, so check with them for current terms. ## At a glance | | NoChurn | Justt | |---|---|---| | What it is | Subscription retention: failed payments, cancel flows, win-back, churn score, chargebacks | Chargeback management and alerts across industries | | Pricing model | Flat monthly price by MRR band, never a share of recovered revenue | Success-based: you pay when a chargeback is won | | Starting price | Free until $300 MRR, then from $9/month | Custom, on request | | Dispute responses | Evidence gathered automatically (cancel flow answers, emails sent, usage, support conversations); AI drafts the reply; a person reviews it before it is sent | Automated, with optimization that can decide which disputes are worth fighting | | Pre-dispute alerts (Ethoca, Verifi) | No | Yes, Ethoca and Verifi alerts, including Verifi RDR | | Early fraud warnings | Stripe early fraud warnings, with one-click refund | Not covered in the pages we reviewed | | Guarantee | None | Not stated on the pages we reviewed | | Processors for disputes | Stripe and Braintree; Paddle, Lemon Squeezy and Polar disputes are handled by the merchant of record and shown read only; other providers read only | Over 40 PSPs according to its integrations page, including Stripe, Adyen, PayPal, Braintree and Nuvei; custom connections where needed | | Industries | Subscription businesses | Retail, digital goods, travel, event ticketing, subscription, crypto, gaming | | Failed payments, cancel flow, win-back | Yes, all included | Not the focus | Justt figures come from its homepage, FAQ, integrations and alerts pages, accessed November 2026. ## Where Justt is a better fit - **You are a large merchant with many payment providers.** Justt connects to dozens of PSPs, including Adyen and Nuvei. NoChurn drafts replies on Stripe and Braintree only. - **You sell beyond subscriptions.** Travel, ticketing, retail, gaming: Justt covers them. NoChurn is not designed for one-off orders. - **You want alerts.** Justt combines Ethoca and Verifi alerts and RDR with dispute responses. NoChurn has no alert network. - **You want a hands-off service.** Justt's FAQ describes a fully hands-off option. With NoChurn, a person on your team reviews every reply. - **You only want to pay on wins.** Success-based pricing ties the cost to results. ## Where NoChurn is different **Built for subscriptions.** In a subscription business, a dispute is often the end of a story that started earlier: a missed cancellation, a forgotten renewal, a failed card. NoChurn works on those moments too, with [failed payment recovery](/#dunning), a [cancel flow](/#cancel) with one-click cancel always visible, and [win-back](/#winback). **Evidence from your own history with the customer.** NoChurn collects cancel flow answers, emails sent, usage and support conversations, and drafts a reply that a person approves before it is sent to Stripe or Braintree. See [chargebacks](/#disputes). **Public, flat price.** Free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, custom above. No sales call needed. See [pricing](/pricing/). **Every feature on every plan.** Including the API, signed webhooks and the MCP server. NoChurn is new and has no customer results to show. Justt is an established specialist. ## Using both, or switching If you are an enterprise merchant with many providers or heavy dispute volume, Justt is likely the better dispute tool, and NoChurn can still run your recovery, cancel flows and win-back. Turn off chargeback drafting in NoChurn so each dispute has one responder. If you are a Stripe or Braintree subscription business and want disputes in NoChurn: 1. **Connect Stripe or Braintree** with the [quickstart](/docs/quickstart/). 2. **Set up the cancel flow and emails** so evidence exists before the next dispute. 3. **Pick reviewers** for drafted replies. 4. **Switch on a fixed date** and let open disputes finish with Justt. 5. **Review your contract and any alert enrolment** with Justt before ending the service. ## FAQ ### Does NoChurn have Ethoca or Verifi RDR alerts? No. NoChurn reads Stripe early fraud warnings and offers a one-click refund; it is not part of any alert network. ### Does NoChurn decide which disputes to fight? It drafts a reply when it has evidence. A person on your team decides whether to send it or accept the dispute. ### Does NoChurn charge per won dispute? No. The price depends only on your MRR band, and chargebacks are included on every plan. ## How NoChurn helps NoChurn recovers failed payments, runs a fair cancel flow, wins back churned customers and drafts dispute replies on Stripe and Braintree for you to review, for one flat price by MRR. See [chargebacks](/#disputes) and [pricing](/pricing/). --- # Disputifier alternative: NoChurn vs Disputifier Source: https://www.nochurn.sh/compare/disputifier/ Disputifier is a chargeback tool aimed mainly at online stores, with a native Shopify app. It answers disputes automatically, connects to Ethoca and Verifi alerts and sells per-order fraud prevention. NoChurn is a retention tool for subscription businesses; chargebacks are one feature, next to failed payment recovery, cancel flows, win-back and churn scoring. This page reflects Disputifier's public pages as of November 2026. Its own pages do not always agree on alert pricing, so check the current pricing page before you decide. ## At a glance | | NoChurn | Disputifier | |---|---|---| | What it is | Subscription retention: failed payments, cancel flows, win-back, churn score, chargebacks | Chargeback responses, alerts and prevention, mainly for ecommerce | | Pricing model | Flat monthly price by MRR band, never a share of recovered revenue | Responses: 20% of recovered revenue; alerts priced by volume; fraud and order-not-received prevention $0.05 per order; no subscription or minimum | | Starting price | Free until $300 MRR, then from $9/month | Nothing up front; you pay on results and usage | | Dispute responses | Evidence gathered automatically (cancel flow answers, emails sent, usage, support conversations); AI drafts the reply; a person reviews it before it is sent | AI-generated responses submitted automatically | | Pre-dispute alerts (Ethoca, Verifi) | No | Yes, Ethoca and Verifi through Disputifier as a partner | | Early fraud warnings | Stripe early fraud warnings, with one-click refund | Fraud prevention per order | | Guarantee | None | Alert fee refunded if a resolved alert still becomes a chargeback [À VÉRIFIER] | | Processors and platforms | Stripe and Braintree for replies; Paddle, Lemon Squeezy and Polar disputes handled by the merchant of record and shown read only; other providers read only | Shopify app; PayPal, Stripe, Authorize.net, with Afterpay and Klarna support | | Failed payments, cancel flow, win-back | Yes, all included | Not the focus | Disputifier figures come from its pricing page and blog, accessed November 2026. ## Where Disputifier is a better fit - **You run a Shopify store.** Disputifier is a native Shopify app and covers PayPal, Afterpay and Klarna. NoChurn does not handle these. - **You want alerts.** Disputifier brings Ethoca and Verifi alerts into one dashboard. NoChurn has no alert network. - **You want fully automatic submission.** Disputifier submits responses for you. NoChurn always waits for a person to approve the reply. - **You want to pay only on results.** With no subscription and a success fee on responses, a quiet month costs little. ## Where NoChurn is different **Built for subscriptions.** Many subscription disputes come from customers who could not cancel easily or forgot a renewal. NoChurn's [cancel flow](/#cancel) keeps a one-click cancel visible on every step, and [failed payment recovery](/#dunning) and [win-back](/#winback) cover the rest of the customer's life. **Evidence from your own history.** Cancel flow answers, emails sent, usage and support conversations are gathered automatically, and the AI drafts a reply for review before it goes to Stripe or Braintree. See [chargebacks](/#disputes). **Flat price, never a percentage.** Free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, custom above. See [pricing](/pricing/). **Every feature on every plan,** with a REST API, signed webhooks and an MCP server. NoChurn is new and has no customer results to show. Disputifier has been answering disputes for stores for longer. ## Using both, or switching If you sell physical goods on Shopify, Disputifier is likely the better dispute tool. If you also sell subscriptions on Stripe, NoChurn can run recovery, cancel flows and win-back alongside it; turn off chargeback drafting in NoChurn so each dispute has one responder. To move Stripe or Braintree subscription disputes to NoChurn: 1. **Connect Stripe or Braintree** with the [quickstart](/docs/quickstart/). 2. **Set up the cancel flow and emails** so evidence exists for future disputes. 3. **Pick reviewers** for drafted replies. 4. **Switch on a fixed date** and let open disputes finish in Disputifier. 5. **Check your alert enrolment** with Disputifier before ending the service. ## FAQ ### Does NoChurn offer Ethoca or Verifi alerts? No. NoChurn reads Stripe early fraud warnings and offers a one-click refund; it is not part of any alert network. ### Does NoChurn work with Shopify or PayPal disputes? No. NoChurn drafts replies on Stripe and Braintree. Other providers' disputes are shown read only when connected. ### Does NoChurn guarantee results? No. A person on your team reviews every reply, and the outcome is decided by the card issuer. ## How NoChurn helps NoChurn recovers failed payments, runs a fair cancel flow, wins back churned customers and drafts dispute replies on Stripe and Braintree for you to review, for one flat price by MRR. See [chargebacks](/#disputes) and [pricing](/pricing/). --- # Chargeblast alternative: NoChurn vs Chargeblast Source: https://www.nochurn.sh/compare/chargeblast/ Chargeblast is mainly a pre-dispute alerts company. It connects merchants to Mastercard Ethoca and Visa CDRN and RDR alerts, so a likely chargeback can be refunded before it is filed, and it adds a representment product for disputes that do get filed. NoChurn is a retention tool for subscription businesses; chargebacks are one feature, next to failed payment recovery, cancel flows, win-back and churn scoring. This page reflects Chargeblast's public pages and docs as of November 2026. We could not confirm its per-alert price, so check its pricing page directly. ## At a glance | | NoChurn | Chargeblast | |---|---|---| | What it is | Subscription retention: failed payments, cancel flows, win-back, churn score, chargebacks | Pre-dispute alerts, plus representment | | Pricing model | Flat monthly price by MRR band, never a share of recovered revenue | Pay per alert, no seat licences or monthly minimums | | Starting price | Free until $300 MRR, then from $9/month | Not public in the pages we reviewed [À VÉRIFIER] | | Pre-dispute alerts | No | Yes: Ethoca, Verifi CDRN and Verifi RDR | | Early fraud warnings | Stripe early fraud warnings, with one-click refund | Custom auto-refund rules for Stripe early fraud warnings | | Dispute responses | Evidence gathered automatically (cancel flow answers, emails sent, usage, support conversations); AI drafts the reply; a person reviews it before it is sent | Chargeblast Recovery: self-serve, or done for you | | Guarantee | None | Not stated on the pages we reviewed | | Processors and platforms | Stripe and Braintree for replies; Paddle, Lemon Squeezy and Polar disputes handled by the merchant of record and shown read only; other providers read only | Stripe integration (matches alerts to charges), Shopify app, API | | Failed payments, cancel flow, win-back | Yes, all included | Not the focus | Chargeblast figures come from its docs and blog, accessed November 2026. ## Where Chargeblast is a better fit - **Your dispute ratio is close to a card network threshold.** Alerts let you refund before a chargeback is filed, which is what Chargeblast is built for. NoChurn has no alert network. - **You want Ethoca, CDRN and RDR in one place.** Chargeblast's docs explain which combination fits which risk level. - **You want done-for-you representment.** Chargeblast Recovery has a fully managed option. NoChurn always asks your team to review each reply. - **You sell on Shopify.** Chargeblast has a Shopify app; NoChurn does not cover Shopify disputes. ## Where NoChurn is different **Fewer reasons to dispute in the first place.** In a subscription business, many disputes come from customers who could not cancel or did not expect a renewal. NoChurn's [cancel flow](/#cancel) keeps one-click cancel visible on every step, and [failed payment recovery](/#dunning) and [win-back](/#winback) handle the rest of the lifecycle. **Replies built from your own data.** When a dispute opens on Stripe or Braintree, NoChurn gathers cancel flow answers, emails sent, usage and support conversations and drafts a reply for a person to approve. See [chargebacks](/#disputes). **Early fraud warnings on Stripe.** NoChurn shows Stripe early fraud warnings and lets you refund in one click. This is not the same as Ethoca or Verifi alerts. **Flat price, never a percentage or per-alert fee.** Free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, custom above. See [pricing](/pricing/). NoChurn is new and has no customer results to show. ## Using both, or switching Chargeblast and NoChurn overlap less than it seems. A common setup is alerts from Chargeblast and retention from NoChurn. If both draft or submit dispute replies, turn off one of them so each dispute has one responder. If both act on Stripe early fraud warnings, choose one tool for refunds so a charge is never refunded twice. To use NoChurn for Stripe or Braintree subscription disputes: 1. **Connect Stripe or Braintree** with the [quickstart](/docs/quickstart/). 2. **Set up the cancel flow and emails** so evidence exists for future disputes. 3. **Pick reviewers** for drafted replies. 4. **Keep or end alerts** depending on your dispute ratio; NoChurn does not replace them. ## FAQ ### Can NoChurn replace Chargeblast alerts? No. NoChurn is not connected to Ethoca or Verifi. If you need alerts, keep an alerts provider. ### Does NoChurn refund automatically? No. On a Stripe early fraud warning, NoChurn offers a one-click refund that a person triggers. ### Does NoChurn guarantee results? No. A person on your team reviews every reply, and the card issuer decides the outcome. ## How NoChurn helps NoChurn recovers failed payments, runs a fair cancel flow, wins back churned customers and drafts dispute replies on Stripe and Braintree for you to review, for one flat price by MRR. See [chargebacks](/#disputes) and [pricing](/pricing/). --- # Chargebacks911 alternative: NoChurn vs Chargebacks911 Source: https://www.nochurn.sh/compare/chargebacks911/ Chargebacks911 is one of the longest-running chargeback management companies. It offers fully managed, self-managed or hybrid service, combines Ethoca and Verifi CDRN alerts with its own alerts network, and advertises a performance-based ROI guarantee. NoChurn is a retention tool for subscription businesses; chargebacks are one feature, next to failed payment recovery, cancel flows, win-back and churn scoring. This page reflects Chargebacks911's public pages as of November 2026. Its pricing is quoted per merchant, so check with them for current terms. ## At a glance | | NoChurn | Chargebacks911 | |---|---|---| | What it is | Subscription retention: failed payments, cancel flows, win-back, churn score, chargebacks | End-to-end chargeback management: prevention, alerts, representment, analysis | | Pricing model | Flat monthly price by MRR band, never a share of recovered revenue | Performance-based: you pay when revenue is recovered; custom quote | | Starting price | Free until $300 MRR, then from $9/month | Not public; quoted after a demo | | Service model | Software; your team reviews each drafted reply | Fully managed, self-managed or hybrid | | Dispute responses | Evidence gathered automatically (cancel flow answers, emails sent, usage, support conversations); AI drafts the reply; a person reviews it before it is sent | Managed representment by its team, or self-managed with its software | | Pre-dispute alerts | No | Ethoca, Verifi CDRN and its own alerts network | | Root-cause analysis | Churn drivers from your custom data (correlation, not causation) | Intelligent Source Detection, combining machine learning and analysts | | Guarantee | None | Performance-based ROI guarantee | | Processors for disputes | Stripe and Braintree; Paddle, Lemon Squeezy and Polar disputes handled by the merchant of record and shown read only; other providers read only | Described as system-agnostic; confirm your processor with them | | Failed payments, cancel flow, win-back | Yes, all included | Not the focus | Chargebacks911 figures come from its FAQ, merchant solutions and chargeback management pages, accessed November 2026. ## Where Chargebacks911 is a better fit - **You want someone else to handle disputes.** Chargebacks911 offers a fully managed service. NoChurn is software, and your team approves every reply. - **You need alerts.** Chargebacks911 combines Ethoca, Verifi CDRN and its own network. NoChurn has no alert network. - **You want a guarantee.** Chargebacks911 advertises an ROI guarantee; NoChurn offers none. Ask them for the terms in writing. - **You are a large or high-risk merchant, or not a subscription business.** Chargebacks911 works across industries and payment setups. NoChurn drafts replies on Stripe and Braintree only, for subscriptions. ## Where NoChurn is different **Prevention through the subscription itself.** Many subscription disputes start with a hard-to-find cancel button or an unexpected renewal. NoChurn's [cancel flow](/#cancel) keeps one-click cancel visible on every step, and [failed payment recovery](/#dunning) and [win-back](/#winback) cover the rest of the customer's life. **Evidence you already have.** Cancel flow answers, emails sent, usage and support conversations are gathered automatically when a dispute opens on Stripe or Braintree. The AI drafts the reply; a person approves it. See [chargebacks](/#disputes). **Public, flat price with no sales call.** Free until $300 MRR, then from $9/month, in small steps up to $399/month at $500k MRR, custom above. See [pricing](/pricing/). **Every feature on every plan,** with a REST API, signed webhooks and an MCP server. NoChurn is new and has no customer results to show. Chargebacks911 has many years in the business. ## Using both, or switching If you need managed representment, alerts or a guarantee, keep Chargebacks911 for disputes and use NoChurn for recovery, cancel flows and win-back. Turn off chargeback drafting in NoChurn so each dispute has one responder. To move Stripe or Braintree subscription disputes to NoChurn: 1. **Connect Stripe or Braintree** with the [quickstart](/docs/quickstart/). 2. **Set up the cancel flow and emails** so evidence exists for future disputes. 3. **Pick reviewers** for drafted replies; this is work a managed service used to do for you. 4. **Switch on a fixed date** and let open disputes finish with Chargebacks911. 5. **Review your contract and any alert enrolment** before ending the service. ## FAQ ### Does NoChurn offer a managed dispute service? No. NoChurn drafts replies; your team reviews and sends them. ### Does NoChurn offer alerts or a guarantee? No. NoChurn reads Stripe early fraud warnings with a one-click refund, but it has no alert network and no guarantee. ### Does NoChurn charge on recovered revenue? No. The price depends only on your MRR band. ## How NoChurn helps NoChurn recovers failed payments, runs a fair cancel flow, wins back churned customers and drafts dispute replies on Stripe and Braintree for you to review, for one flat price by MRR. See [chargebacks](/#disputes) and [pricing](/pricing/). --- # Stripe Smart Disputes vs NoChurn: who answers your chargebacks? Source: https://www.nochurn.sh/compare/stripe-smart-disputes/ If you take payments on Stripe, you already have a dispute assistant: **Smart Disputes** builds an evidence packet for eligible disputes and submits it before the deadline if you do nothing. Stripe also offers **dispute prevention** through Verifi and Ethoca. NoChurn is not a replacement for either. It is a retention tool for subscription businesses that, when a dispute opens, gathers the subscription evidence Stripe does not have and drafts a reply for a person on your team to review. This page compares them from Stripe's documentation as of November 2026. Stripe ships often, so check the linked docs for the current behavior and Stripe's pricing page for fees in your country. ## At a glance | | NoChurn | Stripe Smart Disputes and dispute prevention | |---|---|---| | What it is | Subscription retention (failed payments, cancel flows, win-back, churn score) with chargeback replies included | Stripe's built-in tools to answer and prevent card disputes | | Pricing model | Flat monthly price by MRR band, never a share of won disputes | Smart Disputes fee charged only on won disputes, none on lost ones; amounts on Stripe's pricing page | | Starting price | Free until $300 MRR, then from $9/month | No setup; part of your Stripe account once enrolled | | Who submits | A person on your team approves every drafted reply before it goes to the processor | Stripe submits the packet automatically just before the deadline unless you turn off auto-submit | | Evidence used | Cancel flow history and answers, renewal reminders and recovery emails sent, usage you send by API, support conversations from a connected help desk, payment history | Data Stripe holds: transaction, cardholder and Stripe network data, plus fields you send at charge time or add to the dispute | | Eligibility | Every dispute NoChurn reads on Stripe and Braintree | Eligible disputes only, decided by reason code, payment method, available evidence, relevance and cost | | Pre-dispute alerts | No alert network; early fraud warnings with a one-click refund and option to stop the subscription | Dispute prevention: deflection through Verifi Order Insights (Visa) and Ethoca Consumer Clarity (Mastercard), resolution rules in Radar, Compelling Evidence 3.0 | | Processors | Stripe and Braintree; disputes on Paddle, Lemon Squeezy and Polar are handled by the merchant of record and shown read only | Stripe only | | Failed payments, cancel flow, win-back | Yes, all included | Not part of these tools (Stripe Billing has its own retention features) | Stripe facts come from the Smart Disputes, setup, dispute prevention and how-disputes-work pages, accessed November 7, 2026. ## What Stripe already does well **No integration.** Stripe says Smart Disputes requires no extra work if you already use Stripe. Once your account is enrolled, Stripe builds packets for eligible disputes and notifies you by email and in the Dashboard. **It never misses a deadline.** If you take no action, Smart Disputes submits the pre-filled packet just before the dispute times out. On Stripe, you usually have 7 to 21 days to respond after a chargeback is created, depending on the card network, so a safety net matters. **You pay only when you win.** Stripe's docs say it bills the Smart Disputes fee only on won disputes. Check the amount on Stripe's pricing page. **You can add to the packet.** The Dispute object lists `smart_disputes.recommended_evidence` and a `smart_disputes.status` (`available`, `requires_evidence` or `unavailable`). Setting `intended_submission_method` to `prefer_smart_disputes` merges your own evidence with Stripe's generated packet. **Prevention before the chargeback.** Stripe's dispute prevention connects to Verifi and Ethoca. Deflection sends transaction data so the cardholder recognizes the charge; resolution rules in Radar refund chosen disputes automatically, and Stripe says those resolved disputes do not count toward your dispute rate. **Where Stripe alone is enough.** If disputes are rare, mostly fraud claims on one-off payments, and your Stripe data (receipts, billing address, terms acceptance) tells the whole story, Smart Disputes may be all you need. ## Where NoChurn adds to Stripe **Evidence from the subscription, not only the payment.** Many subscription disputes are "subscription canceled" or "unrecognized" claims. Winning them depends on things Stripe does not see: whether the customer ever tried to cancel, which reminders and emails they got before the renewal, whether they kept using the product after the charge, and what they said to support. NoChurn already holds most of that, because it runs your cancel flow and recovery emails and reads your help desk. **A person approves every reply.** NoChurn drafts the response with AI, only from items in the evidence file, and nothing goes to Stripe or Braintree until someone on your team has reviewed it. Customer messages are treated as data, never as instructions. **Fewer disputes in the first place.** A one-click "cancel now" that is always visible, clear renewal reminders and fast recovery of failed payments remove common reasons customers call their bank. See [cancel flows](/#cancel) and [failed payments](/#dunning). **Early fraud warnings with a decision.** When Stripe receives an early fraud warning, NoChurn proposes a refund in one click and can stop the subscription so the next renewal does not cause a second dispute. Stripe's own guidance is not to refund every warning; its docs suggest refunding mostly when the charge is about the size of your dispute fee or less. **Flat price, every feature.** Free until $300 MRR, then from $9/month up to $399/month at $500k MRR, custom above. Chargebacks, recovery, cancel flows, win-back and churn score are on every plan. See [pricing](/pricing/). NoChurn is new and has no win-rate figures to share. Stripe has data from its whole network. Weigh that honestly. ## Running both without answering twice You can keep Smart Disputes on and still use NoChurn. The rule is simple: one submission per dispute, because submitting evidence is final. 1. **Connect Stripe** with the [quickstart](/docs/quickstart/), in test mode first. 2. **Decide who submits by default.** Either let NoChurn's reviewed reply go first and keep Smart Disputes as the deadline safety net, or turn off Smart Disputes auto-submit in your Stripe dispute settings. 3. **NoChurn checks before sending.** If Stripe has already submitted a Smart Disputes packet, NoChurn does not submit and shows the dispute as answered by Stripe. 4. **Send more data at charge time anyway.** Stripe recommends collecting email, name, billing address, terms acceptance and receipts; that helps both tools. 5. **Review outcomes monthly** by reason, and fix the source: billing descriptor, renewal reminders, cancel button. ## FAQ ### Is Stripe Smart Disputes free? There is no setup cost, and Stripe says it charges the Smart Disputes fee only when you win. The standard dispute fees still apply when a dispute is opened. Fees vary by country; see Stripe's pricing page. ### Does Smart Disputes work for every dispute? No. Stripe decides eligibility from the reason code, payment method, evidence available, its relevance and cost. A dispute can be `requires_evidence` until you add the recommended fields, or `unavailable`. ### Does NoChurn offer Verifi or Ethoca alerts? No. NoChurn reads Stripe early fraud warnings and offers a one-click refund, but it is not connected to any alert network. Stripe's dispute prevention is the place for that. ### Will NoChurn submit evidence automatically? Every drafted reply waits for a person on your team by default. NoChurn never submits a dispute Stripe has already answered. ## How NoChurn helps NoChurn keeps subscription customers from leaving, or disputing, for the wrong reasons: it recovers failed payments, runs an honest cancel flow, wins back churned customers and, when a dispute opens on Stripe or Braintree, drafts a reply from evidence Stripe does not have, for you to review. One flat price by MRR, every feature included. Read [how to win chargebacks on Stripe](/blog/win-chargebacks-stripe/), see [chargebacks](/features/chargebacks/) or [pricing](/pricing/). --- # What is a good churn rate? Public benchmarks by industry and price point, and how to read them Source: https://www.nochurn.sh/blog/churn-rate-benchmarks/ There is no universal good churn rate. The most complete public dataset we found, Recurly's churn benchmarks (July 2026 data), puts the median overall churn rate at 3.60% across industries, with SaaS lowest at 3.22% and education highest at 4.99%. The more useful comparison is by price: in the same data, churn falls from 4.29% for customers paying $10 to $25 a month to about 3% above $100, and involuntary churn (failed payments) falls far more steeply than voluntary churn. This guide collects those figures in tables you can quote, explains what they measure, and shows how to compare your own number without fooling yourself. All benchmark figures come from [Recurly's churn rate benchmarks page](https://recurly.com/research/churn-rate-benchmarks/), accessed November 7, 2026, which says its figures are updated with July 2026 data from the Recurly network. ## Where do churn benchmarks come from? Public churn data is scarce. Most published benchmarks come from billing or analytics vendors who aggregate their own customers, so each one describes that vendor's customer base, not the whole market. Recurly's page is one of the few that publishes medians by industry and by price point, with voluntary and involuntary churn split out. Keep in mind: - **It is one network.** Recurly describes its customers as spanning streaming media, software, ecommerce, publishing, education and consumer subscriptions. A different vendor's customers will give different numbers. - **It is a median.** Half the businesses in each group churn more, half less. - **Definitions matter more than decimals.** Recurly defines churn rate as the percentage of subscribers who cancel or fail to renew within a period. That is customer churn, not revenue churn. ## Churn rate benchmarks by industry Median churn rates from Recurly network data (July 2026), as published on Recurly's page: | Industry | Total churn | Voluntary | Involuntary | |---|---|---|---| | SaaS | 3.22% | 2.16% | 1.06% | | Business and professional services | 3.44% | 2.27% | 1.18% | | Travel, hospitality and entertainment | 3.91% | 2.63% | 1.28% | | Digital media and entertainment | 4.14% | 2.55% | 1.59% | | Ecommerce | 4.25% | 2.87% | 1.38% | | Education | 4.99% | 3.30% | 1.69% | | All industries | 3.60% | 2.34% | 1.25% | Two patterns stand out. Voluntary churn is the larger part in every industry. And digital media has comparatively low voluntary churn but the second-highest involuntary churn, which Recurly reads as a payment recovery gap rather than an intent problem. One inconsistency to know about: the same page also quotes a median of 3.04% for software businesses, with top-quartile performers at 1.78% or below, next to the 3.22% SaaS figure in the table. The two numbers probably come from slightly different groupings; quote the one that matches your question and name the source. ## Churn rate benchmarks by price per customer Recurly also splits churn by average revenue per customer (ARPC), which is often a better peer group than industry: | Monthly ARPC | Total churn | Voluntary | Involuntary | |---|---|---|---| | $10 to $25 | 4.29% | 2.99% | 1.30% | | $25 to $50 | 3.84% | 2.73% | 1.11% | | $50 to $100 | 3.15% | 2.41% | 0.74% | | $100 to $250 | 2.87% | 2.40% | 0.46% | | Over $250 | 3.07% | 2.90% | 0.18% | Involuntary churn drops from 1.30% to 0.18% between the lowest and highest bands, a fall Recurly puts at 87%. Voluntary churn moves much less, and ticks back up above $250. In practice: if you sell a low-priced consumer subscription, failed payments are a large share of your churn and usually the cheapest part to fix; if you sell a high-priced B2B product, most of your churn is customers deciding to leave. ## What is a good churn rate for SaaS? By Recurly's data, a SaaS business near **3.2%** is at the median of its network and one at **1.78% or below** is in the top quartile. Recurly's own reading is that most well-run subscription businesses sit between 2% and 4%, that below 2% is strong, and that above 5% is worth investigating, either for product fit (voluntary) or payment operations (involuntary). Before you put your number next to these, check three things: 1. **The period.** Recurly's page describes these figures as median annual churn rates. Annual churn is not 12 times monthly churn: the same page notes that 2% monthly churn is roughly 22% a year, not 24%. Compute your rate over the same period as the benchmark, or convert carefully, before comparing. 2. **Customers or revenue.** These are subscriber counts. MRR churn can be much higher or lower if the customers you lose pay more or less than average. Track both; see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). 3. **Voluntary and involuntary separately.** A total that looks fine can hide a high involuntary rate you could fix without touching the product. See [involuntary churn](/blog/involuntary-churn/). ## How do I compare my churn rate with a benchmark? A short method that avoids most mistakes: 1. **Pick your peer group by price first,** then by industry. A $15/month app and a $500/month B2B tool should not use the same benchmark. 2. **Use the same formula.** Subscribers lost in the period divided by subscribers at the start of the period, times 100. Exclude new subscribers who joined and left inside the period, or count them consistently. 3. **Split the cause.** Count a subscription as involuntary churn when failed payments ended it, voluntary when the customer canceled. 4. **Compare against your own history.** A benchmark tells you roughly where you stand; your trend over the last 6 to 12 months tells you whether what you are doing works. [Cohort retention](/blog/cohort-retention-analysis/) is the best view for that. 5. **Look at the gap, not the rank.** If your involuntary churn is well above the median for your price band, start with [failed payment recovery](/blog/recover-failed-payments-stripe/). If voluntary churn is the gap, start with onboarding, the [cancel flow](/blog/cancel-flow-best-practices/) and [cancellation reasons](/blog/cancellation-reasons-survey/). ## What else does the public data say about reducing churn? Recurly's benchmark page also cites its 2026 State of Subscriptions report for two figures worth knowing: - **38% of consumers prefer pausing over canceling.** A pause option is an underused save offer; see [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). - **Nearly 1 in 4 new subscriptions comes from a previously canceled customer.** Voluntary churn is often not final, which is the case for [win-back emails](/blog/win-back-email-examples/). Treat these as one vendor's figures for its own network, not as a law of subscriptions. ## FAQ ### What is the average churn rate for subscription businesses? Recurly's July 2026 network data puts the median overall churn rate at 3.60% across industries: 2.34% voluntary and 1.25% involuntary. ### Is 5% churn bad? Against Recurly's data, 5% is above the median of every industry it lists (education is highest at 4.99%), and Recurly calls anything above 5% worth investigating. Whether it is bad for you depends on your price point, your period and whether the gap is voluntary or involuntary. ### Why is involuntary churn lower for expensive plans? Recurly's explanation is that higher-value subscribers tend to use better payment methods and are more likely to resolve failed payments themselves. ### Are there other public churn benchmarks? Several billing and analytics vendors publish figures from their own customers, with different definitions and periods. Compare only benchmarks that state their period, their formula and whether they count customers or revenue. ## How NoChurn helps NoChurn works on both sides of the split this guide describes, from your real billing events. Failed payments get smart retries and AI-written recovery emails you review; cancellations go through a reason-based flow with a one-click cancel button always visible; churned customers get win-back emails at 30, 60 and 90 days. Send your own attributes, such as plan, signup source or key usage, and NoChurn shows which ones go with churn, with sample size and confidence. It works with Stripe in one click or any billing through the API, free until $300 MRR. See [Custom data & AI](/ai/) and [churn score](/features/churn-score/). --- # How many times should you retry a failed payment? Retry schedules compared across billing platforms Source: https://www.nochurn.sh/blog/payment-retry-schedules-compared/ The billing platforms compared here document default retry limits from 4 retries (Lemon Squeezy) to 20 attempts (Recurly) for a failed subscription payment, over a window that runs from about five days (Mollie) to 60 days (Recurly, the App Store). In our view, a sensible default for monthly card subscriptions is a handful of retries spread over 2 to 4 weeks, timed around likely paydays, with no retries at all on hard declines until the customer updates their card. The retry schedule matters less than what you tell the customer: on most platforms, a card update triggers an immediate retry. This guide puts the documented retry rules of nine platforms side by side, so you can see what yours does before you add anything on top. Every number below comes from the platform's own documentation, linked in each section and accessed in November 2026. Where a platform does not publish a detail, we say so. ## Retry schedules at a glance | Platform | Default retries | Window | Who picks the timing | Hard declines | |---|---|---|---|---| | Stripe Billing | Smart Retries: up to 8 retries (new accounts) | 2 weeks by default; 1 week to 2 months | Stripe's model, or a custom schedule of up to 3 retries | Not charged until a new payment method is attached | | Chargebee | Smart mode: up to 12; Custom mode: 1 to 5 | Your dunning period | Chargebee (Smart) or you (Custom) | Smart mode waits for a new payment method | | Recurly | Up to 20 attempts | 60 days from invoice creation, or end of dunning | Intelligent Retries (ML) or static rules | Generally not retried | | Paddle Billing | Up to 7 | 30 days | Paddle | Not documented in detail | | Lemon Squeezy | 4 | About 2 weeks | Lemon Squeezy | Not documented in detail | | Mollie | Up to 5, once a day | About 5 days | Mollie, depending on the failure reason | Depends on the failure reason | | Braintree | 3 automatic retries, then at least 2 more | Up to 2 days, then intervals you set (1 to 10 days) | You, in the Control Panel | Some codes are never retried | | App Store | Not published | Up to 60 days of billing retry | Apple | Apple decides | | Google Play | Not published | Grace period plus account hold, 60 days by default | Google | Google decides | Polar, GoCardless, Maxio and Zuora also retry failed payments; see our guides on [Polar](/blog/polar-failed-payments/), [GoCardless](/blog/gocardless-failed-payments/), [Maxio](/blog/maxio-dunning/) and [Zuora](/blog/zuora-payment-retries/) for their rules. ## How does Stripe retry failed subscription payments? Stripe's [Smart Retries page](https://docs.stripe.com/billing/revenue-recovery/smart-retries) says that for new accounts, Stripe enables Smart Retries by default with **up to 8 retries within 2 weeks**. You can set the window to 1 week, 2 weeks, 3 weeks, 1 month or 2 months. The alternative is a custom schedule with **up to three retries**, each a set number of days after the previous attempt. Stripe does not publish the signals its model uses or the exact times it picks. For hard declines such as `lost_card` or `stolen_card`, Stripe will not charge again until a new payment method is attached. Details in [how Stripe Smart Retries work](/blog/stripe-smart-retries/). ## How does Chargebee retry failed payments? Chargebee's [dunning documentation](https://www.chargebee.com/docs/payments/2.0/dunning/dunning-v2) describes two modes: - **Smart:** Chargebee picks the timing from transaction patterns and the type of gateway error, and retries **up to 12 times**. - **Custom:** you choose **1 to 5 retries** and the days they run. Chargebee's example: with an 8-day dunning period and a retry frequency of "1,4,8", retries run 1, 4 and 8 days after the first failure. Retries only happen inside the dunning period, so its length caps everything else. More in [how to recover failed payments in Chargebee](/blog/chargebee-failed-payments/). ## How does Recurly retry failed payments? Recurly's [Intelligent Retries](https://docs.recurly.com/docs/retry-logic) use a machine learning model on soft declines only. Retries stop at **20 total transaction attempts or 60 days from invoice creation**, whichever comes first. Direct debit (ACH, SEPA) is not included. The non-ML option, [static retries](https://docs.recurly.com/recurly-subscriptions/docs/static-retries), schedules attempts from decline codes and merchant advice codes and stops after **7 transaction declines, 20 total attempts or 60 days**, or earlier if the dunning cycle ends first. See [how to set up dunning in Recurly](/blog/recurly-dunning/). ## How do Paddle and Lemon Squeezy retry failed payments? Both are merchants of record, so they run retries for you and you mostly react to status changes. - **Paddle Billing:** Paddle's [2025 changelog](https://developer.paddle.com/changelog/2025/default-dunning-payment-recovery) says failed payments on automatically collected subscriptions are retried **up to seven times over 30 days**, at times chosen by Paddle's algorithms. If the customer does not update their payment method, the subscription is canceled after 30 days. See [failed payments on Paddle](/blog/paddle-failed-payments/). - **Lemon Squeezy:** the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object) says a failed renewal moves the subscription to `past_due`, followed by **4 payment retries over about 2 weeks**. PayPal subscriptions follow PayPal's own cadence, which the [Recovery and Dunning page](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning) describes as a retry **every 5 days**. See [failed payments on Lemon Squeezy](/blog/lemon-squeezy-failed-payments/). ## How does Mollie retry failed subscription payments? Mollie's [recurring payments guide](https://docs.mollie.com/docs/recurring-payments) says a failed subscription payment may be attempted again **up to 5 times, once a day**, depending on the failure reason, and that behavior may differ per payment method. When all retries are exhausted, **the subscription is cancelled**. That is a short window compared with card-first platforms, so the customer email matters more. See [failed recurring payments on Mollie](/blog/mollie-failed-recurring-payments/). ## How does Braintree retry failed subscription payments? Braintree's [recurring billing advanced settings](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings) describe a two-stage process: 1. When a transaction fails, there are **three built-in automated retries** before the subscription is marked Past Due, which can take up to two days. A processor decline or gateway rejection moves the subscription to Past Due immediately. 2. Once Past Due, Braintree tries **at least two more times**. You set each interval in the Control Panel, **between 1 and 10 days**. 3. After that, you choose: cancel the subscription, keep retrying once per billing cycle, or leave it past due. Braintree sends no customer emails for this, so the card update page and reminders are yours to build. See [failed subscription payments on Braintree](/blog/braintree-failed-subscription-payments/). ## How do the App Store and Google Play retry payments? On the stores, you cannot retry a charge or choose the schedule. What you control is how long the customer keeps access. - **App Store:** Apple's [involuntary churn guide](https://developer.apple.com/documentation/storekit/reducing-involuntary-subscriber-churn) says a failed renewal enters a billing retry state where the App Store tries to collect payment **for up to 60 days**. Billing Grace Period lets the customer keep access during part of that time. See [App Store billing retry and grace period](/blog/app-store-billing-retry-grace-period/). - **Google Play:** Google's [subscription lifecycle page](https://developer.android.com/google/play/billing/lifecycle/subscriptions) says grace period and account hold are enabled by default, and account hold lasts **60 days minus the grace period**. With a 0-day grace period, Google still waits at least 1 day for retries. See [Google Play grace period and account hold](/blog/google-play-grace-period-account-hold/). ## How many retries are too many? There is no single right number, but a few rules hold across platforms: - **Do not retry hard declines.** Lost, stolen or closed cards will not start working. Every major platform above either skips them or waits for a new payment method. - **Card networks limit retries.** Recurly's [August 4, 2026 changelog](https://docs.recurly.com/recurly-subscriptions/v2021-02-25/changelog/august-4-2026-recurly-subscriptions-management) says it now retries soft declines up to 20 times per 30-day period, "aligning with card network retry rules". If you build your own retries, check your processor's limits before adding more attempts. - **Keep the window shorter than the billing cycle.** On a monthly plan, a window longer than a month means a second invoice lands on the first. Recurly's [dunning windows guide](https://docs.recurly.com/recurly-subscriptions/docs/navigate-retain-dunning-101-dunning-windows), for example, recommends a 27-day window for monthly billing. - **Timing beats volume.** For `insufficient_funds`, one retry after a likely payday can do more than several retries the same week. ## Retries or emails: which recovers more? Retries recover customers whose card works again on its own. Everyone else needs to act: update an expired card, confirm a 3D Secure payment, call their bank. On Stripe, a hard-declined invoice only gets charged again once a new payment method is attached, and Apple's documentation says the App Store attempts to renew immediately when the customer updates their payment information. Either way, the email or in-app message that gets the customer to the update page is what recovers them. Pair the retry schedule with a short email sequence; our [dunning email templates](/blog/dunning-email-templates/) cover days 0, 3, 7 and 14. ## FAQ ### How many times does Stripe retry a failed payment? With Smart Retries on a new account, up to 8 times within 2 weeks by default, per Stripe's docs. You can change the window to between 1 week and 2 months, or use a custom schedule of up to three retries. ### Should I use smart retries or a fixed schedule? Start with the platform's smart option if it has one; it is usually the recommended default. Move to a fixed schedule when you know something the model does not, such as when your customers are paid. ### Do retries continue after the subscription is canceled? It depends on the platform. Some keep collecting open invoices after a cancellation, others stop. Check your platform's end-of-retry and cancellation settings before you rely on either behavior. ### Can I retry App Store or Google Play payments myself? No. Apple and Google run all retries. You can only extend access with a grace period and send the customer to the store's subscription page. ## How NoChurn helps NoChurn sits next to your billing platform's retries rather than replacing them. On Stripe you can keep Smart Retries or let NoChurn time retries to likely paydays and the customer's local time; on other platforms, retries stay where the platform runs them. On top, NoChurn sends AI-written recovery emails on days 0, 3, 7 and 14 by default, reviewed by you before they go out, with a link to update the payment method, and shows logged-in customers an in-app banner or wall. It works with Stripe in one click, with Chargebee, Recurly, Paddle, Lemon Squeezy, Mollie, Braintree, the App Store, Google Play and others, or with any billing through the API. See [failed payments](/features/failed-payments/). --- # Annual vs monthly plans: what changes for churn Source: https://www.nochurn.sh/blog/annual-vs-monthly-churn/ Annual plans are often presented as a churn fix: customers commit for a year, so they cannot leave next month. That is true, and it is also incomplete. Annual plans move churn into one moment, the renewal, change how you have to measure it, and bring their own risks: a large charge on a card that may have changed, notice rules, and refund requests. This guide covers what actually changes. All numbers are hypothetical. ## Monthly customers decide twelve times; annual customers decide once A monthly customer can leave at the end of any month. An annual customer can, in practice, only leave at renewal (unless your terms allow mid-term cancellation with a refund). So: - **Monthly churn** is spread across the year and shows up in every monthly report. - **Annual churn** arrives in lumps, in the months when large groups of annual customers renew. A month where many annual customers renew can look like a churn spike even if nothing changed. A month with no annual renewals can look like perfect retention. Neither tells you much. ## Compare them fairly ### Measure annual plans by renewal rate For annual plans, the useful number is the renewal rate: ```text annual renewal rate = annual subscriptions that renewed ÷ annual subscriptions that came up for renewal ``` Count by renewal date, not by calendar month of the report. If 40 annual subscriptions came up for renewal in Q2 and 31 renewed, the Q2 renewal rate is 31 ÷ 40 = 77.5%. ### Convert monthly churn to a 12-month figure To compare with monthly plans, compound monthly churn over a year: ```text 12-month retention (monthly plans) = (1 − monthly churn) ^ 12 ``` Hypothetical example: monthly plans churn 4% a month. Then 0.96¹² ≈ 0.613, so about 61% of a group of monthly customers remain after 12 months. Annual customers renewing at 77.5% look better on this comparison. This assumes a constant monthly rate, which is rarely true: new customers churn faster than older ones. A [cohort table](/blog/cohort-retention-analysis/) of monthly customers, read at month 12, is more accurate than the formula. ### Watch the selection bias Customers who choose annual plans differ from those who choose monthly. They are often more committed before they pay, have budget approved, or have already tested the product. Better retention on annual plans may come from who picks them, not from the plan itself. So "move everyone to annual and churn drops" does not follow. If you push hesitant customers onto annual plans with a big discount, you may get a weaker renewal rate than your current annual customers show, plus more refund requests. If you want to know the plan's own effect, test it: offer annual to a random half of a segment and compare 12-month revenue retention for the whole segment, not just for those who took it. ## Normalize revenue In MRR, an annual plan counts as one twelfth of its price each month. When an annual customer churns, the whole twelfth disappears from MRR at once at renewal, while the cash was collected a year earlier. Two practical consequences: - **Revenue churn on annual plans is lumpy.** Report it on a trailing 12-month basis or by renewal cohort. - **Do not mix intervals in one cohort table.** Annual customers are "active" for months 1 to 11 by construction, which flattens a mixed curve. Split by billing interval. See the [churn dashboard guide](/blog/churn-dashboard-metrics/) for the definitions to write down. ## Failed renewals hit harder on annual plans A monthly customer whose card fails misses one month's payment. An annual customer whose renewal fails puts a full year of revenue at risk in one charge. Several things make annual renewals more fragile: - **Twelve months is a long time for a card.** It may have expired, been reissued or been replaced since the last charge. Card account updater services help with reissued cards; Stripe's version is described in its [revenue recovery docs](https://docs.stripe.com/billing/revenue-recovery) (accessed November 2026). See [expiring cards](/blog/expiring-cards/). - **The amount is larger.** A full year's charge can run into a card's available balance or limit where a monthly charge would not, and in Europe a bank may ask for authentication; see [authentication-required renewals](/blog/sca-authentication-required-renewals/). - **The customer may have forgotten.** A forgotten charge is a candidate for a dispute. The fixes: check the card before renewal (for example, contact customers whose card expires before the renewal date), send a renewal reminder, and run the same retries and recovery emails you use for monthly plans, ideally with more urgency in the copy because more is at stake. ## Renewal notice rules Annual plans come with notice obligations that monthly plans often do not. Two we could verify, both covered in detail in [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/): - **California.** For automatic renewals with an initial term of one year or longer, a notice is due at least 15 and at most 45 days before renewal ([Cal. Bus. & Prof. Code section 17602](https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=17602)). - **Mastercard.** According to [Stripe's guidance on Mastercard's recurring billing requirements](https://support.stripe.com/questions/guidance-for-mastercard-recurring-billing-compliance-updates), merchants must send a reminder before charging subscriptions billed six or more months apart. In Germany, for consumer contracts concluded since March 2022, a contract tacitly extended after its initial term must be cancellable at any time with at most one month's notice, which changes what an "annual renewal" means after year one (see the renewal reminders guide for the source). ## Cancellation and refunds Decide and publish what happens when an annual customer cancels mid-term: | Policy | Effect on churn reporting | |---|---| | Cancel at period end, no refund | Churn recorded at renewal date | | Prorated refund on request | Churn recorded when cancelled; revenue reversed | | Full refund within N days of renewal | Some renewals reverse shortly after; track them | Whatever you choose, make cancellation easy to find. On an annual plan the cancel flow is used once a year, often right after the renewal reminder, so it matters more per use than on a monthly plan. A clear "turn off renewal" option avoids the angriest outcome: a customer who wanted to leave, got charged for a year and disputes it. ## Offering annual plans in a cancel flow An annual plan can itself be a retention offer for monthly customers who say "too expensive": the same product at a lower effective monthly price, in exchange for commitment. It fits customers who use the product steadily and expect to keep using it. It does not fit customers who are leaving because they do not use it enough; for them a pause or a cheaper plan is more honest. See [downgrade offers](/blog/downgrade-offers/). ## Checklist - [ ] Annual and monthly plans reported separately. - [ ] Annual churn measured as renewal rate by renewal cohort. - [ ] Renewal reminder sent within the notice windows of your markets. - [ ] Cards checked before annual renewals; expiring cards contacted. - [ ] Recovery emails and retries active for failed annual renewals. - [ ] Mid-term cancellation and refund policy written and visible. - [ ] Any "switch to annual" push tested against a holdout. ## Doing this with NoChurn NoChurn treats a failed annual renewal like any failed payment: on Stripe, smart retries timed to the decline reason and payday, AI-written recovery emails you can review, and a hosted card update page; on other billing tools, those emails and the card update link next to the provider's own dunning. Cancel flows ask for the reason and show one offer per reason (discount, pause or plan change) with one-click cancel always visible. Customers who leave get win-back emails at day 30, 60 and 90 by reason, and every customer has a churn score from 0 to 100, updated on every change. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # How to reduce involuntary churn on the App Store: billing retry and grace period Source: https://www.nochurn.sh/blog/app-store-billing-retry-grace-period/ On the App Store, Apple charges the customer, Apple retries the payment, and Apple owns the cancel button. You cannot retry a charge, change a customer's card or see their email address. That does not mean you can do nothing: what you control is how long the customer keeps access, what your app tells them, and how you react to each notification. This guide covers billing retry, Billing Grace Period, the App Store Server Notifications V2 that tell you what happened, what your app is allowed to do, win-back offers, and refund requests. It sticks to Apple's documentation: [Reducing involuntary subscriber churn](https://developer.apple.com/documentation/storekit/reducing-involuntary-subscriber-churn), [Enable Billing Grace Period](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions), the [notificationType reference](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype), the [billingIssue message](https://developer.apple.com/documentation/storekit/message/reason-swift.struct/billingissue), [Supporting win-back offers in your app](https://developer.apple.com/documentation/storekit/supporting-win-back-offers-in-your-app) and [Send Consumption Information](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information) (all accessed November 2026). ## What Apple does when a renewal fails When a renewal fails because of a billing problem, the subscription enters the **billing retry** state. Apple's documentation says the App Store then tries to collect payment for up to 60 days. - If Apple recovers the payment during billing retry, the subscription renews. Without a grace period, the new billing date is the date of recovery, so subsequent renewals move. - If the billing retry period ends without success, the subscription expires. You do not choose the retry schedule and you cannot trigger a retry. Apple does say that when the customer updates their payment information, the App Store immediately attempts to renew. So the most useful thing you can do is get the customer to fix their payment method. ### Billing Grace Period By default, a customer in billing retry loses access. **Billing Grace Period** lets them keep full access for a while as Apple tries to collect. You turn it on in App Store Connect, under your app's Subscriptions section. According to [Apple's help page](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions): | Grace period chosen | Weekly subscriptions | Monthly and yearly subscriptions | |---|---|---| | 3 days | 3 days | 3 days | | 16 days | 6 days | 16 days | | 28 days | 6 days | 28 days | Other points from the same page: - The setting applies to all auto-renewable subscriptions in the app; it cannot be set per product. - You choose whether it applies to **all renewals** (including free trials and free offers turning paid) or **only paid-to-paid renewals**. - You can enable it in sandbox only first, then in production. - Changes can take up to 24 hours and apply to upcoming renewals only. - It does not apply to monthly subscriptions with a 12-month commitment. - Your app must still check the renewal status and give full service during the grace period. The difference matters for revenue: if Apple recovers the payment within the grace period, the customer's days of paid service and your revenue are not interrupted, and the subscription keeps its original billing date. A recovery after the grace period, but still within billing retry, renews on the recovery date. ## The notifications to handle App Store Server Notifications V2 tell your server about each step. The [notificationType reference](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype) lists these billing events: | Event | `notificationType` | `subtype` | |---|---|---| | Renewal fails, subscription enters billing retry | `DID_FAIL_TO_RENEW` | none | | Renewal fails, billing retry with Billing Grace Period | `DID_FAIL_TO_RENEW` | `GRACE_PERIOD` | | Subscription leaves the grace period (billing retry continues) | `GRACE_PERIOD_EXPIRED` | none | | Billing retry recovers the subscription | `DID_RENEW` | `BILLING_RECOVERY` | | Billing retry ends without recovery | `EXPIRED` | `BILLING_RETRY` | | Customer turns off auto-renew | `DID_CHANGE_RENEWAL_STATUS` | `AUTO_RENEW_DISABLED` | | Customer turns auto-renew back on | `DID_CHANGE_RENEWAL_STATUS` | `AUTO_RENEW_ENABLED` | | Subscription expires after the customer cancelled | `EXPIRED` | `VOLUNTARY` | Note that `GRACE_PERIOD_EXPIRED` does not mean the customer is gone. Apple keeps trying; you just stop giving access. You can also ask for the current state with the App Store Server API's [Get All Subscription Statuses](https://developer.apple.com/documentation/appstoreserverapi/get-all-subscription-statuses) endpoint. Its [status](https://developer.apple.com/documentation/appstoreserverapi/status) field is `1` (active), `2` (expired), `3` (billing retry), `4` (Billing Grace Period) or `5` (revoked). The renewal info also carries [`isInBillingRetryPeriod`](https://developer.apple.com/documentation/appstoreserverapi/isinbillingretryperiod), [`gracePeriodExpiresDate`](https://developer.apple.com/documentation/appstoreserverapi/graceperiodexpiresdate) and an [`expirationIntent`](https://developer.apple.com/documentation/appstoreserverapi/expirationintent), where `2` means a billing error and `1` means the customer cancelled. ### Treat `AUTO_RENEW_DISABLED` as an early warning `DID_CHANGE_RENEWAL_STATUS` with `AUTO_RENEW_DISABLED` is the closest thing to a cancellation on the App Store: the customer still has access until the end of the period, but will not renew. It is not a payment failure, but it is the best moment for a retention message, because the subscription is still active. ## What your app can do Apple is explicit about which tools you have. 1. **Let StoreKit show the billing message.** When a subscription is in billing retry, the App Store sends a [`billingIssue` message](https://developer.apple.com/documentation/storekit/message/reason-swift.struct/billingissue). StoreKit shows a Billing Problem sheet when your app launches (or when you ask it to), and the customer can fix their payment method without leaving your app. Apple documents the frequency: every 24 hours on days 1 to 3, every 72 hours on days 4 to 16, every 96 hours on days 17 to 30 and every 120 hours on days 31 to 60. You can delay or suppress it, but if you have no better message, let it show. 2. **Show your own in-app message.** Apple's guide on involuntary churn says your app may tell users they can avoid losing access by resolving their billing error, and can deep link to the Manage Payments page of their account. Check `expirationIntent` first, so you do not show a billing message to someone who cancelled. 3. **Link to subscription management.** [`showManageSubscriptions(in:)`](https://developer.apple.com/documentation/storekit/appstore/showmanagesubscriptions(in:)) (or `manageSubscriptionsSheet` in SwiftUI) opens the same sheet as Settings, where the customer can view, change or cancel their subscription. 4. **Contact the customer through your own channels.** If the customer has an account with you and gave you an email, you can email them. Apple does not share the customer's email, so you need to match the App Store transaction to your own user, for example with an `appAccountToken` set at purchase. 5. **Restore access fast.** After a recovery, StoreKit adds the renewal transaction to the queue. Apple notes that if your app is already running, the observer may not be called and the app finds out at the next launch. Your server will usually know first from `DID_RENEW`. What you cannot do: retry the charge, change the payment method yourself, extend billing retry, or remove Apple's own cancel option. ## Win-back offers Once a subscription has churned (expiration date in the past and auto-renew off), Apple lets you offer a **win-back offer**: a free or discounted period for eligible former subscribers. According to [Apple's guide](https://developer.apple.com/documentation/storekit/supporting-win-back-offers-in-your-app): - You configure the offers and eligibility rules in App Store Connect: paid subscription duration, time since expiration, and time between redeemed offers. - Customers can find them in the App Store, in their account's subscription settings, and in your app, where StoreKit can show a win-back offer sheet by default. - App Store Connect gives each offer a direct link that you can send through your own channels, such as email. Before you send it, call Get All Subscription Statuses and check the `eligibleWinBackOfferIds` array, and send the link to eligible customers only. - A redemption after expiry produces `SUBSCRIBED` with subtype `RESUBSCRIBE`; transactions redeemed with a win-back offer have `offerType` `4`. For active subscribers, Apple's promotional offers and offer codes are the related tools (redemption sends `OFFER_REDEEMED`). ## Refund requests and `CONSUMPTION_REQUEST` Customers ask Apple, not you, for refunds, and Apple decides. When a customer requests a refund, the App Store sends a `CONSUMPTION_REQUEST` notification. If the customer consented to sharing their data with Apple, you can answer with the [Send Consumption Information](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information) endpoint within 12 hours. Apple says it uses this information to inform its refund decisions. You are responsible for getting valid consent, and Apple says not to use the App Tracking Transparency prompt for it. If you do not have consent, do not respond. When Apple refunds, you receive `REFUND`; when it declines a refund requested through your app, `REFUND_DECLINED`; and if a refund is reversed, `REFUND_REVERSED`. ## A checklist - [ ] App Store Server Notifications V2 are enabled, and your server handles the billing events above. - [ ] Billing Grace Period is turned on, tested in sandbox, then enabled in production. - [ ] Your app grants access during the grace period and removes it on `GRACE_PERIOD_EXPIRED`. - [ ] The StoreKit billing message is allowed to show, or replaced with your own. - [ ] Your settings screen links to subscription management. - [ ] Each purchase carries an `appAccountToken`, so you can reach the customer. - [ ] Win-back offers are configured and sent only to eligible customers. - [ ] Consumption requests are answered within 12 hours when the customer consented. ## Doing this with NoChurn Apple keeps payments, retries, the grace period and the cancel button; NoChurn does not change that. NoChurn reads your App Store Server Notifications, matches each subscription to your user through the `appAccountToken`, and puts billing problems, auto-renew changes and refunds on the customer timeline and in a churn score from 0 to 100. Where Apple allows it, it acts: messages in your app or by email linking to Apple's subscription settings, a cancel flow your app shows through the headless API before linking to Apple, win-back emails at day 30, 60 and 90 based on the cancel reason, and answers to consumption requests from your own usage data. See [NoChurn + App Store](/integrations/app-store/). --- # How to reduce cancellations in an iOS app without hiding the cancel button Source: https://www.nochurn.sh/blog/app-store-cancellation-retention/ On iOS, the cancel button is not yours. Customers cancel an App Store subscription in their Apple Account settings, and Apple executes it. You cannot block that, delay it or put a maze in front of it. What you can do is help the customer who is about to leave find a better option, in your app before they reach Apple's page, and, for some developers, on Apple's own confirmation screen. This guide covers the tools Apple documents for that, and a cancel flow that respects them. It is based on Apple's documentation for [`showManageSubscriptions(in:)`](https://developer.apple.com/documentation/storekit/appstore/showmanagesubscriptions%28in:%29), the [Retention Messaging API](https://developer.apple.com/documentation/retentionmessaging), [promotional offers](https://developer.apple.com/documentation/storekit/implementing-promotional-offers-in-your-app), the [notificationType reference](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype) and the [App Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) (all accessed November 2026). ## What Apple controls - **Where cancellation happens.** Apple's notification reference describes cancellation as the customer canceling "from the App Store Subscriptions settings page." Your server then receives `DID_CHANGE_RENEWAL_STATUS` with subtype `AUTO_RENEW_DISABLED`. - **What canceling means.** The subscription stops renewing. The customer keeps access until the end of the paid period, and you later receive `EXPIRED` with subtype `VOLUNTARY`. - **The sheet in your app.** StoreKit's `showManageSubscriptions(in:)` (or `manageSubscriptionsSheet` in SwiftUI) opens the same management screen customers see in their account settings, with the options to view, upgrade, downgrade or cancel. Apple recommends adding a manage subscriptions option to your app. And the rules: [App Review Guideline 5.6](https://developer.apple.com/app-store/review/guidelines/) (Developer Code of Conduct) says apps should never "trick" customers or "engage in any other manipulative practices within or outside of the app," and repeated manipulative behavior can get you removed from the Developer Program. Guideline 3.1.2(a) adds that subscription apps that "attempt to trick users" or use bait-and-switch practices will be removed. A cancel flow that hides the exit is exactly what these rules target, beyond any consumer law in your markets. ## Tool 1: your own "Manage subscription" screen Before opening Apple's sheet, your app can show its own screen. This is where most of the retention work happens, and you control it fully, as long as it does not get in the way. A pattern that respects the rules: 1. **One screen, one question.** "What's the main reason you want to cancel?" with four to six answers and a free text field. 2. **One relevant answer to that reason.** Too expensive: a cheaper plan or a discount. Not using it: a reminder of what they would lose, or a downgrade. Missing feature: a way to tell you, and an honest answer about plans. 3. **A "Continue to cancel" button visible at every step**, opening `showManageSubscriptions(in:)`. Same size and weight as the offer button. No extra confirmation, no countdown. 4. **Skippable question.** The customer can go straight to Apple's sheet without answering. Apple does not send you a cancellation reason; the notification fields it documents for `AUTO_RENEW_DISABLED` do not include one. The answer to your own question is the only reason you will get, so store it with the customer. ## Tool 2: offers Apple can actually execute On iOS, any discount or plan change must go through StoreKit. Two options fit a cancel flow. ### Promotional offers Apple's guide says promotional offers can be effective in "retaining current subscribers." You create them in App Store Connect (up to 10 active per subscription), your server signs each offer, and the customer redeems it in your app. Apple even suggests using the `DID_CHANGE_RENEWAL_STATUS` notification to decide eligibility, so a customer who just turned off renewal can see an offer the next time they open the app. ### Plan changes within the group A downgrade is often a better answer than a discount. Within a subscription group, Apple's notification reference says downgrades take effect at the next renewal date and do not affect the current plan, while upgrades take effect immediately with a prorated refund of the unused period. You receive `DID_CHANGE_RENEWAL_PREF` with subtype `DOWNGRADE` or `UPGRADE`. A cheaper tier, or a switch from monthly to a longer period, keeps the customer paying something. If you want to offer a pause, check what Apple currently supports for your product type. The documentation used for this guide describes downgrades, promotional offers and retention messages, not a pause option. ## Tool 3: retention messages on Apple's own screen Apple's [Retention Messaging API](https://developer.apple.com/documentation/retentionmessaging) lets you choose a message shown after the customer taps Cancel Subscription on a subscription details page. Apple then shows a Confirm Cancellation page where the customer can still cancel, keep the subscription, or, depending on the message, redeem an offer or switch plan. What Apple documents: - **It is a pre-release API.** You have to request access. - **Four message types:** text (with optional bullet points), text with an image, a switch-plan message suggesting another subscription, and a promotional-offer message. - **Default messages** per product and locale, text-based only. Without a default message for a locale, nothing is shown there. - **Real-time messages.** Apple's server calls your endpoint when an active subscriber views a subscription details page with a Cancel button, and you pick a preconfigured message, including offer and switch-plan messages. Defaults act as the fallback if your server does not answer. Before going to production, your endpoint must pass Apple's performance test. - **Devices:** iOS and iPadOS 15.1 or later, visionOS 1 or later, macOS 14 or later. - Apple asks you not to upload misleading or inaccurate content. This is the closest thing on iOS to a retention step inside the cancel flow itself, and Apple keeps the Cancel Subscription button on that page. ## After the customer turns off renewal A turned-off renewal is not a lost customer yet. Between `AUTO_RENEW_DISABLED` and `EXPIRED`, the subscription is still active. - **Don't cut access early.** They paid for the period. - **Show a quiet banner** in the app with the end date and a way to turn renewal back on (Apple's sheet again). If they do, you receive `DID_CHANGE_RENEWAL_STATUS` with `AUTO_RENEW_ENABLED`. - **Use the time for one relevant message**, based on the reason they gave. One, not a sequence. - **Plan for after expiry.** Once the subscription has expired, Apple's [win-back offers](/blog/app-store-win-back-offers/) take over. ## Measuring what works Track, per reason and per offer: 1. How many customers opened your manage screen. 2. How many accepted an offer or changed plan. 3. How many continued to Apple's sheet. 4. How many turned off renewal (from `AUTO_RENEW_DISABLED`), and how many turned it back on. 5. Retention two or three renewals later for those who accepted an offer. The last one matters most. A discount that delays a cancellation by one month is not the same as a customer who stays. ## What to avoid - Hiding the link to Apple's subscription settings, or burying it under several screens. - Making the offer button large and the cancel link small and grey. - Telling customers they must contact support to cancel. - Showing offers the customer cannot actually redeem, or promising terms StoreKit will not apply. - Asking the same customer the same question every time they open the screen. For the general principles behind fair cancel flows, see our [cancel flow best practices](/blog/cancel-flow-best-practices/) and the overview of [click-to-cancel rules](/blog/click-to-cancel-rules/). ## Doing this with NoChurn NoChurn's cancel flow is available as a headless API, so your iOS app can show its own native screen: reasons, one offer (discount, plan change or pause where your billing supports it), and a cancel button that is always visible and opens Apple's subscription settings. The cancel itself stays with Apple. NoChurn records the reason, reads the `AUTO_RENEW_DISABLED` and `EXPIRED` notifications to see what really happened, and uses both for the churn score and for win-back. Setup is on [NoChurn + App Store](/integrations/app-store/). --- # How to handle App Store refund requests (and the consumption request) Source: https://www.nochurn.sh/blog/app-store-refund-requests/ On the App Store, you never issue a subscription refund yourself and you never answer a card dispute. Apple is the merchant: it takes the payment, it decides on refunds, and it deals with the customer's bank. What you can do is narrower but still useful: tell Apple how the customer actually used what they paid for, react correctly when a refund goes through, and spot patterns of abuse. This guide covers that process for auto-renewable subscriptions. It sticks to Apple's own documentation, mainly [Send Consumption Information](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information), the [ConsumptionRequest](https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest) body, the [notificationType reference](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype) and [Get Refund History](https://developer.apple.com/documentation/appstoreserverapi/get-refund-history) (all accessed November 2026). ## How customers ask for a refund Apple's guide to [handling refund notifications](https://developer.apple.com/documentation/storekit/handling-refund-notifications) lists the ways a customer can ask for their money back: - contacting Apple Customer Support; - using Apple's self-service site, reportaproblem.apple.com; - asking their payment method issuer for a refund. There is a fourth route you control: your app can open Apple's refund sheet with StoreKit's [`beginRefundRequest(in:)`](https://developer.apple.com/documentation/storekit/transaction/beginrefundrequest%28in:%29-63bvd). Apple suggests calling it from account settings or a help menu. The sheet shows the purchase and a list of reasons, and Apple's documentation says the App Store takes up to 48 hours to approve or deny the request. Whatever the route, the decision is Apple's. You have no button to approve or decline. ## The notifications you will receive If you have [App Store Server Notifications V2](https://developer.apple.com/documentation/appstoreservernotifications/enabling-app-store-server-notifications) set up, refunds produce a small set of events: | Notification | What it means | |---|---| | `CONSUMPTION_REQUEST` | A customer started a refund request and Apple asks you for consumption data | | `REFUND` | Apple refunded a transaction | | `REFUND_DECLINED` | Apple declined a refund request | | `REFUND_REVERSED` | Apple reversed a refund it had granted, because of a dispute the customer raised | | `DID_CHANGE_RENEWAL_STATUS` with `AUTO_RENEW_DISABLED` | Among other cases, the system turned off auto-renew because the customer requested a refund through your app | | `REVOKE` | Access through Family Sharing or a group ended, for example because the purchaser was refunded | The `CONSUMPTION_REQUEST` payload carries a `consumptionRequestReason` with the reason the customer gave. Apple documents [five values](https://developer.apple.com/documentation/appstoreservernotifications/consumptionrequestreason): `UNINTENDED_PURCHASE`, `FULFILLMENT_ISSUE`, `UNSATISFIED_WITH_PURCHASE`, `LEGAL` and `OTHER`. Store it. Over time it tells you whether refunds come from accidental purchases, from bugs, or from people who simply did not like the product. ## Answering the consumption request Apple says it "uses a variety of factors" to decide on a refund, and that the consumption information you send is one of them. It is your only way to put facts in front of the reviewer. ### The rules Apple's documentation is strict on three points: 1. **Consent first.** You may only send data if the customer consented to share it with Apple. If they did not, Apple says not to respond to the `CONSUMPTION_REQUEST` at all. The server rejects any request where `customerConsented` is not `true` with an HTTP 400 error. 2. **12 hours.** Respond within 12 hours of receiving the notification. 3. **Consent is your job.** Apple states that you are "solely responsible for obtaining valid consent", that it must be freely given, specific, informed and unambiguous, and that you must not use the App Tracking Transparency prompt for it. If you adopt the API, you also have to disclose the data use in your app privacy details. ### The request You call `PUT https://api.storekit.apple.com/inApps/v2/transactions/consumption/` followed by the transaction ID from the notification. The [ConsumptionRequest](https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest) body has five fields: | Field | What to put in it | |---|---| | `customerConsented` | `true`, the only value Apple accepts | | `deliveryStatus` | `DELIVERED`, or one of `UNDELIVERED_QUALITY_ISSUE`, `UNDELIVERED_WRONG_ITEM`, `UNDELIVERED_SERVER_OUTAGE`, `UNDELIVERED_OTHER` | | `consumptionPercentage` | How much was consumed, in milliunits. Must be 0 if the item was not delivered | | `refundPreference` | Optional: `GRANT_FULL`, `GRANT_PRORATED` or `DECLINE` | | `sampleContentProvided` | Whether you offered a free sample, trial or description of the functionality before purchase | For auto-renewable subscriptions, one constraint matters: if you choose `GRANT_PRORATED`, do not send `consumptionPercentage`. Apple [calculates the percentage itself](https://developer.apple.com/documentation/appstoreserverapi/refundpreference) for subscriptions. ### Choosing what to say Be honest, because it is the right thing to do and because Apple gets the last word anyway. A simple rule set: - **The app failed** (outage, broken feature, content never unlocked): set the matching `UNDELIVERED_*` status, a consumption of 0, and `GRANT_FULL`. Fighting a refund for something that did not work is pointless. - **Accidental purchase, no usage**: `DELIVERED`, 0 or near 0 consumption, and `GRANT_FULL` or no preference. - **Real, sustained usage over the period**: `DELIVERED` and `DECLINE` or `GRANT_PRORATED`, depending on your policy. - **Free trial before the paid period**: set `sampleContentProvided` to `true`. The numbers must come from your own usage data, measured the same way for every customer. That means you need usage tied to the App Store transaction, which in practice means setting an `appAccountToken` at purchase so you can map Apple's transaction to your user. ## When a refund goes through A `REFUND` notification means the money is gone. Apple's notification reference says the transaction's `revocationDate` holds the refund timestamp and `revocationReason` holds the reason. There are [two reason values](https://developer.apple.com/documentation/appstoreserverapi/revocationreason): - `0`: refunded for other reasons, for example an accidental purchase; - `1`: refunded because of an actual or perceived issue within your app. Practical steps: 1. **Revoke access** for the refunded transaction, and say so in the app with a short message. Apple's guide recommends "contextual messaging in the app for any actions you take as a result of the refund." 2. **Record the reason.** A rising share of reason `1` is a product signal, not a billing one. 3. **Watch for reversals.** If a `REFUND_REVERSED` arrives, Apple says you need to reinstate the content or service. For auto-renewable subscriptions, the renewal date stays unchanged. 4. **Backfill missed events.** [Get Refund History](https://developer.apple.com/documentation/appstoreserverapi/get-refund-history) returns a customer's App Store-approved refunds, 20 per page, and Apple suggests it for recovering refund notifications missed during an outage. ## What about chargebacks? Customers can ask their card issuer for a refund, but on the App Store the dispute is between the bank and Apple. You will not receive dispute evidence requests and there is nothing to submit. What you will see is the outcome: a `REFUND` if the money went back, and `REFUND_REVERSED` if Apple reversed a refund after a customer dispute. So the "chargeback work" for an iOS app is mostly prevention and detection: - Make the refund path inside your app easy to find (the `beginRefundRequest` sheet), so unhappy customers use it instead of their bank. - Answer every consumption request you are allowed to answer, on time. - Map refunds to accounts. Apple's guide suggests mapping `REFUND` notifications to your user accounts to "identify repeated refunded purchases" and suspicious activity. ## Common mistakes - **Sending data without consent.** It is rejected by the API and it breaks Apple's rules. - **Missing the 12-hour window.** Process `CONSUMPTION_REQUEST` in a queue with an alert, not in a nightly batch. - **Always sending `DECLINE`.** Your preference is only one factor, and claiming usage you cannot back up does not help. - **Not revoking after a refund**, or not restoring after a reversal. - **No link between Apple transactions and your users.** Without `appAccountToken` you cannot measure consumption, and you cannot answer. ## Doing this with NoChurn NoChurn reads your App Store Server Notifications, so refund requests, refunds, declines and reversals appear on each customer's timeline with the reason Apple gave. When Apple sends a consumption request for a customer who consented, NoChurn can answer it with that customer's real usage from your data, within Apple's window. Refunds also feed the churn score. Apple keeps the payment, the refund decision and anything involving the customer's bank; NoChurn never pretends otherwise. Setup and limits are on [NoChurn + App Store](/integrations/app-store/). --- # Tracking churn with App Store Server Notifications V2 Source: https://www.nochurn.sh/blog/app-store-server-notifications-churn/ App Store Connect gives you sales and subscription reports, but if you want churn numbers you can trust and act on (who left, why, and who is about to), you need your own event log. On iOS, that log comes from **App Store Server Notifications V2**: Apple's server calls yours every time a subscription changes state. This guide shows how to set them up reliably, how each notification maps to a churn metric, and how to fill the gaps. It is based on Apple's documentation: [Enabling App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications/enabling-app-store-server-notifications), [Responding to App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications/responding-to-app-store-server-notifications), the [notificationType reference](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype) and [Get Notification History](https://developer.apple.com/documentation/appstoreserverapi/get-notification-history) (all accessed November 2026). ## Setting up the endpoint Apple's requirements are short: 1. An HTTPS URL on your server, with TLS 1.2 or later. If you specify a port, it must be 443 or 1024 and above. 2. Choose **version 2** for the URL in App Store Connect. Apple recommends V2 for all new implementations. You can set a separate sandbox URL, or reuse the same one. 3. If your firewall uses an allow list, add `17.0.0.0/8`, which covers both sandbox and production. 4. Return HTTP 200 to 206 when you have stored the notification. Any other code counts as a failure. 5. Test with the **Request a Test Notification** endpoint, which sends a `TEST` notification, then check the result with Get Test Notification Status. Each notification arrives as a `signedPayload` in JWS format. Verify the signature before trusting anything in it, then decode the payload. ## Delivery, retries and duplicates Things go wrong: deploys, outages, timeouts. Apple's documentation describes what happens then. - **Retries.** For V2, if your server does not return a success code, Apple retries five times, at 1, 12, 24, 48 and 72 hours after the previous attempt. Retries happen in production only; in sandbox Apple sends each notification once. - **Duplicates.** Each payload has a `notificationUUID`, which Apple says to use to identify duplicates. Store it with a unique constraint and ignore repeats. - **History.** **Get Notification History** returns the notifications Apple attempted to send over the past 180 days in production (30 days in sandbox), 20 records per page, optionally filtered by type, subtype or transaction. Run it after any outage. - **Current truth.** History records reflect the state at the time of sending. For the current state of a subscription, Apple points to **Get All Subscription Statuses**. A good pattern: store the raw notification first, return 200, then process it from a queue. Never do slow work before answering Apple. ## What is in a notification The decoded payload has a `notificationType`, an optional `subtype`, a `signedDate` and a `data` object. For subscriptions, `data` contains: - `signedTransactionInfo`: the transaction (product, dates, offer used, revocation if any). - `signedRenewalInfo`: what will happen at the next renewal, including `autoRenewStatus`, `expirationIntent`, `isInBillingRetryPeriod`, `gracePeriodExpiresDate` and `eligibleWinBackOfferIds`. - `status`: the subscription status as of `signedDate`: `1` active, `2` expired, `3` in billing retry, `4` in Billing Grace Period, `5` revoked. To connect a subscription to one of your users, set an `appAccountToken` at purchase. Apple returns it in the transaction and renewal info. Without it, you only have Apple's transaction IDs. ## Mapping notifications to churn metrics Here is how Apple's notification types translate into the numbers most teams track. Descriptions follow Apple's [notificationType table](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype). | Metric | Notification | Subtype | |---|---|---| | New subscriber | `SUBSCRIBED` | `INITIAL_BUY` | | Returning subscriber (including win-back offers) | `SUBSCRIBED` | `RESUBSCRIBE` | | Renewal | `DID_RENEW` | none | | Cancellation intent (renewal turned off) | `DID_CHANGE_RENEWAL_STATUS` | `AUTO_RENEW_DISABLED` | | Cancellation reversed | `DID_CHANGE_RENEWAL_STATUS` | `AUTO_RENEW_ENABLED` | | Billing failure | `DID_FAIL_TO_RENEW` | `GRACE_PERIOD` or none | | Billing recovered | `DID_RENEW` | `BILLING_RECOVERY` | | Voluntary churn | `EXPIRED` | `VOLUNTARY` | | Involuntary (billing) churn | `EXPIRED` | `BILLING_RETRY` | | Price-increase churn | `EXPIRED` | `PRICE_INCREASE` | | Product removed from sale | `EXPIRED` | `PRODUCT_NOT_FOR_SALE` | | Refund | `REFUND` | none, or `SEATS` for multiseat | | Downgrade scheduled | `DID_CHANGE_RENEWAL_PREF` | `DOWNGRADE` | The `expirationIntent` in the renewal info gives the same split as a number: `1` customer canceled, `2` billing error, `3` no consent to a price increase or offer conversion, `4` product not available, `5` other ([reference](https://developer.apple.com/documentation/appstoreserverapi/expirationintent)). ### Count churn at expiry, not at cancellation On the App Store, a cancellation only stops renewal. The customer keeps access until the period ends, and can turn renewal back on. So: - Use `AUTO_RENEW_DISABLED` as a **leading indicator**: subscriptions at risk this period. - Use `EXPIRED` as the **churn event**: subscriptions that actually ended. If you count churn on `AUTO_RENEW_DISABLED`, you will overstate it and miss every customer who changed their mind. ### Billing churn has a long tail Apple's reference says that after a failed renewal, the App Store keeps retrying billing for 60 days, or until the customer fixes their billing or cancels. With Billing Grace Period enabled, the customer keeps access during the grace period; `GRACE_PERIOD_EXPIRED` marks its end while retries continue. A subscription in billing retry is neither active nor churned yet. Report it as its own bucket, and only count it as churn when `EXPIRED` with `BILLING_RETRY` arrives. Note also `recentSubscriptionStartDate` in the renewal info: Apple computes it ignoring lapses of 60 days or fewer, which is handy for tenure and cohorts. ## A simple churn report from notifications With every notification stored, a monthly report is a handful of queries: 1. **Active at start of month**: subscriptions whose latest status before the month was active, in grace period or in billing retry (decide once whether retry counts as active and stick to it). 2. **Churned**: `EXPIRED` notifications in the month, split by subtype. 3. **Voluntary churn rate**: `EXPIRED`/`VOLUNTARY` divided by active at start. 4. **Involuntary churn rate**: `EXPIRED`/`BILLING_RETRY` divided by active at start. 5. **Billing recovery**: `DID_RENEW`/`BILLING_RECOVERY` divided by `DID_FAIL_TO_RENEW` over the same cohort. 6. **At risk now**: subscriptions whose latest renewal info has auto-renew off and a future expiry. 7. **Reactivations**: `SUBSCRIBED`/`RESUBSCRIBE`. For the general formulas and the traps (mixing monthly and annual plans, counting trials), see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ## Common gaps - **Only listening to V1, or only production.** Test V2 in sandbox before switching production; Apple recommends exactly that order. - **No reconciliation job.** Even with retries, run Get Notification History periodically and after incidents. - **Ignoring Family Sharing and groups.** `SUBSCRIBED` and `REVOKE` also fire for family members and group seats. Decide whether those count as subscribers in your metrics. - **Treating refunds as cancellations.** A `REFUND` ends access and returns money; report it separately. - **No `appAccountToken`.** You get clean App Store numbers but cannot join them with usage, plan or acquisition data, which is where churn explanations come from. ## Doing this with NoChurn NoChurn gives you a URL to paste as your App Store Server Notifications endpoint. It verifies and deduplicates each notification, keeps the timeline per customer (matched by your `appAccountToken`), separates voluntary, billing and price-increase churn, and flags auto-renew turned off as an early risk signal in the churn score from 0 to 100. You can add your own attributes by API to see what drives churn. Apple keeps billing, retries and the cancel button. See [NoChurn + App Store](/integrations/app-store/). --- # App Store win-back and promotional offers: how to bring subscribers back Source: https://www.nochurn.sh/blog/app-store-win-back-offers/ When an iOS subscription lapses, you cannot just email a coupon and charge a card. Apple owns the payment, so any discount has to be an offer Apple knows about. Apple gives you two tools built for this: **win-back offers**, made for people whose subscription has already ended, and **promotional offers**, which work for both lapsed and current subscribers. This guide explains how each works, which one to use when, and how to build a simple win-back plan around them. It sticks to Apple's documentation: [Supporting win-back offers in your app](https://developer.apple.com/documentation/storekit/supporting-win-back-offers-in-your-app), App Store Connect Help on [setting up win-back offers](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-win-back-offers) and [promotional offers](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-promotional-offers-for-auto-renewable-subscriptions), and [Implementing promotional offers in your app](https://developer.apple.com/documentation/storekit/implementing-promotional-offers-in-your-app) (all accessed November 2026). ## Win-back offers Apple defines a win-back offer as a free or discounted offer for customers whose subscription is "churned": its expiration date is in the past and it will not auto-renew. You set them up in App Store Connect, and Apple decides who is eligible based on criteria you choose. ### Eligibility you can set | Criterion | What it means | Allowed values | |---|---|---| | Minimum Paid Duration | How long the customer must have paid for the subscription | 1 to 24 months, or 3, 4 or 5 years | | Time Since Last Subscribed | How long ago the subscription ended | A range between 1 and 24 months; both ends required | | Wait Between Offers | How long after a win-back offer ends before the same customer can redeem it again | 2 to 24 months, optional | Offers are set per subscription product, not per group. Apple's help page notes that customers are eligible only for their most recently lapsed product in each group, so you need an offer on each product you want to cover. ### Limits and rules From the App Store Connect help page: - The subscription must be approved by App Review before you can create a win-back offer. - Up to 350 win-back offers per subscription, and at most 5 per storefront per subscription at a time. - Offer types: pay as you go, pay up front, or free. - The earliest start is one day after creation, and an offer must run at least 3 days. - You cannot change the price, reference name or offer identifier after creating the offer. - When several offers overlap, Apple picks one to show based on price, duration and other factors such as paid tenure. A "High Priority" setting tells Apple which offers matter most to you. ### Where customers see them This is the main advantage of win-back offers: Apple shows them for you. Once live, an offer appears on the customer's Manage Subscriptions page (iOS 14.3 and later) and in your app through a StoreKit win-back offer sheet (iOS 18 and later). If you promote the offer with an approved subscription image, it can also appear on your product page and in App Store recommendations (iOS 18 and later). App Store Connect also creates a direct link in the form `https://apps.apple.com/win-back/` followed by the offer's Apple ID. You can send it through your own channels, such as email. ### Check eligibility before you send a link Apple's StoreKit guide is explicit: before sending a direct link, call **Get All Subscription Statuses** from your server and read `eligibleWinBackOfferIds` in the renewal info. Send the link only to eligible customers. If the array has several IDs, Apple orders them with the best offer first. ### Handle redemptions outside your app Customers can redeem a win-back offer on the App Store or in their account settings, not only in your app. With **Streamlined Purchasing** on (the default), the purchase completes outside your app and your app receives the transaction later, through `Transaction.updates` while running or `Transaction.all` and `currentEntitlements` at launch. Your app must listen for these at launch, unlock access and finish the transaction. With Streamlined Purchasing off, your app receives a `PurchaseIntent` instead and completes the purchase itself, which is useful if you need the customer to log in first. On your server, a redeemed win-back offer shows up as a `SUBSCRIBED` notification with subtype `RESUBSCRIBE` (per Apple's [notificationType table](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype)), and the transaction has an `offerType` of `4`. ## Promotional offers Promotional offers are older and more flexible. Apple's StoreKit guide says they "can be effective in winning back lapsed subscribers or retaining current subscribers." Anyone with an existing or expired subscription in your app is eligible as far as Apple is concerned; any extra criteria are yours to decide in your own code. The trade-offs: - **You do the targeting.** Apple does not show these offers for you. Your app decides who sees which offer. - **Each offer is signed by your server.** The signature uses a key generated in App Store Connect, is time-sensitive and can be redeemed once. - **Redemption happens in your app.** Apple says you can present offers through channels such as email, "but they must interact with the offer inside your app's UI." - **Limits.** Up to 10 active promotional offers per subscription; they apply to all storefronts where the subscription is sold, with optional per-storefront prices. After creation, only the price can be edited. Redeeming an introductory offer does not affect eligibility for a promotional offer. ## Which one to use | Situation | Better fit | |---|---| | Lapsed subscriber who no longer opens your app | Win-back offer: Apple shows it in account settings, and you can email the direct link | | Lapsed subscriber who still opens the free tier of your app | Either; a promotional offer lets you choose the exact moment and message | | Subscriber who turned off auto-renew but is still active | Promotional offer (a win-back offer requires the subscription to have expired) | | You need fine-grained rules (by usage, by cancel reason) | Promotional offer, with the logic on your server | Many apps use both: promotional offers for customers still in the app, win-back offers as the safety net Apple displays everywhere else. ## A practical win-back plan 1. **Know why they left.** A notification with `EXPIRED` and subtype `VOLUNTARY` means the customer turned off renewal; `BILLING_RETRY` means billing failed for good; `PRICE_INCREASE` means they did not accept a price increase. Each needs a different message. If you ask for a reason when customers manage their subscription in your app, keep it too. 2. **Wait a little.** A cancellation is a decision; an offer the next morning can feel pushy. Leave some time before the first message. Your Time Since Last Subscribed range should match that plan. 3. **Match the offer to the reason.** Price-related reasons get a discount; "not using it enough" gets a reminder of what changed, maybe a shorter free period; a billing failure needs no discount at all, just a way back in. 4. **Use channels you actually have.** App Store notifications do not include the customer's email address. You can only email people who gave you their address in your own account system, and you need the `appAccountToken` you set at purchase to connect their App Store transaction to that account. 5. **Check eligibility at send time.** Call Get All Subscription Statuses right before sending a win-back link, not when you schedule the campaign. 6. **Measure redemptions properly.** Count `SUBSCRIBED` / `RESUBSCRIBE` notifications whose transaction carries your offer identifier, and compare with a group that received no offer. Then look again a few months later: a win-back that churns at the first full-price renewal is worth less than it looks. ## Common mistakes - **Not handling out-of-app redemptions**, so the customer pays and the app does not unlock. - **Sending direct links without checking eligibility**, which leads to an "offer not available" experience. - **Offering the same discount to everyone**, including customers who left because of a failed card. - **Forgetting the image** if you want the offer promoted on the App Store. ## Doing this with NoChurn NoChurn reads your App Store Server Notifications, so it knows who lapsed, when and why: voluntary, billing, or price increase. It can send win-back emails at day 30, 60 and 90 based on the cancel reason, to customers whose email you have shared from your app, and include your win-back direct link or point them back to your app for a promotional offer. Apple still decides eligibility, shows the offer and takes the payment. Details on [NoChurn + App Store](/integrations/app-store/). --- # Billing descriptors: the cheapest chargeback prevention Source: https://www.nochurn.sh/blog/billing-descriptor-chargebacks/ A customer looks at their card statement, sees a line they do not recognize, and taps "dispute" in their banking app. The bank files it as fraud. For a subscription business, this is one of the most common ways a perfectly valid charge becomes a chargeback, and the fix costs nothing: change the text on that line. That text is the **statement descriptor** (also called billing descriptor or soft descriptor). This guide explains what it is, the rules on Stripe and Braintree, how to write a good one for subscriptions, and what else helps customers recognize a charge. Sources: Stripe's [statement descriptors](https://docs.stripe.com/get-started/account/statement-descriptors), [what is a statement descriptor](https://support.stripe.com/questions/what-is-a-statement-descriptor-and-how-do-i-update-it), [why customers see descriptors that don't match](https://support.stripe.com/questions/why-do-customers-see-statement-descriptors-that-don-t-match-what-i-ve-set-in-stripe) and [account checklist](https://docs.stripe.com/get-started/account/checklist); Braintree's [descriptors](https://developer.paypal.com/braintree/articles/au/transactions/descriptors) and [Transaction: Sale reference](https://developer.paypal.com/braintree/docs/reference/xml-api/transactions/sale); and Visa's [revised enhanced descriptor policy](https://usa.visa.com/content/dam/VCOM/global/support-legal/documents/revised-enhanced-descriptor-policy.pdf) (all accessed November 2026). ## Why descriptors cause disputes The descriptor is often the only information a customer has about a charge when they look at their statement. Three situations produce "I don't recognize this" disputes: 1. **The descriptor shows the legal entity, not the brand.** "ACME HOLDINGS LTD" means nothing to someone who subscribed to "Planwise". 2. **One company, several products.** If you run three apps under one account and all charges show the same name, customers cannot tell which subscription they are paying for. 3. **The charge comes long after signup.** An annual renewal arrives eleven months after the customer last thought about you. A clear name is the only reminder. These disputes usually come in as fraud (Visa 10.4, Mastercard 4863 "cardholder does not recognize"). Even if you win them, they count toward your [network dispute ratios](/blog/chargeback-ratio-monitoring-programs/). Preventing them is much cheaper. ## The rules on Stripe Stripe's [statement descriptor docs](https://docs.stripe.com/get-started/account/statement-descriptors) set these limits for card payments: | Rule | Limit | |---|---| | Total length | 5 to 22 characters | | Characters | Latin characters only; at least one letter | | Forbidden characters | Angle brackets, single and double quotes, and the asterisk | | Content | Must reflect your business name (DBA), URL or legal name; cannot be only numbers | ### Prefix and dynamic suffix Stripe lets you combine a static **prefix** (called the shortened descriptor in the Dashboard) with a **dynamic suffix** per payment: - The prefix is 2 to 10 characters. - Stripe joins prefix and suffix with an asterisk and a space, and that separator counts toward the 22 characters. With a 7-character prefix, 13 characters remain for the suffix. - Dynamic suffixes only work for card payments. - Only the first 22 characters are sent for card payments; anything longer is cut. For subscriptions, the suffix is where you put the product or plan: `PLANWISE* PRO ANNUAL`. ### What the customer actually sees Stripe's support article on mismatched descriptors explains that some banks show a "friendly" merchant name instead of your descriptor, using several data points from the transaction, and that Stripe has no control over that mapping. Stripe's account checklist adds that issuers may also show other account information, such as business name, address, email or phone number. Check that your public business details in your processor account (support phone, support URL) are ones you are happy for customers to see, and that they work. ## The rules on Braintree Braintree supports **dynamic descriptors** per transaction, but they are not enabled on every account by default. Its [Transaction: Sale reference](https://developer.paypal.com/braintree/docs/reference/xml-api/transactions/sale) describes the name format: | Company part | Product part | Total with asterisk | |---|---|---| | 3 characters | up to 18 | 22 | | 7 characters | up to 14 | 22 | | 12 characters | up to 9 | 22 | Braintree also documents a phone and a URL field for descriptors, and notes that the exact length and character rules depend on your processor, and that some processors accept a URL while others accept only a phone number. Check your account settings before relying on a format. ## What a good subscription descriptor looks like ### Principles 1. **Lead with the name customers know.** The brand in your app, emails and app icon, not the holding company. 2. **Add the product or plan when you have room.** Especially if you sell more than one product or have monthly and annual plans. 3. **Keep it readable.** Avoid abbreviations nobody would guess. 4. **Be consistent.** Use the same descriptor in reminders, receipts and help center articles, so a customer who searches for it finds you. ### Examples | Weak | Better | Why | |---|---|---| | `ACME HOLDINGS LTD` | `PLANWISE* PRO MONTHLY` | Brand and plan instead of legal entity | | `AHL*SUB 88213` | `PLANWISE* TEAM ANNUAL` | No internal codes | | `PLANWISE` | `PLANWISE* RENEWAL` | Signals a recurring charge | | `WWW.PLNWS.IO` | `PLANWISE.COM` | A domain the customer can type | Make sure each example fits your processor's character rules; the asterisk in these examples is Stripe's separator, not a character you type into the prefix. ### Trials When a free trial converts, the first charge is the most likely to surprise. Visa once required an enhanced descriptor for that first charge after a trial; its [revised policy](https://usa.visa.com/content/dam/VCOM/global/support-legal/documents/revised-enhanced-descriptor-policy.pdf) (December 2020) made it optional. Even if optional, a suffix such as `TRIAL END` or `FIRST CHARGE` on that payment helps, if your processor lets you set a per-payment suffix. Visa's [trial rules](https://usa.visa.com/dam/VCOM/global/support-legal/documents/visa-new-subscription-rules-flier.pdf) still require a reminder with a cancel link at least seven days before that charge. ## Tell customers what they will see The descriptor works best when the customer has seen it before. Put it in: - **The checkout page:** "This will appear on your statement as PLANWISE* PRO." - **The welcome email and every receipt.** - **Renewal and trial-end reminders.** See [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/). - **A help center article** titled with the descriptor itself, so a customer who searches "PLANWISE PRO charge" finds it. Stripe's [fraud prevention best practices](https://docs.stripe.com/disputes/prevention/best-practices) also recommend telling customers on your site what they will see on their statement. ## Check what it looks like Do not assume. Make a real purchase on your own card for each product and plan, then look at: - the pending transaction in your banking app; - the posted transaction a few days later; - the monthly statement. Banks and apps display descriptors differently, and some replace them with a friendly name. If what you see is not what you set, contact your processor. ## Measure the effect After a descriptor change, compare over the following months: - the share of disputes with "unrecognized" or fraud reason codes on existing customers; - support tickets asking "what is this charge?"; - inquiries and retrievals (on networks that still use them). Disputes arrive weeks after the charge, so give it at least two billing cycles before judging. ## Descriptor checklist - [ ] Brand name customers know, not the legal entity. - [ ] Product or plan suffix where supported. - [ ] Within your processor's length and character rules. - [ ] Public support phone and URL set and working. - [ ] Descriptor shown at checkout, in receipts and reminders, and in the help center. - [ ] Tested on a real card. - [ ] Separate descriptor per product if you sell several. For the rest of the prevention plan, see [how to prevent chargebacks on subscriptions](/blog/prevent-subscription-chargebacks/). ## Doing this with NoChurn NoChurn does not set your descriptor; that stays in Stripe or Braintree. What it does is show each dispute with its reason, so you can see whether "unrecognized" and fraud disputes drop after you change it, and gather evidence automatically when a dispute still arrives (cancel flow answers, emails sent, usage you send by API, help desk conversations read only), with an AI-drafted reply that a person reviews before it is sent. See [chargebacks](/#disputes). --- # Braintree Account Updater and expiring cards Source: https://www.nochurn.sh/blog/braintree-account-updater/ When a customer's card expires or is replaced, every subscription on the old card is a failed payment waiting to happen. Braintree offers two services that fetch new card details from the networks without asking the customer: Account Updater and network tokens. Neither covers every card, so you still need a way to reach the customers they miss. This guide explains how each service works, the details that matter for subscriptions, and a plan for the rest. It sticks to Braintree's own documentation: [Account Updater](https://developer.paypal.com/braintree/articles/guides/account-updater), the [Account Updater webhook](https://developer.paypal.com/braintree/docs/reference/general/webhooks/account-updater/php), [Expiring Cards report](https://developer.paypal.com/braintree/articles/control-panel/reporting/expiring-cards), [Network tokens overview](https://developer.paypal.com/braintree/docs/guides/network-tokens/overview/), [How network tokens work](https://developer.paypal.com/braintree/docs/guides/network-tokens/how-it-works/), [Updating vault records](https://developer.paypal.com/braintree/articles/control-panel/vault/update) and [Recurring billing advanced settings](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings) (all accessed November 2026). For the general picture across providers, see [network tokens and card account updaters](/blog/network-tokens-card-account-updater/) and [expiring cards](/blog/expiring-cards/). ## Account Updater ### What it does According to [Braintree's Account Updater guide](https://developer.paypal.com/braintree/articles/guides/account-updater), Account Updater automatically requests updates for **vaulted** payment methods when a customer's card expires or is replaced, to help avoid failed transactions. It works through the card networks' updater programs, so an update only arrives if the **issuing bank participates**. ### Who can use it Account Updater is not on by default. Braintree says most Braintree Direct merchants domiciled in the US, or transacting primarily with US customers, can enable it, and asks others to contact them. Fees are set in your agreement: Braintree's [disbursement fee report](https://developer.paypal.com/braintree/articles/guides/disbursement-fee-report/transaction-types) lists Account Updater among the product fees billed as event fees. Check your contract for the price. ### What it does not cover - **Prepaid cards** are not supported. - **Cards used through Apple Pay or Google Pay** are not supported. - Card brands: Braintree's developer guide lists Visa, Mastercard and Discover, while its [marketing page](https://www.braintreepayments.com/features/account-updater) also names American Express. The two sources disagree on Amex; confirm with Braintree for your account. ### When cards are checked After an initial batch, Braintree sends update requests on a rolling basis. The guide describes several triggers, including: - a **recurring payment due within two weeks**; - a **decline** on the card, with one documented exception that matters for subscriptions: a card on a **monthly subscription** that charged successfully 30 days earlier is **not** added to a batch the first time it is declined. That exception means the first failed monthly renewal on a replaced card may not trigger an update by itself. Your retries and customer emails need to cover it. ### Next Day Card Refresh Braintree also describes **Next Day Card Refresh**, which attempts to update vaulted cards after an authorization is declined with certain decline codes. It only helps if something retries the payment afterwards, either Braintree's recurring billing retries or your own logic. If your retry settings are off, the refreshed card sits unused until the next billing cycle. Check them in **Account Settings, Recurring Billing, Options** ([advanced settings](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings)). ### Seeing what changed You can review updates in the Control Panel, in a generated report, or through the **Account Updater daily report** webhook. Per the [webhook reference](https://developer.paypal.com/braintree/docs/reference/general/webhooks/account-updater/php): - it is only available to merchants using Account Updater; - it fires once a day with the payment methods updated in the last 24 hours, and does not fire if there were none; - the payload contains a report date and a report URL, and the link expires after one week. Download and store the report as soon as it arrives. If a card was updated, you no longer need to email that customer about it. ## Network tokens Network tokens are a separate Braintree service. According to the [network tokens overview](https://developer.paypal.com/braintree/docs/guides/network-tokens/overview/) and [how they work](https://developer.paypal.com/braintree/docs/guides/network-tokens/how-it-works/): - The card network passes issuer updates (reissue, theft, loss, and changes such as an approaching expiry) to Braintree, which updates the card details in your vault. - There is **no integration change** needed to start using them. - They are available to merchants in the United States and select regions in North America, South America and Europe processing full stack with Braintree. - A token **may not always be used** for a given transaction. Braintree also documents that merchant-initiated recurring charges carry extra parameters (such as the transaction source and the previous network transaction ID) when you run recurring payments outside Braintree's own recurring billing. If you use Braintree subscriptions, check with Braintree how tokens apply to your setup. | | Account Updater | Network tokens | |---|---|---| | How it updates | Requests to network updater programs, in batches and on triggers | Lifecycle updates from the network to the token | | Setup | Must be enabled; eligibility mainly US | No integration change; regional availability | | Gaps | Prepaid, Apple Pay, Google Pay; non-participating issuers | Token not always used | ## The Expiring Cards report For cards neither service will catch, Braintree's Control Panel has an [Expiring Cards report](https://developer.paypal.com/braintree/articles/control-panel/reporting/expiring-cards): go to Reports, find the Vault section, and run Expiring Cards. You can filter by a custom date range or view all expired cards. Run it monthly for the month ahead. ## The subscription trap: new cards do not move subscriptions Braintree's [vault documentation](https://developer.paypal.com/braintree/articles/control-panel/vault/update) points out that adding a **new** payment method to a customer's vault does not update their existing subscriptions. If a customer adds a new card through your app, you must also update each subscription to use the new payment method, then retry any past due charge with [Subscription: Retry Charge](https://developer.paypal.com/braintree/docs/reference/request/subscription/retry-charge/node). Forgetting this step is a common reason a customer "updated their card" and still churned. ## A plan for expiring cards on Braintree 1. **Enable Account Updater** if you are eligible, and network tokens where available. 2. **Turn on automatic retries** for recurring billing so Next Day Card Refresh has something to act on. 3. **Store the daily Account Updater report** and mark updated cards in your system. 4. **Run the Expiring Cards report monthly** for cards expiring next month. 5. **Email customers whose cards were not updated,** 30 days and again about 7 days before expiry, with one link to a card update page. 6. **On the update page,** save the new card, switch every subscription to it, and retry any past due charge. 7. **Cover the first failed monthly renewal.** Because a monthly subscription card is not batched on its first decline, send a recovery email right away rather than waiting for the updater. 8. **Exclude unsupported cards** (prepaid, Apple Pay, Google Pay) from any assumption that the updater will handle them. ## Doing this with NoChurn Account Updater, network tokens and the charge itself stay with Braintree. NoChurn reads the payment method type, brand, last four digits and expiry from Braintree and adds AI-written emails that you review before they go out, with a hosted page where the customer updates the payment method. When a renewal still fails, recovery emails follow alongside Braintree's subscription retries. See [NoChurn + Braintree](/integrations/braintree/). --- # How to add a cancel flow to Braintree subscriptions Source: https://www.nochurn.sh/blog/braintree-cancel-flow/ Braintree's recurring billing has a single cancel operation, and it is final: a cancelled subscription cannot be edited or reactivated. There is no built-in cancellation page, no reason survey and no retention offer. If you want customers to see an alternative before they leave, and to keep a record of why they left, you build that flow in your app and call Braintree at the end. This guide covers the Braintree operations a cancel flow relies on, the limits that shape it, and a step-by-step design. It sticks to Braintree's own documentation: [Subscription: Cancel](https://developer.paypal.com/braintree/docs/reference/request/subscription/cancel/ruby), [Subscription: Update](https://developer.paypal.com/braintree/docs/reference/request/subscription/update/node), [Manage subscriptions](https://developer.paypal.com/braintree/docs/guides/recurring-billing/manage/php/), [Plans](https://developer.paypal.com/braintree/articles/guides/recurring-billing/plans), [Statuses](https://developer.paypal.com/braintree/docs/reference/general/statuses), [Subscription webhooks](https://developer.paypal.com/braintree/docs/reference/general/webhooks/subscription/node) and the [subscriptions guide](https://developer.paypal.com/braintree/articles/guides/recurring-billing/subscriptions) (all accessed November 2026). ## How cancellation works in Braintree [Subscription: Cancel](https://developer.paypal.com/braintree/docs/reference/request/subscription/cancel/ruby) moves a subscription to **Canceled**, which Braintree's [statuses reference](https://developer.paypal.com/braintree/docs/reference/general/statuses) describes as no further billing occurring. The reference is explicit that once a subscription is cancelled, you cannot edit or reactivate it; a returning customer needs a new subscription. Three consequences for your flow: - **Cancel is the last step, never the first.** Run every offer before the call. - **There is no "cancel at period end" flag** in the cancel operation. If you cancel mid-cycle, billing stops, and what the customer keeps access to is your decision in your app. - **Store the cancellation date yourself.** Braintree notes that the cancellation date is not included in subscription search results and suggests capturing it from the `subscription_canceled` webhook. ### Ending at the end of the paid period Many businesses want the customer to keep access until the end of what they paid for, with no further charge. Two approaches fit Braintree's model: 1. **Cancel now, keep access in your app** until the end of the current billing period, using the period end date you stored for the subscription. 2. **Limit the number of billing cycles.** [Subscription: Update](https://developer.paypal.com/braintree/docs/reference/request/subscription/update/node) lets you set the number of billing cycles, which must be greater than or equal to the current billing cycle, and turns "never expires" off. When a subscription reaches its set number of cycles, Braintree marks it **Expired**. This lets the subscription end naturally after the current cycle, and a customer who changes their mind before then can be restored by setting it back to never expire. The second approach keeps the subscription editable until it ends, which makes "undo" easy. Test it in the sandbox with your plan settings before relying on it. ## What you can offer instead Braintree's [update operation](https://developer.paypal.com/braintree/docs/reference/request/subscription/update/node) gives you the levers for retention offers. ### Discounts You can add, update or remove **discounts** (and add-ons) on an existing subscription. Key rules from the docs: - Discount **details** (name, amount, duration) are managed in the Control Panel, not through the API. Create your retention discounts there first, then apply them by ID. - A given discount can be applied only once to a subscription; to apply it more than once, use its quantity. Create a dedicated retention discount, for example "Retention 30% x3", so accepted offers are easy to find in reports and never confused with sales discounts. ### Price and plan changes You can change the subscription's price, with a flag that controls whether the change is **prorated**, or move it to another plan. Braintree notes that switching to a plan with a **different billing frequency** is only available to select merchants who request it, and resets the current billing cycle. For most cancel flows, a downgrade to a cheaper plan with the same frequency is the simpler offer. ### A pause The Braintree documentation we reviewed does not describe a pause or "skip a cycle" operation for subscriptions. The `subscription_billing_skipped` webhook exists, but it fires when a cycle is skipped because a zero or negative balance already covers it, not on request. If you want to offer a pause, you would build it on top of Braintree (for example with a temporary full discount for a set number of cycles), and test the billing behaviour carefully first. ## Webhooks your flow should listen to From Braintree's [subscription webhooks](https://developer.paypal.com/braintree/docs/reference/general/webhooks/subscription/node): | Kind | Use in a cancel flow | |---|---| | `subscription_canceled` | Record the cancellation date, revoke access when due, start win-back | | `subscription_expired` | The subscription reached its last cycle (for the "limited cycles" approach) | | `subscription_charged_successfully` | Confirms an offer price was charged | Listen even for cancellations you trigger yourself. Support agents can cancel from the Control Panel, and those cancellations should land in the same records. ## Building the flow 1. **Route the cancel button to your own page,** never straight to the API. 2. **Ask why.** Five to seven reasons plus "Other". Store the answer with the Braintree subscription ID. Ideas in [cancellation reason surveys](/blog/cancellation-reasons-survey/). 3. **Show one offer that matches the reason:** | Reason | Offer | Braintree operation | |---|---|---| | Too expensive | Limited-time discount | Update: add a retention discount | | Need less | Cheaper plan | Update: change plan or price | | Not using it right now | A pause, if you have built one | Your own logic (see above) | | Technical problem | Help from support | None until resolved | | Switching or closing | No offer | Cancel | 4. **Keep "Cancel subscription" visible on every step,** as easy to click as the offer. Rules and good practice in [click-to-cancel rules](/blog/click-to-cancel-rules/) and [cancel flow best practices](/blog/cancel-flow-best-practices/). 5. **On accept,** call Subscription: Update, confirm by email with the new price and how long it lasts. 6. **On cancel,** call Subscription: Cancel (or limit billing cycles), show the date access ends, send a confirmation. 7. **Handle past due subscriptions.** A customer cancelling while past due may owe a balance; decide your policy and show it. 8. **Review monthly** which reasons come up most and which offers are still paying after three months. ## Common mistakes - **Cancelling, then trying to apply an offer.** Cancelled subscriptions cannot be edited. - **Creating discounts in code.** Discount details live in the Control Panel; plan them ahead. - **Losing the cancel date.** Without the webhook stored, you cannot time win-back emails or measure churn by month. - **Hiding the cancel option behind the offer.** It costs trust and, in many places, breaks the rules. ## Doing this with NoChurn Braintree keeps the subscription, payments and the cancellation itself. NoChurn's cancel flow asks for the reason, shows an offer (a discount, a plan change or a cancellation on the Braintree subscription), and keeps a one-click cancel visible at every step, hosted or headless through the API. The answers feed win-back emails at day 30, 60 and 90 and a churn score from 0 to 100, and they become evidence if the customer later disputes a charge. See [NoChurn + Braintree](/integrations/braintree/). --- # How to fight chargebacks on Braintree Source: https://www.nochurn.sh/blog/braintree-disputes/ A chargeback on a subscription is rarely about a stolen card. More often the customer forgot they signed up, did not recognise the descriptor, or thought they had cancelled. Those cases are winnable when you have the right records and submit them in the format Braintree expects. Braintree's tooling is good, but strict: miss the date or put evidence in the wrong category and the response never reaches the bank. This guide goes through how Braintree structures disputes, the evidence rules that matter for recurring billing, and a process you can run for every case. It sticks to Braintree's own documentation: the [disputes overview](https://developer.paypal.com/braintree/docs/guides/disputes/overview), [Managing disputes via the API](https://developer.paypal.com/braintree/docs/guides/disputes/managing), [Evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/ruby/), the [Dispute response object](https://developer.paypal.com/braintree/docs/reference/response/dispute/php), [Chargeback reason codes](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/chargeback-reason-codes), [Disputing chargebacks](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/disputing-chargebacks), [Dispute: Accept](https://developer.paypal.com/braintree/docs/reference/request/dispute/accept/ruby) and [PayPal disputes](https://developer.paypal.com/braintree/articles/guides/payment-methods/paypal/disputes) (all accessed November 2026). For the basic API calls and webhook names, see the disputes section of [recovering failed subscription payments on Braintree](/blog/braintree-failed-subscription-payments/). ## Dispute kinds and statuses The [dispute object](https://developer.paypal.com/braintree/docs/reference/response/dispute/php) has a **kind** and a **status**. **Kinds:** | Kind | What it is | |---|---| | Retrieval | A request for information about a transaction | | Chargeback | The cardholder's bank reverses the transaction | | Pre-arbitration | A later stage, after a chargeback | **Statuses:** Open, Accepted, Auto Accepted, Disputed, Won, Lost and Expired. "Disputed" means you have submitted evidence and are waiting for the bank's decision. "Expired" means the reply-by date passed and you forfeited the right to contest. PayPal transactions processed through Braintree follow PayPal's own process, with three stages (retrieval, claim, chargeback) described in Braintree's [PayPal disputes guide](https://developer.paypal.com/braintree/articles/guides/payment-methods/paypal/disputes). Braintree notes that retrievals and claims resolved through PayPal or your gateway do not incur dispute fees, while a dispute escalated to a chargeback may carry fees from the issuer or bank. ### Pre-arbitration auto-accept Per Braintree's [disputing chargebacks article](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/disputing-chargebacks), since August 27, 2025, Braintree auto-accepts pre-arbitrations under $1,000 for flat-rate merchants in the US, and a fee to process the pre-arbitration is charged regardless of the outcome. If you fall in that group, your effort belongs at the first chargeback response. ## The reply-by date is the whole game Every dispute has a reply-by date. According to Braintree, you must add your evidence **and finalize** before it, or your response is not considered by the bank. If you do not respond, an Accept response is sent on your behalf. Uploading evidence without finalizing counts as no response. Practical rules: - Use **Dispute: Search** filtered by reply-by date to list everything due in the next few days. - Set an internal deadline two business days before the reply-by date. - Evidence can only be added or removed (with [Dispute: Remove Evidence](https://developer.paypal.com/braintree/docs/reference/request/dispute/remove-evidence/php/)) while the dispute is **Open**. ## Reason codes that hit subscription businesses The [chargeback reason codes article](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/chargeback-reason-codes) and dispute reference list, among others: - **Cancelled recurring transaction:** the cardholder says they were billed for a recurring charge they cancelled or tried to cancel. Card-brand codes listed by Braintree include Visa 41 and 1320, Mastercard 41 and 4841, Discover 4541 and American Express C28. - **Fraud / not authorised:** the cardholder says they did not make the purchase. - **Not received:** the cardholder says they did not get the product or service. For subscriptions, "cancelled recurring" and "fraud" from customers who forgot the subscription are the common pair. Each needs different evidence. ## Categorized evidence: the rule that trips teams up Braintree's [evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/ruby/) say that when you respond to a **fraud or non-receipt** dispute, you must **categorize each piece of evidence** by the requirement it satisfies. A table in the same guide lists which categories each reason code accepts; using a category not allowed for that code is a validation error, and so is finalizing without valid evidence. Two categories matter most for recurring billing: - `RECURRING_TRANSACTION_ID`: the ID of a previous **undisputed** recurring transaction for the same service. - `RECURRING_TRANSACTION_DATE_TIME`: the date of that transaction. Braintree requires it whenever you provide a recurring transaction ID (or ARN); a response without it is rejected. Proof of previously undisputed recurring transaction history is one of the evidence types Braintree lists for certain fraud and not-received disputes. In plain terms: if the same card paid you for months without complaint, say so, in the right category, with dates. When you dispute through the Control Panel, Braintree adds transaction details such as AVS and CVV results to your response automatically. ## What to submit, by reason | Reason | Evidence that addresses it | |---|---| | Cancelled recurring transaction | Your cancellation policy as shown at sign-up; the customer's account history showing no cancellation request before the charge (or the date they cancelled and that the charge preceded it); renewal reminders sent | | Fraud (customer does not recognise it) | Prior undisputed recurring payments on the same card (categorized), sign-up details, login and usage after the disputed charge | | Not received / service not provided | Usage logs for the billed period, access records, support conversations where the customer used the service | Keep each document focused. A one-page summary that states the facts with dates, followed by the supporting records, is easier for a bank analyst to read than a long export. ### When to accept instead [Dispute: Accept](https://developer.paypal.com/braintree/docs/reference/request/dispute/accept/ruby) closes an Open dispute in the customer's favour. Braintree's docs add one important note: if you already **refunded** the transaction, do not accept; submit the refund as evidence instead. Accept when: - the customer did cancel and you charged anyway (fix the bug, then refund any other affected customers); - the evidence you have does not address the reason code; - the amount is lower than the time a response would take, and you have no pattern to defend. ## A process for every dispute 1. **Webhook in.** On `dispute_opened`, fetch the dispute and record kind, reason, amount and reply-by date. 2. **Stop future charges if appropriate.** A customer disputing a renewal is unlikely to pay the next one. Decide whether to cancel the subscription or pause access while the case is open. 3. **Gather records** from billing, product usage, email and support, for the customer and the disputed period. 4. **Pick the categories** allowed for this reason code and map each record to one. 5. **Write the summary,** add text and file evidence. 6. **Finalize** before your internal deadline. 7. **Track the outcome** from `dispute_won` and `dispute_lost` webhooks, by reason code. 8. **Fix the cause.** Unclear descriptor, missing renewal reminder, a cancel button that was hard to find: each lost dispute should change something. For prevention, see [click-to-cancel rules](/blog/click-to-cancel-rules/) and [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/). ## Test before you go live Braintree's sandbox can simulate outcomes: submitting the text `compelling_evidence` and finalizing moves a test dispute to Won, and `losing_evidence` simulates a loss ([testing guide](https://developer.paypal.com/braintree/docs/guides/disputes/testing-go-live/php)). Use it to check your categorization and finalize logic end to end. ## Doing this with NoChurn Braintree keeps the dispute, the decision and the funds. NoChurn follows Braintree dispute webhooks and gathers evidence automatically: cancel flow answers, emails sent, product usage and support conversations. It drafts a reply with AI, and nothing is sent to Braintree until a person on your team has reviewed and approved it. Support conversations come from read-only help desk connectors and are quoted as is. See [NoChurn + Braintree](/integrations/braintree/). --- # How to recover failed subscription payments on Braintree Source: https://www.nochurn.sh/blog/braintree-failed-subscription-payments/ Braintree's recurring billing is deliberately lean. It charges subscriptions, retries failed charges on a schedule you choose, and tells you what happened through webhooks. Everything else, including emails to customers, a page to update the card and what your product does while a subscription is past due, is up to you. This guide covers what Braintree does natively, the settings that matter, and the pieces you need to add. It ends with a short section on disputes, since a failed or contested renewal often turns into one. It sticks to Braintree's own documentation: [Recurring billing advanced settings](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings), the [Recurring billing overview](https://developer.paypal.com/braintree/docs/guides/recurring-billing/overview), [Statuses](https://developer.paypal.com/braintree/docs/reference/general/statuses), [Subscription: Retry Charge](https://developer.paypal.com/braintree/docs/reference/request/subscription/retry-charge/node), [Subscription webhooks](https://developer.paypal.com/braintree/docs/reference/general/webhooks/subscription/node), [Account Updater](https://developer.paypal.com/braintree/articles/guides/account-updater) and [Managing disputes via the API](https://developer.paypal.com/braintree/docs/guides/disputes/managing) (all accessed November 2026). ## What happens when a subscription charge fails When Braintree bills a subscription and the transaction is processor declined or gateway rejected, the subscription moves to **Past Due**. From there, according to the [advanced settings guide](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings): - Braintree retries automatically if retries are enabled in the Control Panel. - A successful retry returns the subscription to **Active**, as long as it has not passed its final billing date. - Automatic retries do not change the start and end dates of the current billing period. - Some decline codes, such as an expired or stolen card, are never retried because they suggest the transaction is unlikely ever to succeed. The subscription object helps you track this: `daysPastDue` gives the number of days the subscription has been past due, and `failureCount` counts consecutive failed charge attempts. ### Subscription statuses at a glance | Status | Meaning (from Braintree's [statuses reference](https://developer.paypal.com/braintree/docs/reference/general/statuses)) | |---|---| | Active | Billing normally | | Past Due | A charge failed; retries may be pending | | Canceled | No further billing will occur | | Expired | The subscription reached its set number of billing cycles | Expired is not a failure state; a subscription that ends for non-payment shows up as Canceled or stays Past Due, depending on your settings. ## The retry settings Retries are configured in the Control Panel under **Account Settings, Recurring Billing, Options**, not through the API. The settings documented by Braintree: - **Whether to retry** failed transactions automatically. - **Days before the first retry**, between 1 and 10 days. - **What to do after the retries fail:** cancel the subscription, continue retrying, or leave it past due. The last setting deserves a deliberate choice: | Option | What Braintree does | When it makes sense | |---|---|---| | Cancel | Ends the subscription | You want a clear end state and will win customers back separately | | Continue retrying | Retries once per billing cycle, on the usual billing date | Low-value plans where customers often top up later | | Leave past due | Balance keeps accruing each cycle, no further retries | You will collect yourself and need the history | With "leave past due", the balance grows every cycle without any new attempt, so someone has to contact the customer. With "continue retrying", there is only one attempt per cycle, so it is not a substitute for prompt retries after the first failure. ### Manual retries You can retry a past due subscription yourself with [Subscription: Retry Charge](https://developer.paypal.com/braintree/docs/reference/request/subscription/retry-charge/node), from the API or the Control Panel. Pass `true` to submit the transaction for settlement automatically if the retry succeeds. A successful manual retry brings the subscription back to Active; a failed manual retry does not count as one of the automatic attempts. This is what you call right after a customer updates their card, rather than waiting for the next scheduled retry. ## Account Updater [Account Updater](https://developer.paypal.com/braintree/articles/guides/account-updater) requests updated details for vaulted cards that have expired or been replaced, which prevents some failures before they happen. Per Braintree's docs: - Updates depend on the issuing bank participating; prepaid cards and cards used through Apple Pay or Google Pay are not supported. - After the initial batch, requests go out on a rolling basis, including when a recurring payment is due within two weeks, and after some declines. - You can review updates in the Control Panel, in a report, or through a daily webhook. One important detail: adding a **new** payment method to a customer's vault does not move existing subscriptions to it. If a customer gives you a new card, update the subscription's payment method token, then retry the charge. ## Webhooks for subscriptions Braintree sends these [subscription webhook](https://developer.paypal.com/braintree/docs/reference/general/webhooks/subscription/node) kinds: | Kind | When it fires | What to do | |---|---|---| | `subscription_charged_unsuccessfully` | An existing subscription fails to produce a successful charge (not on manual retries, not on the initial charge) | Log the decline, start customer messaging | | `subscription_went_past_due` | The subscription moves from Active to Past Due (once per cycle) | Show an in-app banner, send the first email | | `subscription_charged_successfully` | A charge succeeds | Stop messaging, clear the banner | | `subscription_went_active` | The subscription becomes Active | Restore access | | `subscription_canceled` | The subscription is canceled | Remove access, store the cancel date | | `subscription_expired` | The subscription reached its last cycle | End access as planned | Braintree notes that the cancellation date is not returned in subscription search results, so if you need it, store it when `subscription_canceled` arrives. ## What you need to add yourself Braintree documents some [email notifications for recurring billing](https://developer.paypal.com/braintree/articles/guides/recurring-billing/email-notifications); check what they cover for your account. A complete recovery process usually needs more than that: 1. **A first email on `subscription_went_past_due`**, sent the same day, with one link to update the card. Do not quote the raw decline reason. 2. **A card update page** built with Braintree's client-side integration, so card data goes straight to Braintree and never touches your servers. On success, update the subscription's payment method and call Retry Charge. 3. **Reminders timed around the retries**, for example a day after each scheduled retry fails. 4. **A final notice** before the subscription is canceled, with the date. 5. **An in-app banner** while the subscription is past due. 6. **Separate handling for hard declines.** If the card is expired or reported stolen, Braintree will not retry, so the email is the only path to recovery: send it immediately. ## Braintree disputes Disputes are the other way subscription revenue leaks, and Braintree provides a full API for them, described in [Managing disputes via the API](https://developer.paypal.com/braintree/docs/guides/disputes/managing): - **Webhooks** of kind `dispute_opened`, `dispute_won`, `dispute_lost`, `dispute_accepted`, `dispute_expired` and others tell you when a case opens or changes status. - **Text evidence** (for example a refund or tracking number) is added with Dispute: Add Text Evidence. - **File evidence** is uploaded with a Document Upload request, then attached with Dispute: Add File Evidence. Braintree's docs give a 4 MB limit per file and 5 MB per dispute by default. - **Finalize** sends your response and evidence to the cardholder's bank. Evidence can only be added while the dispute is open. - **Reply-by date:** each dispute has one. If you miss it, you lose the right to contest and the dispute becomes expired. - **Accepting** a dispute means you do not contest it and the funds go back to the customer. For a subscription business, the strongest evidence is usually the history: when the customer signed up, what they used, which reminders they received and whether they ever tried to cancel. Gather it before the deadline gets close. ## Doing this with NoChurn Braintree keeps card processing, your merchant account and its own subscription retries; NoChurn works next to them. It connects with your Braintree merchant ID and API keys, follows Braintree webhooks, and adds AI-written recovery emails that you review before they go out, with a hosted page to update the payment method. For disputes, NoChurn gathers evidence automatically (cancel flow answers, emails sent, usage, support conversations) and drafts a reply with AI, which is sent to Braintree only after you review it. It also adds cancel flows with offers and a one-click cancel that is always visible, win-back emails at day 30, 60 and 90, and a churn score from 0 to 100. See [NoChurn + Braintree](/integrations/braintree/). --- # How to win back canceled subscribers on Braintree Source: https://www.nochurn.sh/blog/braintree-win-back/ A cancelled subscriber on Braintree is still in your vault: customer record, payment methods, transaction history. That makes win-back easier than finding a new customer. But Braintree does not run win-back campaigns, and it has one rule that shapes everything: a cancelled subscription cannot be reactivated. Every returning customer starts a new subscription. This guide covers how to track cancellations on Braintree, how to restart a subscriber cleanly, and a campaign structure you can run. It sticks to Braintree's own documentation: [Subscription: Cancel](https://developer.paypal.com/braintree/docs/reference/request/subscription/cancel/ruby), [Subscription: Create](https://developer.paypal.com/braintree/docs/reference/request/subscription/create/ruby), [Plans](https://developer.paypal.com/braintree/articles/guides/recurring-billing/plans), [Statuses](https://developer.paypal.com/braintree/docs/reference/general/statuses), [Subscription webhooks](https://developer.paypal.com/braintree/docs/reference/general/webhooks/subscription/node), [Recurring billing advanced settings](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings) and [Account Updater](https://developer.paypal.com/braintree/articles/guides/account-updater) (all accessed November 2026). ## Step 1: capture every cancellation Win-back timing depends on the date a customer left and why. Braintree gives you the event but not a stored date: - The `subscription_canceled` [webhook](https://developer.paypal.com/braintree/docs/reference/general/webhooks/subscription/node) fires when a subscription is cancelled. - Braintree notes that the cancellation date is **not included in subscription search results**, and suggests storing it from that webhook. So the first job is a webhook handler that writes the subscription ID, customer ID, plan, price and cancellation date to your own database. Without it, you cannot tell a customer who left last week from one who left last year, and you cannot build cohorts later. Also listen to `subscription_expired`, which fires when a subscription reaches its set number of billing cycles. Depending on how you handle end-of-term cancellations, some of your churn may arrive as expirations rather than cancellations. ## Step 2: separate voluntary from failed-payment churn Braintree cancels subscriptions for two very different reasons: - **The customer asked,** through your cancel flow or support. - **Payments failed** and your [retry settings](https://developer.paypal.com/braintree/articles/guides/recurring-billing/recurring-advanced-settings) end with "cancel the subscription" after the last retry. The webhook looks the same. Mark the source when you cancel (your cancel flow knows), and for system cancellations, check whether the subscription was Past Due just before. The two groups get different messages: a voluntary churner needs a reason to return, a failed-payment churner just needs an easy way to restart with a working card. ## Step 3: know the reason Braintree does not record why a customer cancelled. Capture the reason in your cancel flow and store it with the subscription ID (see [how to add a cancel flow to Braintree subscriptions](/blog/braintree-cancel-flow/)). The reason decides the content and the offer of each win-back email. ## Step 4: restarting a subscriber on Braintree Braintree's [cancel reference](https://developer.paypal.com/braintree/docs/reference/request/subscription/cancel/ruby) is explicit: a cancelled subscription cannot be edited or reactivated, so you create a new one. In practice: 1. **Find the customer** in the vault by your stored customer ID. 2. **Check the payment method.** If the old card is still valid, the customer may only need to confirm. If it has expired, ask for a new one first. [Account Updater](https://developer.paypal.com/braintree/articles/guides/account-updater), where enabled, may already have refreshed it. 3. **Create the subscription** with [Subscription: Create](https://developer.paypal.com/braintree/docs/reference/request/subscription/create/ruby), from a plan and the payment method token. Subscriptions always start from a [plan](https://developer.paypal.com/braintree/articles/guides/recurring-billing/plans). 4. **Apply the return offer,** if any, as a discount on the new subscription. Discount details are managed in the Control Panel, so create your win-back discount there in advance and apply it by ID. 5. **Confirm** by email, with the price, any discount and when it ends. Note from Braintree's plan docs: changes to a plan apply to new subscriptions only. If you raised prices since the customer left, their new subscription gets the new price unless you set the price or a discount explicitly. Decide whether returning customers get their old price. Always ask for explicit consent before charging a stored card for a new subscription. The "come back" link should open a page that shows the plan and price and asks the customer to confirm, not start billing on a click in an email. ### What the return page should show The page behind the "come back" link does most of the work, so keep it short and specific to the customer: - the plan they had, and the plan you suggest if their reason was price; - the price they will pay, with any discount and the date it ends; - the card on file (brand and last four digits only) with a clear option to use a different one; - one confirmation button, and a plain sentence on when the first charge happens. If the customer picks a new card, save it first, then create the subscription on that new payment method. A customer who has to log in, find billing settings and start again from a pricing page is far less likely to finish. ## Step 5: choose the offer by reason | Reason given | Message | Offer | |---|---|---| | Too expensive | A lower plan, or a limited discount | Discount for the first months, or downgrade | | Not using it enough | What others use it for, what changed | Usually none | | Missing feature | It shipped (only if true) | None needed | | Switched to another tool | What improved since they left | Optional discount | | Payment failed | Restart in one click with a new card | None | | Closed business, no need | Nothing | Do not email | Keep win-back discounts time-limited and separate from your sales discounts, so you can measure them. ## Step 6: timing A reason-based sequence spaced over three months works for most subscription businesses: 1. **Day 30:** a short, personal note tied to the reason. 2. **Day 60:** what changed since they left. 3. **Day 90:** the offer, if any, with a clear end date. Failed-payment churners are the exception: contact them within days, while they still expect the service. Stop the sequence as soon as a new subscription is created for the customer, and suppress it for anyone who opted out. Copy ideas in [win-back email examples](/blog/win-back-email-examples/). ## Step 7: measure For each cancel reason and each email: - the share of churned customers who started a new subscription within 120 days; - the revenue of those subscriptions, net of discounts; - how many are still active three months later. Because Braintree gives returning customers a new subscription ID, link old and new subscriptions through the customer ID in your own data. Otherwise a returning customer looks like a new one, and your win-back results disappear into new sales. ## Common mistakes - **Not storing the cancellation date.** It is not in search results; without the webhook, it is gone. - **Emailing failed-payment churners as if they chose to leave.** - **Charging a stored card without confirmation.** - **Ignoring price changes,** so a returning customer is surprised by the new price. - **Mixing win-back revenue into new customer revenue.** ## Doing this with NoChurn Braintree keeps the vault, the new subscription and the charge. NoChurn follows Braintree webhooks, stores each cancellation with the reason from its cancel flow, and sends win-back emails at day 30, 60 and 90 written from that reason, with a link to come back. Failed-payment churn is handled separately with AI-written recovery emails you review and a hosted page to update the payment method, and each customer has a churn score from 0 to 100. See [NoChurn + Braintree](/integrations/braintree/). --- # What a chargeback really costs: fees, lost revenue and ratios Source: https://www.nochurn.sh/blog/chargeback-cost-fees/ A chargeback looks like a refund with a fee on top. For a subscription business it is usually more: the payment, the fee, the time to answer, the customer who will not renew, and a tick on a ratio the card networks watch. Knowing the full cost changes two decisions: how much to invest in prevention, and which disputes are worth contesting. This guide breaks the cost into its parts, with the published fees from processors' own pages. Sources: Stripe's [pricing](https://stripe.com/pricing), [dispute fees FAQ](https://support.stripe.com/questions/dispute-fees-faq), [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) and [accepting disputes FAQ](https://support.stripe.com/questions/accepting-disputes-faq); Braintree's [pricing](https://www.paypal.com/us/enterprise/paypal-braintree-fees) and [fee documentation](https://developer.paypal.com/braintree/articles/wells-flat/pricing-fees); Adyen's [manage disputes](https://docs.adyen.com/risk-management/manage-disputes) and [Visa chargebacks](https://docs.adyen.com/risk-management/chargeback-guidelines/visa-chargebacks) pages; and the network program documents cited below (all accessed November 2026). Fees vary by country and contract; treat the figures here as examples and check your own. ## The five parts of the cost | Part | Paid when | Recovered if you win? | |---|---|---| | 1. The disputed amount | Debited when the chargeback opens | Yes | | 2. Processor fees | At opening, and sometimes when you contest | Partly | | 3. Team time | Every case you answer | No | | 4. Lost future revenue | When the customer leaves | Rarely | | 5. Ratio and program risk | Every dispute, won or lost | No | ## 1. The disputed amount When a chargeback opens, the processor debits the amount from your balance. If you win, it comes back; if you lose or accept, it does not. Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says the issuer typically takes 60 to 75 days to decide after you submit, so even a won case ties up cash for two to three months. Processing fees on the original payment are a separate matter. Stripe's pricing page says the original processing fees are not returned, even if you win. ## 2. Processor fees ### Stripe From Stripe's US [pricing page](https://stripe.com/pricing) and [dispute fees FAQ](https://support.stripe.com/questions/dispute-fees-faq): | Fee | US amount | Returned if you win? | |---|---|---| | Dispute fee (when a dispute is opened) | $15 | No, unless your contract says otherwise | | Countered fee (if you contest) | $15 | Yes | Accepting a dispute does not avoid the dispute fee. Amounts differ by country; check the pricing page for yours. For Visa and Mastercard **compliance** disputes, which are rare for subscriptions, Stripe collects an extra USD 500 network fee if you contest, refunded if you win. ### Braintree PayPal's [Braintree pricing page](https://www.paypal.com/us/enterprise/paypal-braintree-fees) lists a $15 chargeback fee for standard US merchants. Braintree's [fee documentation](https://developer.paypal.com/braintree/articles/wells-flat/pricing-fees) describes it as non-refundable, even if you win, and says retrievals do not carry it. ### Adyen and other acquirers Adyen's [manage disputes](https://docs.adyen.com/risk-management/manage-disputes) page says a chargeback fee applies to each booked chargeback; the amount is in your contract. Adyen's network pages also mention scheme fees if a case escalates, for example a USD 600 filing fee under Visa's arbitration process. ### Pre-dispute tools Network services that resolve disputes before they are filed, such as Visa Rapid Dispute Resolution or Mastercard's Ethoca Alerts, charge a fee per case. Stripe's [dispute prevention](https://docs.stripe.com/disputes/get-started/prevention) docs describe them. They replace the dispute fee and keep the case out of Visa's VAMP count, but the merchant still refunds the payment. Visa also announced, in its [merchant business news digest](https://usa.visa.com/support/merchant/library/visa-merchant-business-news-digest.html), a fee associated with successful Compelling Evidence 3.0 qualifications from 17 April 2026. Ask your processor whether and how it is passed on. ## 3. Team time Someone has to read the dispute, find the evidence, write the response and check it. For a subscription business, that means pulling usage logs, cancellation records, emails and support threads from several systems. The time per case depends on how scattered your data is. Put a number on it for your own team: hours per case times the cost of an hour. Compare that with the amount at stake. For a $9 monthly charge, a manual response almost never pays for itself; for a $1,200 annual plan, it usually does. See [refund or fight](/blog/refund-or-fight-chargeback/). ## 4. Lost future revenue This is the cost that is specific to subscriptions, and the one most often left out. A customer who files a chargeback often does not keep paying. You should also stop renewals on a card that was reported as stolen. Either way, the future renewals are gone. A simple way to estimate it for your business: **Lost future revenue = monthly price × expected remaining months for a customer like this one** Use your own retention data for "expected remaining months". For a customer on a $49 monthly plan whom you would otherwise expect to keep for another ten months, that is $490: ten times the disputed charge. This is also why prevention beats winning. A customer who found the cancel button and left is gone either way; a customer who did not recognize a charge, got a reminder and stayed is not. ## 5. Ratios and monitoring programs Every dispute counts toward your network ratios, whether you win, lose or accept. Stripe's [accepting disputes FAQ](https://support.stripe.com/questions/accepting-disputes-faq) says an accepted dispute counts like any other, and its [measuring disputes](https://docs.stripe.com/disputes/measuring) page says won disputes count too. Cross the thresholds and costs change in kind: - **Visa VAMP:** from 1 April 2026, the excessive merchant threshold is 1.5% with at least 1,500 fraud reports and disputes per month in most regions, per Visa's [fact sheet](https://corporate.visa.com/content/dam/VCOM/corporate/visa-perspectives/security-and-trust/documents/visa-acquirer-monitoring-program-fact-sheet-2025.pdf). Identified merchants face per-case fees through their acquirer. - **Mastercard ECP:** from 100 chargebacks and a 1.5% ratio in a month, with assessments that escalate the longer a merchant stays in, per Braintree's [Excessive Chargeback Program](https://developer.paypal.com/braintree/articles/risk-and-security/card-brand-monitoring-programs/mastercard-programs/excessive-chargeback-program) page. - **Your processor's own limits,** which may be stricter: reserves, delayed payouts, or in the worst case a closed account. Details and dates are in [chargeback ratio thresholds and monitoring programs](/blog/chargeback-ratio-monitoring-programs/). ## A worked example A hypothetical SaaS on Stripe in the US, $49 monthly plan, one disputed renewal. The figures below use Stripe's published US fees and the assumptions stated; replace them with yours. | Item | Accept | Contest and lose | Contest and win | |---|---|---|---| | Disputed amount | −$49 | −$49 | $0 | | Dispute fee | −$15 | −$15 | −$15 | | Countered fee | $0 | −$15 | $0 (returned) | | Team time (assumed 30 min at $40/hour) | $0 | −$20 | −$20 | | Future renewals lost (assumed 10 months) | −$490 | −$490 | Likely lost too | | Counts toward ratios | Yes | Yes | Yes | Two things come out of a table like this. First, the fees are small next to the value of the customer. Second, winning recovers the $49, but not necessarily the customer. ## Where the money is Given that breakdown, the order of priorities for most subscription businesses is: 1. **Prevent disputes** with a recognizable [descriptor](/blog/billing-descriptor-chargebacks/), renewal reminders, an easy cancel and fast refunds. See [how to prevent chargebacks on subscriptions](/blog/prevent-subscription-chargebacks/). 2. **Refund early** when a customer clearly did not want a charge, before it becomes a dispute. 3. **Make contesting cheap** by having evidence assembled automatically, so the decision to fight depends on the case, not the effort. See the [evidence checklist](/blog/chargeback-evidence-checklist-saas/). 4. **Watch your ratios** monthly, per network. ## Doing this with NoChurn NoChurn lowers the time part of the cost: for Stripe and Braintree disputes, it gathers evidence automatically (cancel flow answers, emails sent, usage you send by API, help desk conversations read only) and drafts the reply with AI, sent only after a person on your team has reviewed it. On Stripe, early fraud warnings come with a one-click refund. Cancel flows with a one-click cancel and win-back emails at day 30, 60 and 90 work on the other parts. NoChurn's price depends only on MRR, from free up to $300 MRR to $399/month up to $500k, and it never takes a share of recovered revenue. See [pricing](/pricing/). --- # Chargeback evidence checklist for SaaS Source: https://www.nochurn.sh/blog/chargeback-evidence-checklist-saas/ The issuing bank decides a chargeback on what you send, and nothing else. It does not log in to your app, read your help center or call your support line. For a SaaS business, that means the case is won or lost on records you made months earlier: what the customer agreed to, when they used the product, what they told you. This is a working checklist: what to record all the time, what to send for each kind of dispute, and how to package it so a reviewer can follow it. It is based on processor documentation: Stripe's [evidence best practices](https://docs.stripe.com/disputes/best-practices), [reason codes and defense requirements](https://docs.stripe.com/disputes/reason-codes-defense-requirements) and [Dispute object](https://docs.stripe.com/api/disputes/object); Braintree's [evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/ruby/); Adyen's [dispute reason codes and defense requirements](https://docs.adyen.com/risk-management/understanding-disputes/dispute-reason-codes); and Visa's [Dispute Management Guidelines for Merchants](https://usa.visa.com/dam/VCOM/global/support-legal/documents/merchants-dispute-management-guidelines.pdf) (all accessed November 2026). ## Part 1: what to record all the time You cannot assemble evidence after the fact if it was never logged. These records should exist for every customer, from day one. ### Account and agreement - [ ] Account creation date, customer account ID and email. - [ ] The exact terms, pricing and cancellation policy shown at signup, versioned, with the version the customer accepted. - [ ] Timestamp, IP address and device of the acceptance (checkbox, button click). - [ ] For trials: what was shown about when the first charge happens and for how much. ### Payments - [ ] Every invoice and charge: date, amount, plan, billing period, card brand and last four digits. - [ ] Receipts and renewal reminders sent, with timestamps. - [ ] Refunds and credits, with dates and amounts. - [ ] The statement descriptor used on each charge. ### Usage - [ ] Logins with timestamp, IP address and device or user agent. - [ ] Key product actions with timestamps: projects created, files uploaded, API calls, seats added, whatever shows real use. - [ ] Which user in the account did what (for team plans). ### Cancellation - [ ] Every cancellation attempt, including flows started and abandoned, with timestamps. - [ ] Answers given during the cancel flow. - [ ] The confirmation email sent after cancellation. - [ ] Plan changes, pauses and offers accepted. ### Communication - [ ] All emails sent to the customer (transactional and marketing), with delivery status. - [ ] All support conversations, with timestamps. ### Retention Keep these at least as long as a dispute can arrive. Stripe says networks typically give cardholders around 120 days from the payment, sometimes more; and [Visa Compelling Evidence 3.0](/blog/visa-compelling-evidence-3/) looks at transactions up to 365 days back. A retention of 18 months or more covers both. Check that this is compatible with your privacy policy. ## Part 2: what to send, by dispute type Read the reason code first; it tells you what the bank will look for. Mapping and codes are in [reason codes for subscriptions](/blog/chargeback-reason-codes-subscriptions/). ### Fraud: "I did not authorize this" (Visa 10.4, Mastercard 4837, 4863) - [ ] Customer account ID, email and signup date. - [ ] Prior undisputed payments on the same card, with dates and amounts. - [ ] IP address and device for sessions around each of those payments and the disputed one. - [ ] Usage in the billed period: logins and key actions with timestamps. - [ ] 3D Secure authentication result, if any (Stripe adds this for you). - [ ] Any message from the cardholder that shows they know the service. - [ ] If Visa 10.4: check CE 3.0 eligibility (two prior undisputed transactions 120 to 365 days old, matching identifiers). ### Cancelled recurring: "I cancelled" (Visa 13.2, Mastercard 4841) - [ ] The cancellation policy as shown at signup, with the relevant section highlighted. Stripe suggests uploading the relevant part rather than your whole terms. - [ ] Proof the customer accepted it (timestamp, IP). - [ ] Your cancellation records: no request before the charge, or the exact time of the request if it came after. - [ ] Usage after the date the customer says they cancelled. Visa's guidelines, for disputes processed from 19 October 2024, accept proof that the cardholder used the service after withdrawing permission. - [ ] Renewal reminder or receipt sent before or after the charge. - [ ] Any refund already issued. If your records show the customer did cancel before the charge, do not contest. Accept and fix the bug. ### Not received (Visa 13.1, Mastercard 4855) - [ ] Proof the account was provisioned and accessible during the billed period. - [ ] Logins and usage during that period. - [ ] Your terms on service delivery. - [ ] Any outage or access restriction in that period, and how you handled it (if access was really blocked, consider accepting). ### Not as described (Visa 13.3, Mastercard 4853) - [ ] The product or plan description shown at purchase. - [ ] Usage showing the features were available and used. - [ ] Support conversations about the issue, and your responses. - [ ] Refund policy shown at purchase. ### Credit not processed (Visa 13.6, Mastercard 4860) - [ ] The refund record, if issued: date, amount, reference. - [ ] If no refund was due: the refund policy accepted at signup and the conversation where it was discussed. ### Duplicate (Visa 12.6, Mastercard 4834) - [ ] Both invoices, showing they cover different periods, seats or products. - [ ] Or, if one was a mistake, the refund. ## Part 3: how to package it Processors have strict limits, and reviewers read many cases. A clear packet is part of the evidence. ### Respect the format Stripe documents these constraints on its [best practices](https://docs.stripe.com/disputes/best-practices) and [responding](https://docs.stripe.com/disputes/responding) pages: | Constraint | Stripe | |---|---| | Submissions | One. You cannot add or edit after submitting | | Files | One file per evidence type; combine several documents into one multi-page file | | Size | 4.5 MB combined; Mastercard evidence limited to 19 pages combined | | Text | 150,000 characters across all text fields | | Links | Banks do not review external content; do not rely on URLs | Braintree organizes evidence by category and is equally strict about format; its [evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/ruby/) page lists what each category accepts. Adyen lists the defense documents per reason code. Check your processor before building templates. ### Write a cover note Start with a short summary, in plain language: 1. Who the customer is and when they signed up. 2. What they bought, at what price, on what billing interval. 3. What happened: the charge, the claim, and why the claim is wrong. 4. A list of attached documents, each tied to one point. Example: "Customer acc_8812 signed up on 3 February 2025 for the Team plan, monthly, and accepted the terms (Exhibit A, with timestamp and IP). The disputed charge of 7 March 2026 is the 14th renewal on the same card; the previous 13 were not disputed (Exhibit B). Users on the account logged in 41 times between 7 March and 2 April 2026 (Exhibit C). No cancellation request was received (Exhibit D)." ### Make logs readable - Export logs as a table: date, time with time zone, user, IP, action. - Filter to the relevant period. Thousands of rows hide the point. - Highlight the rows that matter. - Use the customer's name or email as shown on the card account where possible, so the reviewer can connect them. ### Do not - Send internal jargon or database dumps. - Send screenshots of an admin panel without explanation. - Argue about the customer's character. Stick to facts and timestamps. - Miss the deadline. The date on the dispute is the one that counts; Stripe says you usually have 7 to 21 days. ## Part 4: review before sending - [ ] Reason code read and evidence matches it. - [ ] Cover note explains the case in under a page. - [ ] Every claim in the note has an exhibit. - [ ] Personal data limited to what the case needs. - [ ] File sizes and page counts within limits. - [ ] A second person has read it. - [ ] Deadline checked. ## Doing this with NoChurn NoChurn gathers this evidence automatically for each Stripe and Braintree dispute: cancel flow answers with timestamps, the emails NoChurn sent, usage and custom data you send by API, and conversations from Intercom, Zendesk, HubSpot, Help Scout, Gorgias or Crisp (read only). It drafts the cover note and response with AI, and nothing is sent until a person on your team has reviewed it. The bank still decides the outcome. See [chargebacks](/#disputes) and [custom data](/#insights). --- # Chargeback ratio thresholds and card network monitoring programs Source: https://www.nochurn.sh/blog/chargeback-ratio-monitoring-programs/ Card networks watch how many disputes and fraud reports each merchant generates. Cross a threshold and you enter a monitoring program: fees, remediation plans and, if it lasts, the risk of losing the ability to accept that card. For a subscription business, where one confusing renewal can trigger dozens of disputes in a week, these thresholds are worth knowing precisely. The programs changed significantly in 2025 and 2026, and many articles online still describe the old ones. This guide summarizes what Visa, Mastercard and the major processors document **as of November 4, 2026**. Sources: Visa's [VAMP fact sheet](https://corporate.visa.com/content/dam/VCOM/corporate/visa-perspectives/security-and-trust/documents/visa-acquirer-monitoring-program-fact-sheet-2025.pdf), Visa's articles [introducing VAMP](https://corporate.visa.com/en/sites/visa-perspectives/security-trust/introducing-visa-acquirer-monitoring-program.html) and [evolving VAMP](https://corporate.visa.com/en/sites/visa-perspectives/security-trust/visa-vamp-program-update-fraud-disputes.html), Mastercard's [Security Rules and Procedures, Merchant Edition](https://www.mastercard.com/content/dam/mccom/shared/business/support/rules-pdfs/SPME-Manual.pdf) (4 August 2026), Stripe's [monitoring programs page](https://docs.stripe.com/disputes/monitoring-programs) and [FAQ](https://support.stripe.com/questions/monitoring-program-faq), Braintree's pages on [VAMP](https://developer.paypal.com/braintree/articles/risk-and-security/card-brand-monitoring-programs/visa-programs/visa-dispute-monitoring-program), the [Excessive Chargeback Program](https://developer.paypal.com/braintree/articles/risk-and-security/card-brand-monitoring-programs/mastercard-programs/excessive-chargeback-program) and the [Excessive Fraud Merchant Program](https://developer.paypal.com/braintree/articles/risk-and-security/card-brand-monitoring-programs/mastercard-programs/excessive-fraud-merchant-program), and Adyen's [monitor risk performance](https://docs.adyen.com/risk-management/dispute-and-fraud-monitoring) page (all accessed November 2026). Your acquirer's contract can set stricter limits. ## Visa: the Acquirer Monitoring Program (VAMP) ### Timeline | Date | What changed | |---|---| | 1 April 2025 | VAMP relaunched as one global program, replacing the Visa Dispute Monitoring Program (VDMP) and Visa Fraud Monitoring Program (VFMP) | | 1 June 2025 | Revised thresholds and methodology took effect | | 30 September 2025 | Advisory period (no fines) ended, per Visa | | 1 April 2026 | Excessive merchant threshold lowered from 2.2% to 1.5% in Asia Pacific, Canada, Europe and the US | If you read about "VDMP" or "VFMP" thresholds, that material predates April 2025. ### The VAMP ratio Visa's fact sheet describes a single, count-based ratio covering fraud and disputes on card-not-present transactions. Stripe's FAQ puts it as: the month's VAMP count (fraud reports plus disputes) divided by the total settled transactions in the same month. Two details matter for subscriptions: - **Fraud reports count even without a dispute.** Stripe's monitoring page says early fraud warnings are considered fraudulent regardless of their outcome and are included in VAMP. - **Some resolved disputes are excluded.** Stripe says disputes resolved through pre-dispute products, such as its dispute prevention tools (Visa Rapid Dispute Resolution, for example), are excluded from the VAMP count. ### Merchant thresholds | Region | Excessive merchant ratio | Minimum monthly count | |---|---|---| | Asia Pacific, Canada, Europe, US | 1.5% (2.2% until 31 March 2026) | 1,500 | | Latin America and Caribbean | 1.5% | 1,500 | | CEMEA | 2.2% | 150, and at least USD 75,000 | Both the ratio and the count must be met. A small merchant with 0.5% of transactions disputed but only 40 disputes a month is not identified at merchant level under these numbers. ### Acquirer thresholds This is the part many merchants miss. VAMP also measures each **acquirer's** whole portfolio: Above Standard from 0.5% and Excessive from 0.7%. An acquirer near those levels has every reason to push its merchants well below 1.5%. In practice, your processor may contact you long before you reach Visa's merchant threshold. Stripe also notes that if you use several processors that share an acquirer, Visa aggregates the data, so you could be identified even if your ratio on one processor looks fine. ### Enumeration VAMP also targets card testing. Visa's fact sheet sets an enumeration ratio of 20% (2,000 basis points) and a count of 300,000 enumerated authorization attempts. Subscription signup forms are a common target for card testing, so protect them with fraud rules and rate limits. ### Fees and exit Identified merchants face fees, assessed through the acquirer; Braintree's [fall 2025 release guide](https://developer.paypal.com/braintree/articles/risk-and-security/compliance/network-updates/2025/f-2025-all) lists new VAMP fees from 1 October 2025. What is passed on to you depends on your processor's contract. Stripe's FAQ says merchants outside CEMEA exit when either the VAMP count or the VAMP ratio falls below the threshold. Stripe estimates VAMP data daily in its Dashboard, while Visa's official figures arrive with about a month of delay. ## Mastercard: ECP and EFM Mastercard runs two separate programs, defined in section 8 of its Security Rules and Procedures, Merchant Edition. ### Excessive Chargeback Program (ECP) The ratio is the number of chargebacks in a calendar month divided by the number of Mastercard sales transactions in the **previous** month. Both the count and the ratio must be met. | Level | Chargebacks per month | Ratio | |---|---|---| | Excessive Chargeback Merchant (ECM) | 100 to 299 | 1.5% to 2.99% | | High Excessive Chargeback Merchant (HECM) | 300 or more | 3.0% or more | Braintree notes that since April 2020, Mastercard no longer identifies merchants at the older Chargeback Monitored Merchant level (100 chargebacks and 1.0%); some articles still quote it. Assessments start in the second month and escalate the longer a merchant stays in the program. To exit, a merchant must stay below the ECM thresholds for three consecutive months. The previous-month denominator matters when billing is lumpy. Disputes can arrive weeks or months after the charge (cardholders typically have about 120 days), so a large annual renewal cohort in January can produce chargebacks in March, which are divided by February's smaller transaction count. Plan for that spike before a big renewal date. ### Excessive Fraud Merchant program (EFM) EFM looks at fraud chargebacks (reason codes 4837 and 4863) on card-not-present transactions. Per Braintree's and Stripe's documentation, a merchant is identified when, in a month, all of these are true: - at least 1,000 Mastercard e-commerce sales in the previous month; - at least USD 50,000 in fraud chargebacks; - a fraud chargeback ratio of 0.5% or more; - 3D Secure used on less than 50% of transactions in regulated countries, or less than 10% elsewhere. Australia has lower amount and ratio thresholds. If a merchant breaches both EFM and ECP in the same month, only the EFM assessments apply. Exit also requires three consecutive months below the thresholds. The 3D Secure condition is a useful lever: a merchant that authenticates enough of its transactions is not identified under EFM, whatever its fraud level. ## Side by side | | Visa VAMP | Mastercard ECP | Mastercard EFM | |---|---|---|---| | Counts | Fraud reports and disputes | Chargebacks | Fraud chargebacks | | Denominator | Settled CNP transactions, same month | Sales transactions, previous month | Sales transactions, previous month | | Main merchant threshold | 1.5% and 1,500 (most regions) | 1.5% and 100 | 0.5% and USD 50,000 | | Won disputes count? | Yes | Yes | Yes | ## What counts, and what does not - **Won disputes still count.** Stripe's [measuring disputes](https://docs.stripe.com/disputes/measuring) page says all disputes, won or lost, count toward your dispute rate. Accepting a dispute counts too. - **Refunds before a dispute do not create one.** A customer who gets a refund has no reason to dispute. But a refund does not remove a fraud report that already exists. - **Inquiries** on networks that still use them are not chargebacks. The practical conclusion: you cannot win your way out of a monitoring program. Only prevention lowers the ratio. ## A monitoring routine for subscription businesses 1. **Compute your own ratios monthly,** per network, with the right denominator for each. Do not rely on a blended "dispute rate". 2. **Watch spikes after billing events:** annual renewal cohorts, price increases, trial conversions. 3. **Act on early fraud warnings** before they become disputes, keeping in mind they already count for Visa. See [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/). 4. **Fix the causes:** a clear [descriptor](/blog/billing-descriptor-chargebacks/), renewal reminders, easy cancel and fast refunds. See [preventing subscription chargebacks](/blog/prevent-subscription-chargebacks/). 5. **Ask your processor** what internal thresholds they apply. They are often stricter than the networks'. ## Doing this with NoChurn NoChurn shows every Stripe and Braintree dispute with its reason, so you can see which causes drive your ratio, and gathers evidence automatically for the ones you contest (cancel flow answers, emails sent, usage you send by API, help desk conversations read only). Replies are drafted with AI and sent only after human review. On Stripe, early fraud warnings come with a one-click refund. Cancel flows keep a one-click cancel visible, which removes one common source of "cancelled recurring" disputes. NoChurn does not calculate network monitoring status; your processor's dashboard is the reference. --- # Chargeback reason codes that hit subscription businesses most Source: https://www.nochurn.sh/blog/chargeback-reason-codes-subscriptions/ Every chargeback arrives with a reason code. It is the card network's label for what the cardholder claims, and it decides which evidence the issuer will look at. Answer a "cancelled recurring" dispute with fraud evidence, or the other way round, and you lose a case you could have won. Subscription businesses see a small set of codes again and again. This guide lists them, explains what each one means for recurring billing, and says what evidence fits. It relies on Visa's [Dispute Management Guidelines for Merchants](https://usa.visa.com/dam/VCOM/global/support-legal/documents/merchants-dispute-management-guidelines.pdf), the [Visa Core Rules](https://usa.visa.com/dam/VCOM/download/about-visa/visa-rules-public.pdf), Stripe's [dispute categories](https://docs.stripe.com/disputes/categories) and [reason codes](https://docs.stripe.com/disputes/reason-codes-defense-requirements) pages, Braintree's [chargeback reason codes](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/chargeback-reason-codes) and Adyen's [dispute reason codes](https://docs.adyen.com/risk-management/understanding-disputes/dispute-reason-codes) (all accessed November 2026). Rules change; the version in force on the transaction date is the one that applies. ## How reason codes are organized Visa groups its codes into four categories: **10 Fraud**, **11 Authorization**, **12 Processing errors** and **13 Consumer disputes**. Mastercard uses four-digit numbers (4837, 4841 and so on). Processors simplify both into their own categories. Stripe, for example, maps them to a `reason` field with values like `fraudulent`, `subscription_canceled` and `product_not_received`. One practical note from Braintree: its systems do not store decimals, so Visa 10.4 appears as `1040`. Check how your processor formats codes before building reports on them. ## The codes that matter most for subscriptions | Cardholder's claim | Visa | Mastercard | Stripe `reason` | |---|---|---|---| | "I did not make this payment" (card absent) | 10.4 | 4837 | `fraudulent` | | "I don't recognize this charge" | 10.4 in most cases | 4863 | `unrecognized` or `fraudulent` | | "I cancelled, but was charged again" | 13.2 | 4841 | `subscription_canceled` | | "I never received the service" | 13.1 | 4855 | `product_not_received` | | "It was not as described" | 13.3 | 4853 | `product_unacceptable` | | "I was promised a refund" | 13.6 | 4860 | `credit_not_processed` | | "I was charged twice" | 12.6 | 4834 | `duplicate` | Amex uses its own codes; the one subscription businesses meet most is C28, cancelled recurring billing, which Stripe and Braintree both map to the cancelled-subscription category. The rest of this article goes through the first four, which make up the bulk of subscription cases. ## Fraud: Visa 10.4, Mastercard 4837 and 4863 ### What the cardholder claims That they did not authorize or take part in the payment. Visa's guidelines describe 10.4 as a card-absent transaction the cardholder says they did not authorize. Mastercard separates "no cardholder authorization" (4837) from "cardholder does not recognize" (4863). ### Why subscriptions get them Many are not real fraud. A renewal the customer forgot, a descriptor they did not recognize, a family member using the card: all of these get reported as fraud because that is the first option the bank offers. See [friendly fraud in subscriptions](/blog/friendly-fraud-subscriptions/). ### Evidence that fits - **Prior undisputed payments** on the same card, by the same customer account. For Visa 10.4, this may qualify for [Compelling Evidence 3.0](/blog/visa-compelling-evidence-3/), which requires at least two prior undisputed transactions roughly 120 to 365 days old with matching identifiers such as IP address or device ID. - **Usage around the billing date:** logins, IP addresses, devices, key actions. - **Authentication:** if the payment went through 3D Secure, the liability may have shifted to the issuer. Stripe adds the authentication data to the evidence for you. - **Communication** from the cardholder that shows they know the service. ### When to accept If the account was created and paid in one go, never used, and several similar accounts appeared at the same time, it is probably real fraud. Accept, cancel the subscription and block the pattern. ## Cancelled recurring: Visa 13.2, Mastercard 4841 ### What the cardholder claims That they withdrew permission to be charged, or that the merchant was told the account was closed, and a recurring charge happened anyway. ### Why it matters so much This code is the purest subscription dispute. It is about your cancel process, not about fraud. Visa's guidelines state the merchant remedy plainly: if the cardholder withdrew permission and you did not issue a credit, accept the dispute. For disputes processed on or after 19 October 2024, Visa's guidelines also allow a remedy when the cardholder kept using the service: you can provide proof that the cardholder used the service after the date they withdrew permission and before the dispute processing date. Other remedies are proof that you already issued a credit, or a written withdrawal of the dispute from the cardholder. Visa's [free trial policy](https://usa.visa.com/dam/VCOM/global/support-legal/documents/subscription-merchants-visa-public.pdf) adds a nuance: if the claim is that the cardholder never agreed to a subscription at all (for example, after a trial they did not understand), the dispute may fall under 13.5 Misrepresentation rather than 13.2. ### Evidence that fits - The cancellation record with exact timestamps, or proof there was no cancellation request. - The cancellation policy shown to the customer at signup, and proof they accepted it. - Usage after the claimed cancellation date. - Any refund or credit already issued. ### The real fix If you lose 13.2 cases, the cancel path is probably hard to find or not honored. A visible cancel button and an immediate confirmation email remove most of them. Mastercard's [recurring billing standards](https://www.mastercard.us/content/dam/public/mastercardcom/na/global-site/documents/subscription_recurring-payments-and-negative-option-billing-merchants.pdf) require an online cancellation method for subscriptions. See [cancel flow best practices](/blog/cancel-flow-best-practices/). ## Not received: Visa 13.1, Mastercard 4855 ### What the cardholder claims That they paid for a service and did not get it. ### For digital subscriptions Delivery is access. Stripe's reason code page points to login records, usage timestamps and your terms. Show that the account was provisioned and available for the billed period, and ideally that it was used. Watch for a specific failure: an account that was charged while access was blocked, for example after a failed payment put the account in a restricted state. If access really was cut off, the cardholder is right. ## Credit not processed: Visa 13.6, Mastercard 4860 ### What the cardholder claims That you promised a refund, or accepted a cancellation with a refund, and the money never arrived. ### Evidence that fits - The refund record with date and amount, if you did refund. - Your refund policy as shown at purchase, if the customer was not entitled to one. - Support conversations where the refund was discussed. Many of these come from refunds that take a few days to appear on a statement. A clear refund confirmation email with the expected timeline prevents them. ## Duplicate processing: Visa 12.6, Mastercard 4834 For subscriptions, these usually come from a retry that succeeded twice, a plan change that charged twice in one period, or two subscriptions on the same account. Check your logs: if both charges are real (for example two seats, or a prorated upgrade), show the invoices. If one is a mistake, refund it. ## Using reason codes to prevent disputes Your reason code mix is a map of what to fix: | Most common code | Likely cause | First fix | |---|---|---| | Fraud (10.4, 4837, 4863) on long-time customers | Unrecognized descriptor, forgotten renewal | [Descriptor](/blog/billing-descriptor-chargebacks/), renewal reminders | | Fraud on new accounts | Real fraud or card testing | Fraud rules, 3D Secure | | Cancelled recurring (13.2, 4841) | Cancel process hidden or not honored | Visible cancel, confirmation email | | Credit not processed (13.6, 4860) | Refunds slow or unclear | Refund confirmation with timeline | | Not received (13.1, 4855) | Access issues, onboarding failures | Check provisioning | Track codes monthly. A change in the mix after a product change usually tells you which change caused it. For the full defense process, see [the chargeback evidence checklist for SaaS](/blog/chargeback-evidence-checklist-saas/). ## Doing this with NoChurn NoChurn reads each Stripe and Braintree dispute with its reason and deadline, and gathers the evidence that fits it automatically: cancel flow answers with timestamps, emails sent, usage you send by API and help desk conversations (read only). It drafts a reply with AI, and nothing is sent until a person on your team has reviewed it. Disputes on other providers are shown read only. See [chargebacks](/#disputes). --- # Chargeback, dispute, retrieval request, inquiry: what each one means Source: https://www.nochurn.sh/blog/chargeback-vs-dispute-vs-retrieval-request/ Payment people use "dispute", "chargeback", "retrieval", "inquiry" and "request for information" as if they were the same thing. They are not. Some of these stages move money and count against you with the card networks; others are a question from the bank that costs nothing if you answer it well. Knowing which one you are looking at decides how fast you need to act and what you should send. This guide defines each term, shows where it sits in the dispute cycle, and maps it to the names used by three processors: Stripe ([how disputes work](https://docs.stripe.com/disputes/how-disputes-work), [Dispute object](https://docs.stripe.com/api/disputes/object)), Adyen ([dispute flow](https://docs.adyen.com/risk-management/understanding-disputes/dispute-process-and-flow), [Visa chargebacks](https://docs.adyen.com/risk-management/chargeback-guidelines/visa-chargebacks)) and Braintree ([chargebacks and retrievals overview](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/overview)). All accessed November 2026. ## The short version | Term | What it is | Money moves? | Counts toward network dispute ratios? | |---|---|---|---| | Dispute | The umbrella word for a cardholder questioning a payment with their bank | Depends on the stage | Depends on the stage | | Inquiry / retrieval request / request for information | The bank asks you for details about a payment before deciding anything | No | Not as a chargeback | | Chargeback | The formal reversal: the bank takes the funds back while the case is decided | Yes | Yes, won or lost | | Pre-arbitration / second chargeback | The issuer (or you) pushes back after the first round | Can move again | Part of the same case | | Arbitration | The card network itself rules | Yes, plus network fees | Part of the same case | The rest of this article explains each row. ## Dispute: the umbrella term "Dispute" is the generic word. Stripe uses it for the whole process, from the first question to the final decision, and its Dispute object covers both inquiries and chargebacks. On Stripe, the status tells you which one you have: statuses starting with `warning_` are inquiries, and `needs_response`, `under_review`, `won` and `lost` are chargebacks. When someone on your team says "we got a dispute", the first question is therefore: is it an inquiry or a chargeback? ## Inquiry, retrieval request, request for information These three names describe the same idea: the cardholder's bank asks for information about a payment before it decides whether to open a chargeback. - **Stripe** calls it an **inquiry** and notes that it is sometimes also called a "retrieval" or a "request for information". Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says American Express and Discover use this phase most often, while Visa and Mastercard no longer use it. - **Adyen** calls it a **Request for Information (RFI)**. Its [dispute flow](https://docs.adyen.com/risk-management/understanding-disputes/dispute-process-and-flow) page describes it as a stage where no money is withdrawn, but warns that if you do not respond in time, a chargeback may follow. - **Braintree** calls it a **retrieval**. Its [overview](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/overview) says a retrieval is a customer's request for more detail about a charge they do not recognize, that it is non-financial, and that it cannot be won or lost. ### Why you should still answer An inquiry costs nothing on its own, which tempts teams to ignore it. That is a mistake. Adyen's pages for some networks are blunt: for [UnionPay](https://docs.adyen.com/risk-management/chargeback-guidelines/unionpay-chargebacks), if you do not answer an RFI and a chargeback follows, the chargeback is undefendable; for [Diners/Discover](https://docs.adyen.com/risk-management/chargeback-guidelines/diners-discover-chargebacks), you might not be able to defend it. A good inquiry response is short and factual. Braintree suggests including the transaction date, amount and statement descriptor. For a subscription, add what the customer bought, when they signed up, the plan and billing interval, and evidence they used the account. Often the cardholder simply did not recognize the line on their statement; once the bank explains it, the case ends there. ### Inquiry statuses on Stripe | Stripe status | Meaning | |---|---| | `warning_needs_response` | Inquiry waiting for your answer | | `warning_under_review` | You answered; the bank is reviewing | | `warning_closed` | Closed without becoming a chargeback | If an inquiry escalates, the status moves to `needs_response`, and funds are withdrawn. ## Chargeback: the formal reversal A chargeback is the stage with financial effect. The issuing bank reverses the payment through the card network, and the processor debits the amount from your balance while the case is decided. On Stripe, a dispute fee is charged at this point; in the US, Stripe's [pricing page](https://stripe.com/pricing) lists $15, plus a separate $15 countered fee if you contest, returned if you win. Braintree's [pricing](https://www.paypal.com/us/enterprise/paypal-braintree-fees) lists a $15 chargeback fee for standard US merchants. Other processors and countries differ. Every chargeback carries a **reason code** from the card network: for example Visa 10.4 (card-absent fraud) or 13.2 (cancelled recurring transaction), Mastercard 4837 (no cardholder authorization) or 4841 (cancelled recurring or digital goods). Stripe maps these to simpler categories such as `fraudulent` or `subscription_canceled` on its [categories page](https://docs.stripe.com/disputes/categories). The reason code decides what evidence matters; see [chargeback reason codes for subscriptions](/blog/chargeback-reason-codes-subscriptions/). Two facts about chargebacks surprise many teams: 1. **Winning does not erase it.** Stripe's [measuring disputes](https://docs.stripe.com/disputes/measuring) page says all disputes, won or lost, count toward your dispute rate. Card network monitoring programs work the same way. 2. **You cannot refund your way out once it is open.** Stripe's [dispute withdrawals FAQ](https://support.stripe.com/questions/dispute-withdrawals-faq) explains that you cannot refund a charge while a dispute is pending, because the bank has already returned the money to the cardholder. ### How long you have Deadlines are short. Stripe says you usually have 7 to 21 days to respond, depending on the network, and the exact date is on each dispute. Cardholders, on the other hand, have much longer to file: Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says networks typically allow about 120 days from the payment, and more in some situations. For a monthly subscription, that means several past renewals can be disputed at once. ## Pre-arbitration and second chargebacks If you defend a chargeback and the issuer still disagrees, the case can go to a second round. Adyen's [Visa chargebacks](https://docs.adyen.com/risk-management/chargeback-guidelines/visa-chargebacks) page describes two Visa workflows: - **Collaboration** (consumer disputes and processing errors): the issuing bank can open a pre-arbitration after reviewing your evidence. If it is accepted, the dispute is lost and you receive a second chargeback. - **Allocation** (fraud and authorization): Adyen files a pre-arbitration case with your documents, and the bank has 30 days to respond. Other networks have their own names and timelines. JCB, for instance, uses a second chargeback with a 35-day window, per Adyen's [JCB page](https://docs.adyen.com/risk-management/chargeback-guidelines/jcb-chargebacks). Braintree groups this stage under "pre-arbs" in its [overview](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/overview). ## Arbitration Arbitration is the last step: the card network itself decides. It carries network fees on top of processor fees; Adyen's pages mention, for example, a USD 600 filing fee under Visa's arbitration process. Few subscription disputes get this far, because the amounts are usually small compared with the fees. ## Related terms you will meet - **Early fraud warning (EFW).** Not a dispute. The issuer tells the network a payment was reported as fraud. Stripe exposes them as separate objects; see [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/). - **Friendly fraud / first-party misuse.** A cardholder disputes a payment they did make. See [friendly fraud in subscriptions](/blog/friendly-fraud-subscriptions/). - **Refund.** Something you initiate. A refund before a dispute is opened can prevent one; after a chargeback, the money already went back through the bank. - **Reversal.** On Stripe, a refund processed quickly enough to be a reversal of the authorization rather than a refund; Stripe's EFW docs explain why the difference matters for fraud reporting. ## What to do at each stage | Stage | Your move | |---|---| | Inquiry | Answer fast with plain facts: what, when, descriptor, usage. Consider a refund if the customer clearly did not want the charge. | | Chargeback | Read the reason code and deadline. Decide whether to fight or accept (see [refund or fight](/blog/refund-or-fight-chargeback/)). Build evidence for that reason code. | | Pre-arbitration | Only continue if you have new, strong evidence; fees rise at each step. | | Any stage | Cancel future renewals on a card reported as stolen, so the next charge does not create a new case. | ## Doing this with NoChurn NoChurn shows each Stripe and Braintree dispute with its stage, reason and deadline, and gathers evidence automatically: cancel flow answers, emails NoChurn sent, usage you send by API and conversations from your help desk (read only). It drafts a reply with AI, and nothing is sent until a person on your team has reviewed it. Disputes from other providers are shown read only, and on Paddle, Lemon Squeezy and Polar the merchant of record handles them. The bank still decides every case. See [chargebacks](/#disputes) and [pricing](/pricing/). --- # How to add a cancel flow to Chargebee Source: https://www.nochurn.sh/blog/chargebee-cancel-flow/ Chargebee gives you a lot of control over how a subscription ends: when the cancellation takes effect, what happens to credits, whether a reason is required, and whether customers can do it themselves. What it does not give you by default is a flow: a short sequence that asks why the customer is leaving and offers something useful before they go. This guide shows how cancellation works in Chargebee Billing, which settings matter, and how to build a fair cancel flow on top, either with Chargebee's own retention product or your own page and the API. It sticks to Chargebee's documentation: [Subscription Cancellation](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations), the [Self-Serve Portal](https://www.chargebee.com/docs/billing/2.0/hosted-capabilities/self-serve-portal), [Reason Codes](https://www.chargebee.com/docs/billing/2.0/site-configuration/reason-codes), the [Cancel a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items), [event types](https://apidocs.chargebee.com/docs/api/events/event-types) and Chargebee Growth's [targeted offers use case](https://www.chargebee.com/docs/growth/use-cases/retain-cancelling-subscribers-with-targeted-offers) (all accessed November 2026). ## How cancellation works in Chargebee ### Site-wide defaults Chargebee's [cancellation docs](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations) put the defaults under Settings › Configure Chargebee › Billing LogIQ › Customers & Subscriptions › Subscription cancellation. There you set: - **When it takes effect:** immediately, at the end of the current term, on a specific date, or at the end of the billing term. - **What happens to unused time:** how credits are handled. - **Overrides:** "Allow overriding via Chargebee interface" lets your team change the default case by case, and "Add condition to this rule" lets the behavior differ by channel (web interface, API, Self-Serve Portal, scheduled cancellations). ### End of term: non-renewing When a cancellation is scheduled for the end of term, the subscription does not end right away. Per the [Cancel a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items), its status becomes `non_renewing` and its remaining billing cycles drop to 0. It then cancels at the end of the term. Chargebee sends `subscription_cancellation_scheduled` when the cancellation is scheduled, a `subscription_cancellation_reminder` 6 days before it takes effect, and `subscription_cancelled` when it does ([event types](https://apidocs.chargebee.com/docs/api/events/event-types)). A non-renewing subscription can still be kept. Chargebee has a "Remove scheduled cancellation" operation for exactly that case. ### Contract terms For subscriptions on a contract term, the [cancellation docs](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations) say a cancellation from the Self-Serve Portal happens at the end of the contract term only. In the API, these subscriptions use `contract_term_cancel_option` instead of `cancel_option`. ## Letting customers cancel themselves In the [Self-Serve Portal](https://www.chargebee.com/docs/billing/2.0/hosted-capabilities/self-serve-portal) settings, "Allow customers to cancel subscription" turns self-service cancellation on. You choose when it takes effect: immediately, at the end of the term, or let customers choose (in which case they can also pick a date within the subscription period). The same section includes optional feedback collection, reactivation, and removal of scheduled cancellations. Turn it on. Making customers email support to cancel creates friction that shows up as chargebacks and angry reviews, and in many places the law now expects cancellation to be as easy as signing up. ## Reason codes Chargebee has a native list of cancellation reasons. You configure it under Settings › Configure Chargebee › Reason Codes › Subscriptions › Subscription Cancellation ([Reason Codes](https://www.chargebee.com/docs/billing/2.0/site-configuration/reason-codes)). The codes then appear as choices when a subscription is cancelled from the Chargebee interface or the Self-Serve Portal, and you can make them mandatory. In the API, the [Cancel a subscription](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items) endpoint takes `cancel_reason_code`: a case-sensitive string, up to 100 characters, that must match one of the configured codes, and that must be passed if you made reasons mandatory. Keep the list short and actionable. Six to eight reasons that each map to a different response beat twenty that nobody reads: | Reason code | What you can offer | |---|---| | Too expensive | A discount for a few months, or a cheaper plan | | Not using it enough | A pause, or a smaller plan | | Taking a break / seasonal | A pause with a resume date | | Missing a feature | Nothing to buy; log it and say if it is planned | | Switching to another tool | Nothing; ask what they chose and let them go | | Technical problems | A fast route to support | | Other | Free text | ## Building the flow ### Option 1: Chargebee's own retention product Chargebee offers cancel-page offers through Chargebee Growth (which absorbed the product previously called Chargebee Retention). Its [targeted offers use case](https://www.chargebee.com/docs/growth/use-cases/retain-cancelling-subscribers-with-targeted-offers) describes three offers on a cancel page: a discount (tied to a coupon in Chargebee Billing), a pause, and a plan downgrade, applied in Billing when the customer accepts. It also notes that subscribers without a stored payment method cannot complete the change or resume automatically after a pause. If you already pay for Growth, start there. ### Option 2: your own page and the API If you prefer your own page, the building blocks are all in Chargebee Billing: 1. **Intercept the cancel button in your app.** Show your own page before anything is cancelled. 2. **Ask for the reason.** One question, using your Chargebee reason codes as the options. 3. **Show one offer that fits the reason,** or none. Use a coupon for discounts, the [pause API](https://apidocs.chargebee.com/docs/api/subscriptions/pause-a-subscription) for breaks, or a plan change. 4. **Keep "Cancel my subscription" visible on every step.** One click, no extra screens. 5. **Cancel with the reason.** Call the [cancel endpoint](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items) with `cancel_option` set to `end_of_term` (or `contract_term_cancel_option` for contract subscriptions) and the `cancel_reason_code`. Note that `end_of_term` as a boolean is deprecated in favour of `cancel_option`. 6. **Confirm clearly.** Show the end date and send a confirmation email. 7. **Offer a way back.** Until the end date, a "Keep my subscription" button that removes the scheduled cancellation. ### Using the reason after cancellation Chargebee notes that `cancel_reason_code` may not be returned for non-renewing subscriptions by default when you retrieve them; a site-level setting includes it, so you can act on the reason before the cancellation runs ([Subscription Cancellation](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations)). Turn it on if you want reason-based reminders during the remaining term. ## Fairness rules worth keeping - **Cancel is always one click away.** An offer is a choice, not a gate. - **No more than one offer.** A second offer after a "no" feels like haggling. - **Do not ask for a reason twice.** If the customer answered on your page, pass it through; do not make them pick again in the portal. - **Honour the cancellation immediately.** If they decline the offer, cancel, confirm, and stop. ## Measuring it Track, per reason: how many customers reached the cancel page, how many accepted an offer, and how many of those were still paying 90 days later. A save that cancels a month later is a delay, not a save. Chargebee's `subscription_cancellation_scheduled` and `subscription_cancelled` events, together with your page's own logs, give you all three numbers. ## Doing this with NoChurn Cancellation itself stays in Chargebee: NoChurn calls Chargebee to cancel, pause or apply an offer, and Chargebee's portal keeps working as configured. NoChurn provides the flow: reasons, one offer per reason (discount, pause or plan change), and a one-click cancel that is visible at every step, hosted or headless through the API. Answers feed a churn score from 0 to 100 and win-back emails at day 30, 60 and 90 based on the reason. See [NoChurn + Chargebee](/integrations/chargebee/). --- # How to measure churn in Chargebee Source: https://www.nochurn.sh/blog/chargebee-churn-metrics/ Churn sounds like one number, but in Chargebee it is spread across several statuses, events and settings. A subscription can be scheduled to cancel and still be active. It can be paused and paying nothing. It can be cancelled for non-payment rather than by choice. Unless you decide up front how each case counts, two people on your team will compute two different churn rates from the same data. This guide shows how to build a clear churn measurement from Chargebee Billing: which states and events to use, how to separate voluntary from involuntary churn, and how to handle pauses and reactivations. It sticks to Chargebee's documentation: [Subscription Cancellation](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations), the [Cancel a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items), [event types](https://apidocs.chargebee.com/docs/api/events/event-types), the [List events](https://apidocs.chargebee.com/docs/api/events/list-events) and [List subscriptions](https://apidocs.chargebee.com/docs/api/subscriptions/list-subscriptions) APIs, [Reason Codes](https://www.chargebee.com/docs/billing/2.0/site-configuration/reason-codes) and [Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription) (all accessed November 2026). ## Start with Chargebee's reports Chargebee has built-in reporting, including a [standard Subscriptions report](https://www.chargebee.com/docs/billing/2.0/reports-and-analytics/standard-subscriptions). Use it first, and read how each figure is defined on that page before comparing it with anything else. This guide focuses on building your own measurement from Chargebee's data, which you need when you want churn joined with product usage, signup source or cancellation reasons in your own warehouse. ## The states that matter | Chargebee state | Churned? | Why | |---|---|---| | `in_trial` | Not yet a paying customer | Measure trial conversion separately | | `active` | No | Paying | | `non_renewing` | Not yet | Cancellation scheduled for end of term; still active | | `paused` | No, but not paying | Track separately | | `cancelled` | Yes | Ended | The `non_renewing` row is the one teams get wrong. Per the [Cancel a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items), an end-of-term cancellation moves the subscription to `non_renewing` and sets its remaining billing cycles to 0. It can still be saved with "Remove scheduled cancellation". Count it as churn on the date it becomes `cancelled`, not on the day the customer clicked. ## The events that matter Chargebee's [event types](https://apidocs.chargebee.com/docs/api/events/event-types) give you a timestamped record of every transition: | Event | Use it for | |---|---| | `subscription_created` | New subscriptions | | `subscription_cancellation_scheduled` | Cancellations scheduled (leading indicator) | | `subscription_cancellation_reminder` | Sent 6 days before a scheduled cancellation | | `subscription_cancelled` | Churn, on its effective date | | `subscription_reactivated` | Customers who came back after cancelling | | `subscription_paused`, `subscription_resumed` | Pause periods | | `subscription_pause_scheduled` | Pauses scheduled for later | You can receive these as webhooks, or pull history through the [List events API](https://apidocs.chargebee.com/docs/api/events/list-events). For a first analysis, pulling the last twelve months of events is often the fastest way to get a baseline. A note on spelling: Chargebee's event reference uses `subscription_cancelled` with two Ls, while some of its other pages write "canceled". Match the exact string you see in your own payloads. ## Voluntary vs involuntary churn These need different fixes, so split them from day one. - **Involuntary:** the [event types reference](https://apidocs.chargebee.com/docs/api/events/event-types) says `subscription_cancelled` carries a `cancel_reason` when the cancellation was caused by non-payment or a missing card. Those are your failed-payment losses. - **Voluntary:** cancellations without that system reason, typically carrying a `cancel_reason_code` from your configured [Reason Codes](https://www.chargebee.com/docs/billing/2.0/site-configuration/reason-codes). Make reason codes mandatory for cancellations from the app and the portal. Per Chargebee's docs, when reason codes are mandatory, the cancel API must also receive a `cancel_reason_code`. Then every voluntary cancellation has a reason, and you can report churn by reason without guesswork. One practical point from the [cancellation docs](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations): `cancel_reason_code` may not be included when you retrieve a non-renewing subscription unless you enable the related site-level setting. Enable it, or capture the reason from the `subscription_cancellation_scheduled` event. ## Pauses Chargebee's [Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription) page says renewals stop while a subscription is paused. A paused customer is not paying and has not left. Pick one rule and keep it: - **Exclude paused subscriptions** from both the starting base and churn, and report the paused count next to the churn rate. This is the most common choice. - If a pause ends in a cancellation, count the churn on the cancellation date like any other. Whatever you choose, do not let pauses silently lower your churn rate. A pause offer that only delays cancellation should show up eventually as churn. ## Reactivations A customer who cancels and later reactivates (`subscription_reactivated`) is still churn in the month they left. Count the reactivation separately, as recovered or reactivated customers, rather than subtracting it from past churn. Rewriting past months makes trends impossible to read. ## A monthly churn calculation With the states and events above, a customer churn rate for one month: 1. **Starting base:** subscriptions `active` or `non_renewing` at 00:00 on the first day of the month (exclude `in_trial`, and `paused` if that is your rule). The [List subscriptions API](https://apidocs.chargebee.com/docs/api/subscriptions/list-subscriptions) gives you current state; for a past date, rebuild state from events. 2. **Churned:** subscriptions from that base with a `subscription_cancelled` event during the month. 3. **Customer churn rate:** churned divided by starting base. 4. **Split:** the same ratio for involuntary (system `cancel_reason`) and voluntary (with `cancel_reason_code`), which add up to the total. New subscriptions created during the month are not in the starting base, so their cancellations within the month are reported separately or left out. Write down which. For revenue churn, replace counts with each subscription's monthly recurring amount at the start of the month (annual plans divided by 12). Report contraction from downgrades separately from cancellations. ## Leading indicators Churn is a lagging number. These move earlier: - **Cancellations scheduled** (`subscription_cancellation_scheduled`) this month, especially for annual plans. - **Non-renewing saves:** subscriptions leaving `non_renewing` without being cancelled. - **Failed renewals** that have not been recovered yet. - **Pauses started**, and the share of pauses that end in cancellation. ## Common mistakes - **Counting churn on the click.** The cancellation date is when the subscription becomes `cancelled`, not when it became `non_renewing`. - **Mixing trials into the base.** Trials that do not convert are a conversion problem, not churn. - **One blended number.** Without the voluntary and involuntary split, you cannot tell whether to fix your dunning or your product. - **Silent pauses.** Excluding paused subscriptions without reporting them hides a growing group of customers who are not paying. ## Keep definitions stable Write your definitions down: what counts as the base, when churn is dated, how pauses, trials, reactivations and contract terms are treated. Change them rarely, and when you do, recompute history. A churn rate is mostly useful compared with itself. ## Doing this with NoChurn Subscriptions, cancellations and Chargebee's own reports stay in Chargebee. NoChurn reads your Chargebee events, separates voluntary and involuntary churn, records the reason from its cancel flow (where cancel is always one click away), and gives each customer a churn score from 0 to 100. You can send your own product data by API to see which attributes correlate with churn, and if you connect a help desk, support conversations are read for the score and insights. See [NoChurn + Chargebee](/integrations/chargebee/). --- # How to recover failed payments in Chargebee Source: https://www.nochurn.sh/blog/chargebee-failed-payments/ Chargebee has a mature dunning system: it classifies payment errors, retries on its own schedule or yours, emails customers with a link to update their card, and applies a final action when nothing works. Most of the recovery you can get from Chargebee comes down to a handful of settings and how well your emails are written. This guide explains those settings and what to add around them. It sticks to Chargebee's own documentation: [Dunning](https://www.chargebee.com/docs/payments/2.0/dunning/dunning-v2), [Smart and manual dunning](https://www.chargebee.com/docs/payments/2.0/kb/payments/smart-and-manual-dunning-management), [What is Smart Dunning](https://www.chargebee.com/docs/payments/2.0/kb/payments/what-is-smart-dunning), [which webhook fires during dunning](https://www.chargebee.com/docs/payments/2.0/kb/payments/which-webhook-event-will-trigger-when-invoice-is-in-dunning), the [Invoices API](https://apidocs.chargebee.com/docs/api/invoices), the [payment_failed event](https://apidocs.chargebee.com/docs/api/events/webhook/payment_failed), the [Self-Serve Portal](https://www.chargebee.com/docs/billing/2.0/hosted-capabilities/self-serve-portal) and [how customers update their payment method](https://www.chargebee.com/docs/payments/2.0/kb/billing/how-to-let-my-customer-update-their-payment-method-during-transaction-failures) (all accessed November 2026). Chargebee has two generations of dunning; this guide describes the current one and flags where the older version differs. ## How Chargebee dunning works When an automatic renewal charge fails, the invoice enters dunning. Chargebee then retries the payment and sends reminder emails during a **dunning period**: the number of days the invoice stays in dunning before the final action is carried out. Retries only happen inside that window. With auto-collection on, the subscription [stays Active during dunning](https://www.chargebee.com/docs/billing/2.0/kb/billing/subscription-status-as-active-when-payment-failed-on-renewal). What happens after depends on your settings. ### Two retry modes Chargebee's [Dunning page](https://www.chargebee.com/docs/payments/2.0/dunning/dunning-v2) describes two modes: | | Smart mode | Custom mode | |---|---|---| | Who picks the timing | Chargebee, based on the gateway error | You, as days after the first failure | | Maximum retries | Up to 12 | Up to 5 | | Hard declines | Not retried until the payment method changes | The docs describe retries on the days you set | | Exact dates | Not guaranteed | Fixed | **Smart mode** classifies gateway error codes as hard or soft declines. Hard declines wait for the customer to update their payment method. For soft declines, Chargebee chooses a time to retry based on the error category and the chances of recovery. Chargebee's docs say exact retry dates cannot be guaranteed in this mode. A manual "Collect Now" also counts as a retry. One Chargebee help article notes that Smart Dunning is available from specific plans, so check yours. **Custom mode** lets you set retry days. Chargebee's example: with an 8-day dunning period and a retry frequency of "1,4,8", retries run 1, 4 and 8 days after the first failure. Chargebee also markets [Revive](https://www.chargebee.com/payments/retries-and-dunning/), a machine-learning retry mode that runs inside Smart Dunning's limits. Check with Chargebee for availability on your plan. ### 3D Secure failures Whichever mode you pick, Chargebee says payments that failed because of 3D Secure are retried only the day before the dunning period ends, if the customer has not acted. Those customers need to complete authentication themselves, so the email is what recovers them, not the retry. ### The final action When all retries fail, you choose what happens to: - **the subscription**: cancel it, or keep it active; - **the invoice**: mark it not paid, write it off, or void it. Cancelling is the strict option; keeping the subscription active with the invoice unpaid gives you more time to reach the customer, at the cost of serving someone who has not paid. Choose on purpose rather than leaving the default. ### Dunning v1 Older sites may still be on Dunning v1. Chargebee's own help articles give different retry counts for v1, so if your site uses it, check the settings in your dashboard rather than relying on an article, and consider moving to the current version. ## Dunning emails and the card update link Chargebee sends dunning emails during the retry attempts, and those emails include a link where the customer can update their payment method on Chargebee's hosted pages ([update payment method guide](https://www.chargebee.com/docs/payments/2.0/kb/billing/how-to-let-my-customer-update-their-payment-method-during-transaction-failures)). Chargebee can also notify customers when a card is about to expire, has expired or becomes invalid. There are three other ways to get a new payment method: 1. **Request payment method.** From a customer or subscription page in the dashboard, staff can send a secure link to Chargebee's hosted page. 2. **Self-Serve Portal.** Once enabled under Settings › Configure Chargebee › Checkout and Self-Serve Portal, customers can manage payment methods and pay unpaid invoices ([Self-Serve Portal](https://www.chargebee.com/docs/billing/2.0/hosted-capabilities/self-serve-portal)). 3. **API.** The hosted pages API for managing payment sources returns a URL you redirect the customer to, if you want the link inside your own app or emails. The default email templates are a starting point. Edit them so the customer recognizes your brand, understands what failed, and sees one clear button. ## Events and webhooks Chargebee's guidance for following dunning is to listen to [`payment_failed`](https://apidocs.chargebee.com/docs/api/events/webhook/payment_failed) and read the invoice's `dunning_status`: | `dunning_status` | Meaning | |---|---| | `in_progress` | The invoice is in dunning, retries remain | | `exhausted` | The last retry failed; the dunning period is over | | `success` | A payment was collected during dunning | | `stopped` | Dunning was stopped for this invoice | Each failed attempt during dunning generates a `payment_failed` event; only the last one carries `exhausted` ([which event marks the end of dunning](https://www.chargebee.com/docs/payments/2.0/kb/payments/which-event-marks-the-closing-of-the-dunning-period)). [`payment_succeeded`](https://apidocs.chargebee.com/docs/api/events/webhook/payment_succeeded) fires when a payment is collected. Use these to keep your own records in sync, to stop any extra communication the moment a payment succeeds, and to know when the final action has happened. ## A recovery setup, step by step 1. **Pick a retry mode.** Smart mode is the sensible default for card payments if your plan includes it, since it skips pointless retries on hard declines. Use Custom mode if you need predictable dates, for example to match when your customers are paid. 2. **Set the dunning period** to fit your billing cycle. A monthly plan cannot wait as long as an annual one. 3. **Choose the final action** for the subscription and the invoice deliberately. 4. **Turn on and rewrite the dunning emails.** Send the first one on the first failure, with the update link. For hard declines, the email is the only thing that will recover the payment. 5. **Handle 3D Secure separately.** Tell those customers that their bank needs them to confirm the payment, and send them the link right away. 6. **Enable the Self-Serve Portal** so customers who ignore the email can still fix their card from your app. 7. **Turn on card expiry notices** to catch failures before they happen. 8. **Listen to `payment_failed` and `payment_succeeded`** and log the outcome by error type, so you can see which failures your setup recovers and which it does not. ## What to add on top Chargebee's retries and emails cover the basics well. What it leaves to you is mostly communication: emails that read like they come from a person, in the customer's language, that say what to do for the specific failure; replies that reach someone; and a follow-up for customers who were lost so you can try to win them back. ## Doing this with NoChurn NoChurn connects to your Chargebee site with an API key and follows its webhooks. It runs next to your Chargebee dunning settings: it sends recovery emails written by AI, reviewed by you, with a link for the customer to update their payment method, and it adds cancel flows, win-back emails at day 30, 60 and 90, and a churn score from 0 to 100. Invoicing, the charge itself and your payment gateway stay with Chargebee. Disputes come from the gateway behind Chargebee; with Stripe or Braintree, NoChurn gathers the evidence and drafts a reply that is sent only after you review it. NoChurn is free under $300 MRR. See [NoChurn + Chargebee](/integrations/chargebee/). --- # How to pause subscriptions in Chargebee Source: https://www.nochurn.sh/blog/chargebee-pause-subscriptions/ Some customers do not want to leave. They want to stop paying for a few months: a seasonal business, a parental leave, a project on hold. If cancelling is the only option, you lose them. Chargebee has a mature pause feature, with more options than most billing systems, and it is worth setting up properly before you need it. This guide covers how pausing works in Chargebee Billing: the site defaults, the options in the app, the API and the Self-Serve Portal, what happens to billing, and how to offer a pause at the right moment. It sticks to Chargebee's documentation: [Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription), the [Pause a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/pause-a-subscription), the [Self-Serve Portal](https://www.chargebee.com/docs/billing/1.0/hosted-capabilities/self-serve-portal) and the [event types reference](https://apidocs.chargebee.com/docs/api/events/event-types) (all accessed November 2026). ## Turn it on and set the defaults Pausing has to be enabled first. Chargebee's [Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription) page puts the settings under Settings › Configure Chargebee › Billing LogIQ › Customers & Subscriptions › Pause Subscription. The defaults cover three questions: | Setting | Options | |---|---| | When the pause starts | Immediately, or at the next renewal | | How long it lasts | Indefinitely, or until a set date and time | | When the subscription resumes | Immediately, or at the next renewal | These are defaults, not limits. Your team can still choose differently when pausing a specific subscription. ## Pausing from the Chargebee app When someone on your team pauses a subscription, Chargebee lets them pause: - **immediately,** - **at the end of the current term,** or - **on a scheduled date.** If no resume date is set, the pause is indefinite. A resume date can be set when pausing and edited later. Chargebee also has a knowledge base article on [extending a pause date](https://www.chargebee.com/docs/billing/2.0/kb/billing/how-to-extend-the-pause-date-for-a-subscription). One behavior to know: a scheduled pause overrides other scheduled changes on that subscription, such as a pending upgrade ([Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription)). If you schedule plan changes and pauses for the same customers, check the result. ## Pausing through the API The [Pause a subscription](https://apidocs.chargebee.com/docs/api/subscriptions/pause-a-subscription) endpoint takes a `pause_option`. Its values mirror the app, plus one: | `pause_option` | Behavior | |---|---| | `immediately` | Pauses now | | `end_of_term` | Pauses when the current term ends | | `specific_date` | Pauses on the date you pass | | `billing_cycles` | Pauses at term end and resumes after a set number of skipped billing cycles | You set when billing comes back with `resume_date`. The `billing_cycles` option is the most natural fit for a customer-facing offer: "Skip the next 2 months" maps directly onto it. Resuming is a separate call. In the app or through the resume API, it can be immediate or scheduled for a specific date and time. ## Letting customers pause themselves The [Self-Serve Portal](https://www.chargebee.com/docs/billing/1.0/hosted-capabilities/self-serve-portal) can offer pausing to customers. You decide how long a pause can last: - indefinitely, - for a fixed number of days, or - for a duration the customer picks from intervals you configure, capped at a maximum number of days. Per the [Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription) page, the portal only supports immediate resumption: a customer who resumes from the portal is back on billing right away. If you enable portal pausing, cap the duration. An indefinite pause is easy to forget, for you and for the customer. ## What happens to billing The [Pause Subscription](https://www.chargebee.com/docs/billing/2.0/subscriptions/pause-subscription) page is clear on the effects: - **Renewals stop** while the subscription is paused. - **Monthly plans keep their billing cycles.** The customer does not lose paid time. - **Yearly plans lose service time.** Pausing a yearly subscription mid-term costs the customer that part of the year, because the term keeps running. - **Unbilled charges** can be invoiced when the pause starts or kept until the subscription resumes. The yearly-plan point changes how you should offer a pause. For an annual customer who wants a break, `end_of_term` is usually the fair choice: they use what they paid for, then pause instead of renewing. ## Events to listen to The [event types reference](https://apidocs.chargebee.com/docs/api/events/event-types) includes: - `subscription_pause_scheduled` when a pause is scheduled for a future date, - `subscription_paused` when the subscription is paused, - `subscription_resumed` when it resumes. Use them to update access in your app, to stop usage-based charges if you track usage yourself, and to schedule a reminder before the resume date. ## Offering a pause well Chargebee handles the mechanics. Whether customers take the pause depends on how and when you offer it. ### 1. Offer it when they try to cancel Put the offer on the cancel path, for customers whose reason fits: "taking a break", "seasonal", "not using it right now". Do not show it to someone who says they switched to another tool. And keep the cancel button visible next to the offer; a pause is an alternative, not an obstacle. ### 2. Make it concrete "Pause for 1, 2 or 3 months" beats "Pause your subscription". Each choice maps to `billing_cycles` or a `resume_date`. ### 3. Pick the right start for the plan Monthly plans: pausing immediately is fine. Yearly plans: default to `end_of_term` so the customer does not lose service time they paid for. ### 4. Remind before it resumes A charge after a forgotten pause feels like a surprise, and surprises turn into disputes. Send a reminder a few days before the resume date with options to extend, resume now or cancel. Chargebee's docs we used do not describe a built-in pause-ending reminder, so trigger it from `subscription_paused` and the resume date. ### 5. Handle missing payment methods If a customer has no valid payment method on file, a resumed subscription will simply fail at its first renewal. Ask for a card update in the reminder when you can see that the card on file has expired. ### 6. Measure what happens after For every pause, record the outcome: resumed and paid, extended, cancelled during the pause, or cancelled within a month of resuming. If most pauses end in cancellation, the offer is delaying churn rather than preventing it, and the reasons you offer it for may need adjusting. ## Common mistakes - **Pausing annual plans immediately by default.** The customer loses service time they paid for, and may only notice when they come back. - **Indefinite portal pauses.** Without a cap, a pause becomes a quiet cancellation that never shows up in your churn numbers. - **Treating paused as churned, or as active.** It is neither. Report paused subscriptions on their own line. - **No reminder before resuming.** The first charge after a long pause is the one most likely to be disputed. ## Doing this with NoChurn Pausing stays a Chargebee feature: NoChurn calls Chargebee's pause API when a customer accepts the offer, and your Chargebee settings still apply. NoChurn adds the cancel flow around it: the customer gives a reason, sees a pause (or a discount or plan change) only when it fits, and can always cancel in one click. It is hosted, or headless through the API. Pause outcomes and reasons feed each customer's churn score from 0 to 100. See [NoChurn + Chargebee](/integrations/chargebee/). --- # How to win back churned customers on Chargebee Source: https://www.nochurn.sh/blog/chargebee-win-back/ On Chargebee, a churned customer is rarely gone for good. The subscription record, the customer, and often the payment method are all still there. Chargebee can bring a cancelled subscription back with one API call, which makes win-back much cheaper than a new sale, if you set it up deliberately. This guide explains the two moments you can act on (before the cancellation takes effect, and after), the Chargebee operations for each, and a reason-based sequence to run on top. It sticks to Chargebee's documentation: [Subscription Cancellation](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations), the [Reactivate a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/reactivate-a-subscription), the [Update a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/update-subscription-for-items), the knowledge base articles on [applying a coupon while reactivating](https://www.chargebee.com/docs/billing/2.0/kb/product-catalog/how-to-apply-a-coupon-while-reactivating-a-cancelled-subscription) and [reactivating via checkout](https://www.chargebee.com/docs/billing/2.0/kb/billing/can-i-use-checkout-to-update-a-subscription-api-to-reactivate-resume-subscriptions), and the [event types reference](https://apidocs.chargebee.com/docs/api/events/event-types) (all accessed November 2026). ## Two states, two windows A Chargebee subscription that is on its way out is in one of two states. | State | What it means | How to win it back | Event that opens the window | |---|---|---|---| | `non_renewing` | Cancellation scheduled for the end of the term; still active | Remove the scheduled cancellation | `subscription_cancellation_scheduled` | | `cancelled` | Ended | Reactivate the subscription | `subscription_cancelled` | Per the [Cancel a subscription API](https://apidocs.chargebee.com/docs/api/subscriptions/cancel-subscription-for-items), an end-of-term cancellation moves the subscription to `non_renewing` and sets its remaining billing cycles to 0. It becomes `cancelled` when the term ends. ## Window 1: non-renewing subscriptions This is the cheapest save. The customer still has access, nothing needs re-entering, and Chargebee's "Remove scheduled cancellation" operation puts the subscription back on its normal renewal schedule. Chargebee helps you time it. Its [event types](https://apidocs.chargebee.com/docs/api/events/event-types) include `subscription_cancellation_reminder`, sent 6 days before a scheduled cancellation takes effect. That event is a natural trigger for a "Your plan ends on Friday" email with a "Keep my plan" button. The [Self-Serve Portal](https://www.chargebee.com/docs/billing/2.0/hosted-capabilities/self-serve-portal) also has a setting to let customers remove a scheduled cancellation themselves. If you use the portal, turn it on; a customer who changes their mind should not need to contact you. Know the reason before you write. Chargebee's [cancellation docs](https://www.chargebee.com/docs/billing/2.0/subscriptions/cancellations) note that `cancel_reason_code` may not be returned for non-renewing subscriptions by default; a site-level setting includes it in the Retrieve Subscription response, so you can act on the reason before the cancellation runs. ## Window 2: cancelled subscriptions ### The reactivate endpoint Chargebee's [Reactivate a subscription](https://apidocs.chargebee.com/docs/api/subscriptions/reactivate-a-subscription) endpoint is a `POST` to `/api/v2/subscriptions/{subscription-id}/reactivate`, for subscriptions in `cancelled` status. Two parameters matter for win-back: - `reactivate_from`: the date the subscription counts as reactivated. Omit it to reactivate immediately. Backdating requires that backdating be enabled for reactivation. - `invoice_immediately`: whether charges raised at reactivation are invoiced right away or added to unbilled charges. The default comes from your site settings, and it only covers charges raised by that call. Successful reactivation sends `subscription_reactivated` (or `subscription_reactivated_with_backdating` when the date is in the past). ### Reactivating with a discount The reactivate endpoint does not take coupons. Per Chargebee's [knowledge base](https://www.chargebee.com/docs/billing/2.0/kb/product-catalog/how-to-apply-a-coupon-while-reactivating-a-cancelled-subscription), use the [Update a subscription](https://apidocs.chargebee.com/docs/api/subscriptions/update-subscription-for-items) API instead: it accepts coupon IDs, and its `reactivate` flag reactivates a cancelled subscription in the same request. The flag defaults to `true` when you pass subscription items or coupons, unless you set it to `false`. That gives you a clean "come back at 30% off for 3 months" path: create a coupon with a limited duration in Chargebee, then reactivate with it through the update call when the customer accepts. ### What does not work - **Checkout:** Chargebee's [knowledge base](https://www.chargebee.com/docs/billing/2.0/kb/billing/can-i-use-checkout-to-update-a-subscription-api-to-reactivate-resume-subscriptions) says the "create checkout to update a subscription" call cannot be used to reactivate or resume subscriptions. If the customer needs to enter a new card, collect it separately, then reactivate. - **Decommissioned subscriptions** cannot be reactivated. ## Building the win-back flow ### Step 1: collect the reason at cancellation Chargebee's [Reason Codes](https://www.chargebee.com/docs/billing/2.0/site-configuration/reason-codes) give you a native list that appears in the app and the Self-Serve Portal, and that the cancel API accepts as `cancel_reason_code`. Set it up before anything else. A win-back sequence without reasons is a generic "We miss you". ### Step 2: separate involuntary churn The [event types reference](https://apidocs.chargebee.com/docs/api/events/event-types) says `subscription_cancelled` includes a `cancel_reason` when the cancellation came from non-payment or a missing card. Those customers did not choose to leave. Do not send them a win-back offer; send them a card update request and reactivate when they pay. ### Step 3: match the message to the reason | Reason | What to send | |---|---| | Too expensive | A time-limited coupon, applied through reactivation | | Not using it enough | What changed, and a smaller plan | | Missing a feature | A note when it ships; no coupon | | Switched to another tool | One honest message, then stop | | Seasonal or temporary | A check-in when they said they would be back | | Non-payment | Not a win-back: a payment update request | ### Step 4: space the messages Three touches after cancellation is enough: around day 30, day 60 and day 90. Stop at the first reply, unsubscribe or reactivation (`subscription_reactivated`). ### Step 5: make coming back one click Every email should link to a page in your app that, on confirmation, calls reactivate (or update with the coupon). If the card on file is no longer valid, ask for a new one on that page first. ### Step 6: respect consent A former customer is not automatically a marketing contact. Check your consent basis per region, keep the message tied to their reason, and include a one-click unsubscribe. ## Measuring it Measure two rates separately: 1. **Non-renewing saves:** subscriptions that left `non_renewing` without being cancelled, divided by all `subscription_cancellation_scheduled` events in the period. 2. **Reactivations:** `subscription_reactivated` events within 90 days of cancellation, divided by voluntary cancellations, split by reason and by whether a coupon was used. Then check who is still paying 90 days after coming back. A reactivation that cancels again at the end of the coupon is a delay, and it tells you the coupon was the wrong offer for that reason. ## Common mistakes - **Treating `non_renewing` as churned.** The customer is still active and still reachable in the app. This is your best window, not a lost cause. - **Sending offers to involuntary churn.** A customer whose card failed needs a payment link, not a discount. - **Leading with the biggest coupon.** Start with relevance; offer a discount only where the reason calls for one. - **Reactivating without a valid card.** The subscription comes back and fails at the next renewal. Check the payment method first. ## Doing this with NoChurn Reactivation, coupons and billing stay in Chargebee; NoChurn calls Chargebee's API to apply them. NoChurn collects the reason through its cancel flow (with a one-click cancel always visible), separates involuntary churn, and sends win-back emails at day 30, 60 and 90 based on the reason. Each customer also has a churn score from 0 to 100, and if you connect a help desk, past support conversations inform it. See [NoChurn + Chargebee](/integrations/chargebee/). --- # The churn dashboard: which metrics to track and how to compute them Source: https://www.nochurn.sh/blog/churn-dashboard-metrics/ A churn dashboard should answer three questions every month: how much revenue did we lose, why, and is it getting better? Most dashboards answer the first one and stop. This guide lists the metrics that answer all three, gives a formula for each, and works through one month of hypothetical numbers. For the basics of customer, gross and net churn, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). This article is about assembling them into one page you can trust. ## The dashboard in four rows | Row | Metrics | Question it answers | |---|---|---| | 1. Revenue base | MRR, MRR movements | How big is the base and how did it move? | | 2. Headline churn | Customer churn, gross revenue churn, NRR, GRR | How much did we lose? | | 3. Churn by cause | Voluntary vs involuntary, cancel reasons | Why did we lose it? | | 4. Levers | Recovery rate, save rate, win-back rate, cohort retention | Is what we do working? | Keep it to one screen. If a metric does not lead to a decision, move it to a secondary report. ## Row 1: the revenue base ### MRR Monthly recurring revenue is the sum of every active subscription's monthly value. Normalize other intervals: an annual plan counts as one twelfth of its price, a quarterly plan as one third. Decide and document three things before you compute it: - **Discounts.** Is MRR before or after recurring discounts? Stripe's Billing analytics let you choose whether to exclude discounts ([Stripe analytics docs](https://docs.stripe.com/billing/subscriptions/view-metrics), accessed November 2026). - **Past-due subscriptions.** Stripe counts past-due subscribers as active. That is defensible, but it means MRR includes revenue you have not collected. - **Usage-based charges.** Either exclude variable usage from MRR or use a trailing average, and say which. ### MRR movements Break the month's change into categories. Stripe's MRR roll-forward uses new, reactivation, expansion, contraction, churn and FX adjustment; you can use the same list. ```text ending MRR = starting MRR + new + reactivation + expansion − contraction − churned ± FX adjustment ``` If this equation does not balance in your data, a category is missing or double counted. Fix that before reading any other metric. ## Row 2: headline churn ```text customer churn = customers lost ÷ customers at start gross rev churn = (churned MRR + contraction) ÷ starting MRR GRR = 1 − gross rev churn NRR = (starting MRR − churned − contraction + expansion) ÷ starting MRR ``` Reactivations and new customers stay out of all four. A deeper look at the last two is in [NRR vs GRR](/blog/net-revenue-retention/). ### Stripe's subscriber churn is a different number Stripe's subscriber churn rate uses a rolling 30-day window, and its denominator includes subscribers active at the start plus new subscribers added during the window. A start-of-period denominator gives a higher figure for the same losses. Neither is wrong; just do not put them side by side as if they were the same metric. ## Row 3: churn by cause ### Voluntary vs involuntary ```text involuntary churned MRR = MRR of subscriptions that ended on a failed payment voluntary churned MRR = MRR of subscriptions the customer cancelled ``` On Stripe, `cancellation_details.reason` on the subscription tells you which it was (`cancellation_requested`, `payment_failed`, `payment_disputed`) per the [cancel API reference](https://docs.stripe.com/api/subscriptions/cancel). The split matters because the fixes differ completely; see [involuntary churn](/blog/involuntary-churn/). ### Cancel reasons Show voluntary churned MRR by cancel reason, not just counts. Ten small customers saying "too expensive" and one large customer saying "missing feature" lead to different roadmaps. ### At-risk MRR ```text at-risk MRR = MRR of subscriptions currently past due + MRR of subscriptions scheduled to cancel at period end ``` This is the only row that looks forward. It tells you what next month's churn will be if nobody acts. ## Row 4: the levers ### Failed payment recovery rate ```text recovery rate = failed invoices later paid ÷ invoices that failed at least once ``` Measure it per cohort of failed invoices (for example, all invoices that first failed in March), and only after the retry window has closed. Otherwise this month's rate looks low because many invoices are still in progress. ### Cancel flow save rate ```text save rate (N days) = customers who started a cancellation and are still subscribed N days later ÷ cancellation starts ``` Use 30, 60 and 90 days. Stripe's [retention performance](https://docs.stripe.com/billing/retention/performance) counts a save if the customer stays at least 7 days after accepting an offer, which is a short window for monthly plans. ### Win-back rate ```text win-back rate (N days) = churned customers who resubscribed within N days ÷ customers who churned in the cohort ``` ### Cohort retention A small table of logo or revenue retention by signup month. It is the best check that changes to onboarding or pricing actually worked. Step by step in [cohort retention analysis](/blog/cohort-retention-analysis/). ## Worked example (hypothetical numbers) A fictional company starts April with 500 customers and $50,000 MRR. | Movement | Customers | MRR | |---|---|---| | New | +40 | +$4,000 | | Reactivation | +5 | +$400 | | Expansion | | +$1,500 | | Contraction | | −$700 | | Churned (voluntary) | −15 | −$1,600 | | Churned (failed payment) | −10 | −$900 | | Ending | 520 | $52,700 | Check the balance: 50,000 + 4,000 + 400 + 1,500 − 700 − 1,600 − 900 = 52,700. It balances. ```text customer churn = 25 ÷ 500 = 5.0% gross rev churn = (2,500 + 700) ÷ 50,000 = 6.4% GRR = 93.6% NRR = (50,000 − 2,500 − 700 + 1,500) ÷ 50,000 = 96.6% involuntary share of churned MRR = 900 ÷ 2,500 = 36% ``` Reading it: a third of lost MRR came from failed payments, which is usually the cheapest churn to reduce. Churned customers paid $100 on average, the same as the base, so the gap between 5.0% customer churn and 6.4% gross revenue churn comes entirely from downgrades. That is worth a look at the contraction list. ## Definitions to write down Put these at the top of the dashboard, or in a linked note: 1. When a cancellation counts as churn: on request or at period end. Stripe lets you choose either for its analytics. 2. When a failed payment counts as churn: when the subscription is cancelled, or a fixed number of days after the last retry. 3. How pauses count: active, churned or excluded. 4. Whether trials and free plans are in the customer count (Stripe excludes them from active subscribers). 5. Whether MRR is before or after discounts. 6. Which currency and exchange rate date you use. A metric whose definition changes silently is worse than no metric. ## Common mistakes - **Mixing new-customer revenue into NRR.** It inflates retention. - **Reading one month.** Small bases swing. Show a 3-month trailing average next to the monthly value. - **No segment split.** Monthly consumer plans and annual B2B contracts behave differently; one blended number hides both. - **Counting accepted offers as saves.** Count only customers still subscribed later. - **Dashboards with numbers nobody owns.** Each row should have a person who acts when it moves. ## Doing this with NoChurn NoChurn reads your billing events (Stripe in one click; Chargebee, Recurly, Maxio, Zuora, Paddle, Lemon Squeezy, Polar, Braintree, Mollie, GoCardless, Razorpay, the App Store, Google Play, or any billing by REST API) and acts on the levers in row 4: smart retries and AI-written recovery emails for failed payments, cancel flows with an offer per reason and one-click cancel always visible, and win-back emails at day 30, 60 and 90 by cancel reason. Each customer gets a churn score from 0 to 100, and your own data sent by API shows churn drivers (correlation, not causation). Every feature is on every plan; the price depends only on MRR ([pricing](/pricing/)). --- # Cohort retention analysis for subscriptions, step by step Source: https://www.nochurn.sh/blog/cohort-retention-analysis/ A monthly churn rate mixes customers who joined last week with customers who have been around for three years. When it moves, you cannot tell whether the product changed or the customer mix did. A cohort table fixes that: it groups customers by when they started and follows each group over time. This guide builds one from scratch, from definitions to SQL to reading the result. All numbers are hypothetical. ## Step 1: define the cohort A cohort is a group of customers who share a start date. For subscriptions, use the **first paid period**, not the signup date: - Free trials and free plans are not revenue. If you start the clock at signup, trial drop-off gets mixed into paid retention. - Track trial-to-paid conversion separately ([how to measure it](/blog/trial-to-paid-conversion/)). Group by calendar month for most businesses. Weekly cohorts help if you have hundreds of new customers a week and want to see the effect of a change quickly; quarterly cohorts help if you have few. ### Customers who leave and come back Decide whether a returning customer joins a new cohort or stays in their original one. Stripe's Billing analytics keep them in the original cohort ([Stripe analytics docs](https://docs.stripe.com/billing/subscriptions/analytics), accessed November 2026). That is a reasonable default: it shows the cohort's revenue honestly over time. Write the choice down either way. ## Step 2: define "active" For each cohort and each month after the start, you need a yes or no per customer. Typical rule: the customer is active in month N if they have a subscription that is paid (or in a paid status) at the end of that month. Edge cases to settle before writing any query: | Case | Common choice | |---|---| | Past due, still retrying | Active until the subscription ends, or until a fixed number of days after the last retry | | Paused | Not active, but flagged separately so you can see pause returns | | Cancelled, still in the paid period | Active until the period ends | | Downgraded to a free plan | Not active for paid retention | | Annual plan, mid-term | Active; annual customers can only really churn at renewal | The last line matters: mixing monthly and annual plans in one table makes month 1 to 11 look artificially flat. Build separate tables per billing interval. ## Step 3: build the table Assume a table `subscription_months` with one row per customer per month they were active (customer_id, month). You can derive it from your billing data or from webhook events. ```sql with first_paid as ( select customer_id, min(month) as cohort_month from subscription_months group by customer_id ), activity as ( select f.cohort_month, (extract(year from age(s.month, f.cohort_month)) * 12 + extract(month from age(s.month, f.cohort_month)))::int as month_number, s.customer_id from subscription_months s join first_paid f using (customer_id) ) select cohort_month, month_number, count(distinct customer_id) as active_customers from activity group by cohort_month, month_number order by cohort_month, month_number; ``` Divide each row by the cohort's size at month 0 to get the retention percentage. Pivot month_number into columns for the familiar triangle. ### Example (hypothetical numbers) | Cohort | Size | M1 | M2 | M3 | M4 | M5 | |---|---|---|---|---|---|---| | January | 120 | 86% | 79% | 75% | 73% | 72% | | February | 140 | 84% | 77% | 74% | 72% | | | March | 110 | 88% | 82% | 79% | | | | April | 150 | 91% | 85% | | | | | May | 130 | 90% | | | | | The empty cells are not zero. They are months that have not happened yet. This is called right censoring, and averaging across a column that includes empty cells as zeros is a classic mistake. ## Step 4: read the table ### Read across a row A row is one cohort's life. Look for where the curve flattens. In the example, January loses 14 points in month 1, then 7, 4, 2 and 1. Most loss is early, then the curve levels off. A curve that keeps falling at the same pace month after month means the product does not have a stable core of users at that price. ### Read down a column A column compares cohorts at the same age. In the example, month-1 retention rises from 84 to 91% between February and April. If you changed onboarding in March, this is where you would see it. Check that the change holds in later columns before celebrating; sometimes better early retention only delays churn. ### Read the diagonal A diagonal is one calendar month across all cohorts. If every cohort drops in the same calendar month, look for an external cause: a price change, an outage, a payment processor issue, a seasonal pattern. ## Step 5: add revenue retention Logo retention counts customers. Revenue retention follows the cohort's MRR, which can rise above 100% when customers expand. ```text revenue retention (cohort, month N) = MRR in month N from customers in the cohort ÷ MRR in month 0 from the cohort ``` Show both. A cohort with 70% logo retention and 105% revenue retention lost many small customers and grew the rest. That is a different business from one where both numbers sit at 85%. See [NRR vs GRR](/blog/net-revenue-retention/) for the revenue-side definitions. ## Step 6: summarize across cohorts For a single "month N retention" figure, weight by cohort size and only include cohorts that have reached month N: ```text weighted month-3 retention = sum of active customers at M3 across cohorts that reached M3 ÷ sum of their starting sizes ``` In the example, cohorts January to March reached month 3: ```text active at M3: 120 × 0.75 + 140 × 0.74 + 110 × 0.79 = 90 + 103.6 + 86.9 ≈ 280.5 starting size: 120 + 140 + 110 = 370 weighted month-3 retention ≈ 280.5 ÷ 370 ≈ 75.8% ``` Use the actual counts rather than rounded percentages in practice; the decimals here come from rounding. ## Step 7: split by segment The most useful cohort tables split by something you can act on: - Billing interval (monthly vs annual) - Plan or price point - Acquisition channel or signup source - Payment method type - Whether the customer reached an activation milestone (see [activation and early churn](/blog/onboarding-activation-churn/)) Each split shrinks the cohorts. Keep the next rule in mind. ## Traps 1. **Small cohorts.** With 20 customers, one cancellation moves retention by 5 points. Show cohort size next to every row, or merge into quarters. 2. **Recent cohorts look better.** Month-1 numbers for last month's cohort may not include failed payments still in retry. Wait until the retry window has closed before reading the latest column. 3. **Mixed intervals.** Annual plans make monthly cohorts look flat. Separate them. 4. **Survivorship in segments.** If you segment by a behavior that takes time (for example, "used feature X"), customers who left early never had the chance to do it. Measure the behavior within a fixed early window, such as the first 14 days, for everyone. 5. **Correlation is not cause.** A segment that retains better may differ in many ways at once. Test changes with a holdout when you can. ## Doing this with NoChurn NoChurn reads subscription events from your billing tool (Stripe in one click, many others by connector or REST API) and lets you send your own customer attributes by API, such as signup source, plan or activation, to see which go together with churn (correlation, not causation). Each customer gets a churn score from 0 to 100 at signup and on every change. To act on what a cohort table shows, it runs failed payment recovery, cancel flows with an offer per reason and one-click cancel always visible, and win-back emails at day 30, 60 and 90. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # How to handle cancellation requests in Crisp Source: https://www.nochurn.sh/blog/crisp-cancellation-requests/ Crisp sits in the corner of your product, and that is exactly where a customer types "how do I cancel?". The chat is fast and personal, which makes it a good place to understand why someone is leaving, and a bad place to make them jump through hoops. The aim is a short, consistent exchange: ask once, offer once if it fits, then cancel and confirm. This guide shows how to set that up with Crisp's own features: segments, routing, message shortcuts and the Stripe integration. It relies on Crisp's help center articles on [message shortcuts](https://help.crisp.chat/en/article/how-can-i-use-shortcut-replies-canned-messages-1bmff5q/), [routing conversations to operators](https://help.crisp.chat/en/article/how-to-route-and-assign-conversations-to-operators-in-crisp-qjl2d2/), [automatic triage](https://help.crisp.chat/en/article/how-to-categorize-and-route-with-the-automatic-triage-feature-1sihmjf/), [classifying topics with Hugo AI](https://help.crisp.chat/en/article/how-to-classify-customer-support-topics-with-hugo-ai-cv1bd0/), the [Stripe integration](https://help.crisp.chat/en/article/how-to-connect-stripe-with-crisp-16tkifn/) and [chat transcripts](https://help.crisp.chat/en/article/how-to-send-and-manage-chat-transcripts-in-crisp-123u31k/) (all accessed November 2026). ## Start with the rule A customer who asks to cancel in chat has asked to cancel. You may ask why, and you may offer one alternative that fits their reason. If they say no, you cancel, in the same conversation, without sending them somewhere else. Cancelling should not be harder than signing up, which is the principle behind the rules summarized in [click-to-cancel rules for SaaS](/blog/click-to-cancel-rules/). ## Spotting cancellation conversations ### Segments In Crisp, segments are labels on conversations or contacts. They can drive routing rules, filters and automations. You can add them by hand, from your site with the chatbox SDK, or automatically. Create a `cancel-request` segment and use it on every cancellation conversation. ### Automatic tagging Crisp offers two automatic ways to add a segment when a conversation arrives: - **[Automatic triage](https://help.crisp.chat/en/article/how-to-categorize-and-route-with-the-automatic-triage-feature-1sihmjf/)** categorizes incoming conversations and can add a segment. Crisp notes that triage runs before routing rules. - **[Hugo topic detection](https://help.crisp.chat/en/article/how-to-classify-customer-support-topics-with-hugo-ai-cv1bd0/)**: you name a topic and describe the situation in plain words ("the customer wants to cancel, close their account or stop being billed"), and Hugo checks conversations it handles against that description. A conversation can match several topics, and a detected topic can add a segment automatically. Topic counts appear in Hugo's analytics. Both are approximations. Review the `cancel-request` segment regularly for conversations that were tagged wrongly, or missed. ### Routing Under Operator Routing in the inbox settings, [routing rules](https://help.crisp.chat/en/article/how-to-route-and-assign-conversations-to-operators-in-crisp-qjl2d2/) can use conversation segments as a condition, along with country, language, custom data, channel and email. Route `cancel-request` conversations to the people allowed to cancel and grant offers. Crisp documents that rules are evaluated from top to bottom and only run when routing rules are enabled, so place this rule above broad fallbacks. ## Looking up the account Before answering, look at the customer's billing. If you use Stripe, Crisp's [Stripe integration](https://help.crisp.chat/en/article/how-to-connect-stripe-with-crisp-16tkifn/) shows subscription status, billing history and payments in the conversation sidebar. Access is read-only: to change or cancel the subscription, you open the customer in Stripe (or use your own admin). Three things to check: 1. **When the current period ends**, so you can tell the customer when access stops. 2. **Whether the last payment failed.** A "cancel" message right after a decline is sometimes frustration with a card problem; a card update link may be what they actually need. See [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). 3. **Monthly or annual.** Annual customers often want to stop the next renewal, not lose access today. ## Shortcut replies Crisp's [message shortcuts](https://help.crisp.chat/en/article/how-can-i-use-shortcut-replies-canned-messages-1bmff5q/) are saved replies with a short trigger called a "bang" (for example `!cancel`). You create them in the inbox settings under Message Shortcuts, give each one a tag to keep them organized, and insert them by typing `!` in the composer. Shortcuts support placeholders such as the contact's first name, with a fallback if the field is empty. You can also [import and export shortcuts](https://help.crisp.chat/en/article/how-to-import-export-message-shortcuts-197bubz/) as a CSV with bang, text and tag columns, which makes it easy to keep them in sync across workspaces. A small set covers almost every case: **`!cancel`** (first reply) > Hi, I can cancel your subscription for you right now. Before I do, could you tell me what's not working for you? If you'd rather skip that, just reply "cancel" and I'll do it. **`!cancelpause`** (only for temporary reasons) > Got it. If it's a quiet period, I can pause your subscription instead: no charges until [date], and everything stays as it is. If you'd still rather cancel, say so and I'll do it now. **`!canceldowngrade`** (only when price is the reason and a cheaper plan fits) > Understood. The [plan] plan at [price] covers what you're using today. I can switch you from your next billing date. Or, if you prefer, I'll cancel now. Your call. **`!canceldone`** (confirmation) > Done. Your subscription is cancelled. You keep access until [date], and you won't be charged again. Thanks for having been with us. Choosing between the offers is covered in [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). ## Recording the reason and outcome Add two more segments when the conversation ends: one for the reason (`reason-price`, `reason-not-using`, `reason-missing-feature`, `reason-switching`, `reason-other`) and one for the outcome (`cancelled`, `paused`, `downgraded`). With both in place, you can filter conversations by segment and count, each month, which reasons lead to which outcomes. For a reasons list that is easy to act on, see [churn survey questions](/blog/cancellation-reasons-survey/). ## Keep the confirmation where the customer can find it A chat message scrolls away. Make sure the customer also has the confirmation in their inbox: - If Crisp's "Email users transcripts of conversations" setting is on, Crisp emails the customer a transcript after the conversation goes inactive, according to the [transcripts article](https://help.crisp.chat/en/article/how-to-send-and-manage-chat-transcripts-in-crisp-123u31k/). - You can also send a transcript manually from the conversation's action menu. - Your billing system's own cancellation email, if you send one, is a second record. That written confirmation protects both sides. If the customer later says they cancelled and were still charged, or the reverse, the dated conversation settles it. ## Mistakes to avoid - **Making the chat the only way to cancel.** Offer a cancel button in the product as well; chat should be one option, not a gate. - **Waiting for an operator.** If cancellation requests sit in a queue overnight, the customer may be charged at renewal in the meantime. Route them to someone who can act the same day. - **Promising what you cannot do.** Operators cannot cancel from the Crisp sidebar; make sure whoever handles these conversations can cancel in Stripe or your admin. - **Several offers in a row.** One offer, then cancel. ## Doing this with NoChurn NoChurn's Crisp connector is read-only, so segments, routing and shortcut replies stay in Crisp. NoChurn adds a cancel flow you can link to from a shortcut: reasons, one matching offer (discount, pause or plan change) and a one-click cancel that is always visible, hosted or headless through the API. Customers who leave can receive win-back emails at day 30, 60 and 90 based on their reason. NoChurn also reads Crisp conversations, matched to customers by email (doubtful matches are suggested, never merged automatically), for the churn score and as dated evidence if a cancelled customer later disputes a charge. See [NoChurn + Crisp](/integrations/crisp/). --- # How to use Crisp conversations as chargeback evidence Source: https://www.nochurn.sh/blog/crisp-chargeback-evidence/ Crisp often holds the most direct record of what a customer knew and did: the chat where they asked how to export their data, the email where they were told how renewals work, the conversation where they said the product was "exactly what we needed". When the same customer disputes a charge, those words can carry your response, if you can get them out cleanly and in time. This guide covers how to extract Crisp conversations, which ones help for which dispute reason, and how to format them for a dispute response on Stripe. It relies on Crisp's help center articles on [chat transcripts](https://help.crisp.chat/en/article/how-to-send-and-manage-chat-transcripts-in-crisp-123u31k/) and the [Stripe integration](https://help.crisp.chat/en/article/how-to-connect-stripe-with-crisp-16tkifn/), the [Crisp REST API reference](https://docs.crisp.chat/references/rest-api/v1/), and Stripe's [dispute evidence best practices](https://docs.stripe.com/disputes/best-practices), [dispute categories](https://docs.stripe.com/disputes/categories) and [How disputes work](https://docs.stripe.com/disputes/how-disputes-work) (all accessed November 2026). ## What Stripe asks for Stripe's dispute evidence has a customer communication field for messages relevant to the case. From Stripe's [best practices](https://docs.stripe.com/disputes/best-practices): - Combine all communication into one file; there is one upload per evidence type. - Include only relevant excerpts, not whole threads. - State clearly whether the customer tried to resolve the issue with you before disputing. - Do not rely on links, audio or video; banks will not review external content. - You submit once; nothing can be added afterwards. - Emails and chats support your case but do not verify the customer's identity, so in fraud disputes they need to be paired with other records. ## Which conversations help | Stripe dispute category | Useful Crisp messages | |---|---| | Subscription canceled | Chats where the customer asked about plans, billing or renewal and was told how to cancel; no cancellation request on record; activity after the date they say they cancelled | | Product not received | How-to questions, feature requests and thanks that show the customer used the service | | Product unacceptable | Your attempts to fix the problem and the customer's answers | | Credit not processed | Messages where a refund was promised, refused or already sent, with the policy explained | | Fraudulent | A conversation from the cardholder about the purchase before the dispute | For cancellation disputes, Stripe's [category guidance](https://docs.stripe.com/disputes/categories) also points to renewal notices and evidence of continued use after the claimed cancellation date, plus any message showing the customer was told about non-refundable terms or offered an alternative. ## Getting conversations out of Crisp ### From the inbox Crisp's [transcript article](https://help.crisp.chat/en/article/how-to-send-and-manage-chat-transcripts-in-crisp-123u31k/) describes two manual options from a conversation's action menu, under Transcript: - **Send** a transcript by email, to yourself or another address. - **Download** a local copy. Crisp also states that conversations cannot be exported as a native CSV from the app; bulk exports go through the API or a migration tool. A note on automatic transcripts: Crisp can email users a transcript of their conversation, controlled by the "Email users transcripts of conversations" setting under Email Settings. If that setting is on, the customer received a copy of the conversation. When it is relevant (for example, a conversation in which cancellation terms were explained), it is worth mentioning that the customer was sent the transcript, if you can confirm it for that conversation. ### Through the API The [REST API](https://docs.crisp.chat/references/rest-api/v1/) gives you what you need to automate this: - List the conversations linked to a contact, with a route that accepts the contact's email in place of its ID: `GET /v1/website/{website_id}/people/conversations/{people_id}/list/{page_number}`. - Fetch a conversation's messages with `GET /v1/website/{website_id}/conversation/{session_id}/messages`. It returns the most recent batch by default; page back with the `timestamp_before` parameter to get older messages. - Read the visitor's email from the conversation metadata. Each message has a sender and a timestamp, which is what makes a quote usable as evidence. Your API token needs the matching scopes (Crisp lists them per route). ## Matching the conversation to the disputed customer A Crisp contact is identified by email when the visitor gave one, or when your site sets it through the chatbox SDK. The Stripe customer has its own email. The two often match, but not always: the customer may chat from a work address and pay with a personal one, or a colleague may write on their behalf. Crisp's [Stripe integration](https://help.crisp.chat/en/article/how-to-connect-stripe-with-crisp-16tkifn/) shows the customer's subscription status, billing history and payments in the conversation sidebar, read-only. Changes to payments or subscriptions are made in Stripe. When the sidebar shows the right Stripe customer, that is a good sign the match is correct. When it shows nothing, check by hand before you use the conversation. An issuer reading a conversation from the wrong person stops trusting the rest of the file. ## Building the file 1. **Read the dispute.** Note the reason and the evidence due date (`evidence_details.due_by` on Stripe's [Dispute object](https://docs.stripe.com/api/disputes/object)). 2. **Collect the conversations** for that customer from signup, or from the last renewal, to the dispute date. 3. **Select the messages** that answer the dispute reason. Two to five excerpts are usually enough. 4. **Quote them with date, time, channel and author**, for example: "2026-08-03 16:20 UTC, chat, customer (sam@example.com): ..." Keep the customer's words exactly as written. 5. **Add a two-sentence summary** at the top: what the messages show, and whether the customer contacted support before disputing. 6. **Merge into one PDF** with your other communication (renewal reminders, cancellation confirmations), in date order. 7. **Pair with records** that conversations cannot prove alone: login and usage logs, cancellation policy, refund policy. ## What to avoid - **Internal notes.** Anything your team wrote for itself rather than to the customer is not customer communication; leave it out. - **Chatbot messages without context.** If an automated message explained renewal terms, say it was automated and when it was shown. - **Refunding during the dispute.** Stripe's [How disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says you cannot issue a refund outside the dispute process while a dispute is open. - **Arguing with the customer in the chat.** Stripe recommends keeping a record of communication during the dispute. Assume an issuer may read it. ## Preventing the next dispute from Crisp Many disputes start as a chat that did not get a clear answer. Add a segment such as `billing` to conversations that mention charges, refunds or cancellation (by hand, with a workflow, or with Crisp's automatic triage, depending on your plan), and give those conversations a short response target. A customer who gets a clear answer in the chat rarely calls their bank. ## Doing this with NoChurn NoChurn's Crisp connector is read-only: it never sends messages or changes conversations in Crisp. It reads conversations and matches them to customers by email; doubtful matches are suggested for you to confirm, never merged automatically. When a dispute opens on Stripe or Braintree, NoChurn gathers evidence automatically, including dated verbatim excerpts from Crisp conversations, cancel flow answers, emails sent and usage, and drafts a reply with AI. Nothing goes to the processor until someone on your team has reviewed it. See [NoChurn + Crisp](/integrations/crisp/). --- # How to catch churn signals in Crisp chats Source: https://www.nochurn.sh/blog/crisp-churn-signals/ Live chat is where churn signals are fastest and easiest to miss. A customer opens the chat widget, types "is there a way to export everything before I go?", gets an answer in two minutes, and the conversation is resolved. Nobody marks it as a warning. A month later the subscription is cancelled. This guide shows how to catch those moments in Crisp while they happen and keep them countable afterwards: labelling chats with segments, automating that with Automatic Triage and workflows, giving agents the right context with people data, and reading ratings. It relies on Crisp's own help center and developer docs: [segments](https://help.crisp.chat/en/article/getting-started-with-segments-88hhzw/), [Automatic Triage](https://help.crisp.chat/en/article/how-to-categorize-and-route-with-the-automatic-triage-feature-1sihmjf/), [workflows](https://help.crisp.chat/en/article/understanding-and-mastering-the-crisp-ai-chatbot-1boypme/), [message shortcuts](https://help.crisp.chat/en/article/how-can-i-use-shortcut-replies-canned-messages-1bmff5q/), [custom data](https://help.crisp.chat/en/article/what-is-custom-data-and-why-is-it-powerful-43jgi3/), [ratings](https://help.crisp.chat/en/article/how-to-monitor-user-ratings-thanks-to-crisp-1jj36o3/), [Analytics](https://help.crisp.chat/en/article/how-do-crisp-analytics-work-fwul5i/), [Hugo topic detection](https://help.crisp.chat/en/article/how-to-classify-customer-support-topics-with-hugo-ai-cv1bd0/) and the [web hooks reference](https://docs.crisp.chat/references/web-hooks/v1/) (all accessed November 2026). ## Why chat needs its own approach Compared with email tickets, chats are short, informal and often anonymous until the visitor is identified. Three consequences: 1. **The signal is often one sentence.** "Do you have a cheaper plan?" in the middle of a chat about something else. 2. **Agents need context during the chat, not after.** Knowing the visitor is a paying customer on the annual plan, renewing next week, changes how you answer. 3. **Chats close quickly.** If nothing is labelled before the conversation is resolved, it is lost in the history. So the setup below does two things: it gives agents context in the conversation, and it labels churn-related chats as they come in. ## Give agents context with people data Crisp separates conversation (session) data from contact (people) data ([custom data](https://help.crisp.chat/en/article/what-is-custom-data-and-why-is-it-powerful-43jgi3/)). Session data belongs to one conversation; people data stays on the contact profile across conversations. - From your website, the chatbox JavaScript SDK sets session data with `$crisp.push(["set", "session:data", ...])`. Crisp advises never putting secrets, access tokens or sensitive account data in frontend session data. - From your backend, the [REST API](https://docs.crisp.chat/references/rest-api/v1/) updates people data. Crisp distinguishes Update People Data, which merges keys into the existing data, from Save People Data, which replaces the whole object. For churn work, a handful of people data keys is enough: `plan`, `billing_interval`, `renewal_date`, `signup_date` and `customer_id`. Push them from your backend when the subscription changes. Do not push card details or anything you would not want an agent to read. ## Label churn signals with segments Crisp [segments](https://help.crisp.chat/en/article/getting-started-with-segments-88hhzw/) are simple labels you can attach to conversations or contacts. Crisp recommends them for simple classification and custom data for richer key/value details. They can be set manually by agents, from your website with the JavaScript SDK, through the REST API, or by workflows and Automatic Triage. A small set of conversation segments for churn: | Segment | Use it when the customer… | |---|---| | `churn-cancel` | asks how to cancel or says they are cancelling | | `churn-price` | asks for a discount or a cheaper plan, or says it is too expensive | | `churn-export` | asks to export data or delete their account | | `churn-competitor` | mentions comparing or moving to another tool | | `churn-bug` | reports a blocking problem for the second time or more | Conversation segments can be used in Inbox custom filters, which Crisp says are available on all plans. Contact segments feed advanced contact filters, which Crisp lists for the Essentials and Plus plans. Crisp Analytics also counts segments added to conversations. ## Automate the labelling ### Automatic Triage Crisp's [Automatic Triage](https://help.crisp.chat/en/article/how-to-categorize-and-route-with-the-automatic-triage-feature-1sihmjf/) applies rules when a conversation enters the Inbox. Each rule pairs filters with an action, such as adding segments or writing custom data, and rules run in an order you control. Crisp lists it on all plans, under Settings > Inbox Settings > Automatic Triage. A first rule set: 1. If the message contains "cancel", "unsubscribe" or "close my account", add `churn-cancel`. 2. If it contains "too expensive", "cheaper" or "discount", add `churn-price`. 3. If it contains "export" together with "account" or "data", add `churn-export`. These are filter-based rules, so they will make mistakes in both directions. Agents should correct segments during the chat; that is part of the job, not an extra. ### Workflows Crisp [workflows](https://help.crisp.chat/en/article/understanding-and-mastering-the-crisp-ai-chatbot-1boypme/) can set conversation segments as an action and react to a Segments Updated event. That lets you, for example, start a workflow when `churn-cancel` is set, to give the customer the direct link to cancel in your app. Make the cancel link the first thing the customer sees, not something behind questions. Crisp's workflow guide marks the older MagicReply AI block as deprecated; current docs point to Hugo, Crisp's AI Agent. Hugo has a [topic detection](https://help.crisp.chat/en/article/how-to-classify-customer-support-topics-with-hugo-ai-cv1bd0/) feature (AI Agent > Automate > Topic detection) that classifies what conversations are about. If you use Hugo, compare its topics with your segments now and then: they answer the same question from different directions. ## Answer consistently with shortcuts Crisp [message shortcuts](https://help.crisp.chat/en/article/how-can-i-use-shortcut-replies-canned-messages-1bmff5q/) are saved replies that agents insert by typing `!` in the composer. They are created under Settings > Inbox Settings > Message Shortcuts, can include placeholders such as custom data with fallback values, and are available from the Mini plan. Useful shortcuts for churn moments: - `!cancel`: the exact steps or direct link to cancel, and when access ends. - `!export`: how to export data. Answer this fully, even if it suggests the customer is leaving. Making it hard is not a retention strategy. - `!pause`: what a pause is and how to request one, for customers who mention a break. - `!plans`: the smaller plans, for customers who say the price is the problem. Keep promises out of shortcuts unless your billing system can keep them. ## Read ratings, then close the loop Crisp ratings go from 1 to 5 stars ([Analytics](https://help.crisp.chat/en/article/how-do-crisp-analytics-work-fwul5i/)). According to the [ratings article](https://help.crisp.chat/en/article/how-to-monitor-user-ratings-thanks-to-crisp-1jj36o3/), when ratings are enabled Crisp emails a rating request one hour after a chat ends, a new rating on the same conversation replaces the previous one, and you can filter contacts by rating to follow up. Analytics shows an overall average, an average for conversations handled only by automation or AI, a trend, and a list with comments and assigned agents. For real-time follow-up, Crisp's [web hooks](https://docs.crisp.chat/references/web-hooks/v1/) include a `session:sync:rating` event (Crisp lists it from the Essentials plan). A small integration can post every rating of 1 or 2 on a conversation with a `churn-` segment to your team channel. ## A weekly review 1. Filter the Inbox on each `churn-` segment for the past week. 2. Read the low-rated chats and their comments. 3. Export or pull the conversations through the API, with the contact's email and your `customer_id`. 4. Match them to your billing data: who cancelled, downgraded or had a failed payment afterwards. 5. Once a month, check which segments actually came before cancellations. Drop the ones that never do. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) covers the method. ## Doing this with NoChurn NoChurn's Crisp connector is read-only: it reads conversations and never sends messages, sets segments or changes contacts in Crisp. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. Matched chats feed the churn score (0 to 100) and the churn drivers view, and are kept as dated, verbatim evidence for chargeback responses on Stripe and Braintree, which NoChurn drafts with AI and sends only after you review them. Segments, triage rules, workflows, shortcuts and ratings stay in Crisp. See [NoChurn + Crisp](/integrations/crisp/). --- # Using Crisp conversation ratings to find customers about to churn Source: https://www.nochurn.sh/blog/crisp-csat-churn/ When a customer rates a support conversation one star, they are telling you something your billing system will only learn weeks later. Crisp collects those ratings natively, and it can push each one to your systems the moment it arrives. This guide explains how Crisp ratings work, how to get them out, how to tie them to the right paying customer, and how to check whether low ratings actually come before cancellations in your business. It sticks to Crisp's own documentation: [how to monitor user ratings and feedback](https://help.crisp.chat/en/article/how-to-monitor-user-ratings-feedbacks-1jj36o3/), [how to take advantage of customer feedback](https://help.crisp.chat/en/article/how-to-take-advantage-of-customer-feedback-f2nj9c/), [getting started with Crisp Analytics](https://help.crisp.chat/en/article/getting-started-with-the-crisp-analytics-fwul5i/), the [Web Hooks reference](https://docs.crisp.chat/references/web-hooks/v1/), the [REST API reference](https://docs.crisp.chat/references/rest-api/v1/) and [how to use webhooks](https://help.crisp.chat/en/article/how-to-use-webhooks-gv1qmo/) (all accessed November 2026). Some features depend on your Crisp plan; we note it where Crisp does. ## How Crisp ratings work ### Turning them on Ratings are a workspace setting: Workspace Settings › Email Settings › Email Behavior › General Options, "Enable Ratings (in chatbox and transcript emails)" ([monitoring ratings](https://help.crisp.chat/en/article/how-to-monitor-user-ratings-feedbacks-1jj36o3/)). The REST API exposes the same thing as a `rating` setting on the website. ### When customers are asked - **Chat conversations**: Crisp sends a rating email one hour after the chat ends. - **Email conversations**: there is no separate rating email; the rating block can appear in the transcript email instead. ### What is stored Each rating is attached to a conversation (Crisp calls it a session) and has a score from **1 to 5 stars** plus an optional comment. If a customer rates the same conversation again, the new rating replaces the old one rather than counting twice. Two things follow for churn analysis. Ratings are per conversation, not per customer, so you will need to roll them up. And the one-hour delay means the customer rates with some distance from the chat, which is good: a rating given an hour later is less likely to be pure frustration of the moment. ## Getting the ratings out Crisp offers four routes. Pick the one that fits what you want to do. | Route | What you get | Good for | |---|---|---| | **Analytics** | Overall Rating (average), Ratings Evolution (trend), and a Ratings report listing visitor, score, comment, assigned agent and a link to the conversation | Reading and spot checks | | **Analytics export** | Report data, with conversation IDs for some reports, but not full conversation content | A quick spreadsheet | | **Contacts search** | An advanced search that filters contacts by rating; the list can be exported or used as a campaign audience | Customer-level lists | | **`session:sync:rating` webhook** | Each new rating as it is submitted | Real-time alerts and your own data store | Crisp's [analytics article](https://help.crisp.chat/en/article/getting-started-with-the-crisp-analytics-fwul5i/) is clear that Analytics is not a full conversation export; for conversation content or metadata, it points to the REST API. ### The rating webhook The [Web Hooks reference](https://docs.crisp.chat/references/web-hooks/v1/) documents `session:sync:rating`, fired when "a user rating was just submitted for session". Its `data` includes `website_id`, `session_id`, `inbox_id` and a `rating` object with `stars` and `comment`. Webhooks are sent as JSON over HTTP POST; Crisp treats any 2xx response as delivered. Two practical notes from Crisp's help center: - The [feedback article](https://help.crisp.chat/en/article/how-to-take-advantage-of-customer-feedback-f2nj9c/) says customer feedback webhooks require the **Essentials** plan. - Crisp's articles disagree on where website hooks are configured: one says Website Settings › Advanced Configuration › Webhooks, the feedback article says Workspace Settings › Advanced Configuration. Look in both if you do not find it. The payload identifies the conversation, not the customer. To know who rated, look up the conversation by its `session_id` with the REST API and read the contact attached to it. ## Tying ratings to paying customers Ratings live in Crisp; cancellations live in your billing system. To compare them you need one customer key. 1. **Use email as the key.** Crisp contact profiles carry the customer's email. If your chatbox runs inside your app, set the signed-in user's email on the session so every conversation is linked to the right contact. Visitors who never gave an email cannot be matched. 2. **Store your billing ID on the contact.** Crisp's people data lets you save custom key/value data on a contact through the REST API (Update People Data merges keys; Save People Data replaces the whole object). A `customer_id` field avoids guessing later. 3. **Review the doubtful matches by hand.** A colleague writing for the account owner, a personal address for a work account, a shared inbox. For B2B accounts, decide whether any team member's rating counts for the account. 4. **Roll up per customer.** For each customer and period: number of rated conversations, lowest rating, average rating, and the comments. ## Do low ratings predict churn in your business? Do not assume they do. Test it on your own data: 1. **Build the customer list from billing**, with start date, cancellation date and whether the cancellation was voluntary or caused by a failed payment. Leave involuntary churn out of this analysis; a support chat did not expire anyone's card. 2. **Fix a window.** Take ratings from a set period (say 90 days) and look at cancellations in the following period. Without fixed windows, long-time customers just have more ratings. 3. **Group customers**: rated low (any 1 or 2), rated high only (4s and 5s), middle, contacted without rating, no contact. 4. **Compare the voluntary churn rate** of each group in the next period, with the number of customers next to every rate. 5. **Read the comments** of low-rated customers who later cancelled, and group them by theme. We go through this method, and its traps (small samples, response bias, rating the agent versus the product), in more detail in [do bad Intercom ratings predict churn?](/blog/intercom-csat-churn/); it applies to Crisp ratings unchanged. Whatever you find, it is a correlation: a low rating can be a symptom of a customer already on the way out. ## Acting on low ratings If low-rated customers do churn more, use Crisp's real-time signal: 1. **Route every 1 or 2 star rating to a person.** The `session:sync:rating` webhook can post to an internal channel with the comment and a link to the conversation. 2. **Check billing before replying.** A low rating right after a failed payment or an unexpected renewal is a billing problem; fix that first. 3. **Reply to the comment, not the score.** Acknowledge what the customer said and what you will do. 4. **Use the Contacts rating filter** to build a list of recent low-rated customers and review it weekly. 5. **Re-run the analysis each quarter** with the same windows, to see whether the gap between groups shrinks. ## Doing this with NoChurn NoChurn's Crisp connector is read-only. It reads conversations, satisfaction ratings, tags and dates, matches them to billing customers by email (a doubtful match is suggested for you to confirm, never merged on its own), and uses them in the 0–100 churn score and in the churn drivers analysis, which ranks the attributes most correlated with churn (correlation, not causation). Conversations can also become evidence in disputes, quoted as written. Answering customers, ratings settings and your workflows stay in Crisp; NoChurn never writes to it. See [NoChurn + Crisp](/integrations/crisp/). --- # How to tell customers about a failed payment in Crisp Source: https://www.nochurn.sh/blog/crisp-failed-payment-messages/ When a renewal fails, the customer usually does not know yet. If they talk to you through Crisp, the chatbox in your app is one more place to tell them, often a better one than an email that lands next to newsletters. This guide shows how to get payment failures into Crisp, how to message the customer with Crisp's automated campaigns, and how to handle what they reply. It sticks to Crisp's own documentation: [how to connect Stripe with Crisp](https://help.crisp.chat/en/article/how-to-connect-stripe-with-crisp-16tkifn/), [how to push Crisp profile events](https://help.crisp.chat/en/article/how-can-i-push-user-events-pxu9vm/), [how to use automated campaigns](https://help.crisp.chat/en/article/how-to-use-automated-campaigns-1ht44u5/), [getting started with segments](https://help.crisp.chat/en/article/getting-started-with-segments-88hhzw/), [how to push custom data](https://help.crisp.chat/en/article/how-can-i-automatically-set-custom-data-1xh7pqk/), the [$crisp methods for the Web Chat SDK](https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/dollar-crisp/) and the [REST API reference](https://docs.crisp.chat/references/rest-api/v1/) (all accessed November 2026). ## Crisp does not retry payments Crisp is a messaging tool. It does not charge cards, retry failed payments or update payment methods. Retries and the card update page stay in your billing system (Stripe, Chargebee and so on). What Crisp adds is a channel: a message in the chatbox or an email from your support address, and a place where the customer's answer arrives. So the setup has two halves: get the failure into Crisp, then decide what Crisp sends. ## Seeing billing in Crisp: the Stripe plugin If you bill with Stripe, Crisp has a [Stripe integration](https://help.crisp.chat/en/article/how-to-connect-stripe-with-crisp-16tkifn/): install it from Plugins › Stripe and authorize your Stripe account. It shows billing details and history in the conversation sidebar for conversations linked to a Stripe customer. Crisp's [Stripe page](https://crisp.chat/en/integrations/stripe/) describes it as read-only for agents; to change a subscription or payment, you open the customer in Stripe. This helps the agent answering "why was I charged?" or "my card failed". It does not, by itself, send anything to the customer. For that you need an event. ## Getting the failure into Crisp as an event Crisp profiles can receive **events**, and automated campaigns can be triggered by them ([pushing profile events](https://help.crisp.chat/en/article/how-can-i-push-user-events-pxu9vm/)). There are two ways to push one. ### From the chatbox (front end) The Web Chat SDK pushes an event on the current session with `$crisp.push(["set", "session:event", ...])`, giving the event name, optional data and a color ([$crisp methods](https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/dollar-crisp/)). Your app can push a `payment:failed` event when the signed-in user loads a page and their account is past due. ### From your server (REST API) The REST API has an **Add A People Event** route, `POST /v1/website/{website_id}/people/events/{people_id}`, which takes a text name, optional data and a color, with the `website:people:events` scope ([REST API reference](https://docs.crisp.chat/references/rest-api/v1/)). This fits better with billing webhooks: when your billing system reports a failure, your server pushes the event to the customer's Crisp profile. Crisp's campaign article describes the trigger event being pushed through the chatbox SDK. If you push from the server instead, test that it triggers your campaign before relying on it. ### Events vs data vs segments Crisp notes that it keeps only the **most recent events** for a contact, and recommends custom data for stable information ([pushing events](https://help.crisp.chat/en/article/how-can-i-push-user-events-pxu9vm/)). A clean split: | Crisp feature | Use it for | |---|---| | Event `payment:failed` | Triggering the campaign, once per failure | | Custom data (`billing_status: past_due`, `update_url`) | What an agent sees on the profile while it is true | | Segment `past-due` | Filtering the inbox and contacts list | Custom data is updated with Update People Data (merges keys) and segments with Update People Profile ([custom data](https://help.crisp.chat/en/article/how-can-i-automatically-set-custom-data-1xh7pqk/), [segments](https://help.crisp.chat/en/article/getting-started-with-segments-88hhzw/)). Remove both when the payment succeeds, or your team will chase customers who have already paid. ## Sending the message: automated campaigns Crisp's [automated campaigns](https://help.crisp.chat/en/article/how-to-use-automated-campaigns-1ht44u5/) send a chat message or an email when a matching event arrives. From Crisp's docs: - You set the trigger event name in the campaign's automation flow, and can add filters and a delay in minutes. - Event data can be used in the message as template variables, so the card update link can come from the event's data. - You can prevent the same campaign from reaching the same user more than once. - An email needs an email address on the session; Crisp can hold events until the email is known. - Email campaigns need a verified sending setup, such as a custom email domain or custom SMTP. - Automated campaigns are available on the Essentials and Plus plans. ### Chat or email? | Channel | Strength | Weakness | |---|---|---| | Chat message in the chatbox | Seen in context, while the customer is using your product | Only reaches people who come back to the app | | Email | Reaches everyone, including those who stopped logging in | Competes with everything else in the inbox | Use both, with different jobs: the email goes out on the failure, the chat message reaches the customer next time they are in the app. Keep your billing system's own failed payment emails in mind so the customer does not get three versions of the same news. ## Writing the message A failed payment message in a chatbox should be short enough to read in one glance: 1. **Say what happened, without blame.** "Your last payment for the Pro plan didn't go through." 2. **Give the consequence and the date.** "Your account stays active until 18 November." 3. **One link.** The card update page from your billing system, passed in the event data. 4. **An open door.** "Reply here if something is wrong; a person will answer." Avoid the decline reason in the message. Some reasons, such as a card reported lost or stolen, should never be shown to the customer, and "your bank declined it" is enough for the others. ## Handling the replies The advantage of Crisp over a no-reply email is that answers come back to your inbox. Prepare for the common ones: - **"I updated my card"**: check your billing system, and confirm only once the payment succeeds. - **"Why was I charged?"**: the Stripe sidebar shows the history; answer with the date and plan. - **"I wanted to cancel"**: cancel as asked, quickly and without hiding the option. Offering an alternative is fine; making the customer argue is not. - **"My company pays by invoice now"**: route to whoever handles billing changes. Keep track of these conversations so you can count them later, and clear the `past-due` segment once the account is settled. ## A checklist - [ ] Your billing system's retries and failure emails are configured. - [ ] Payment failures push a Crisp event, from the app or from your server. - [ ] `billing_status` data and a `past-due` segment are set on failure and removed on success. - [ ] An automated campaign sends one chat message and, if needed, one email per failure. - [ ] The message has one link, from the event data, and no decline reason. - [ ] Your team knows how to answer the common replies. ## Doing this with NoChurn NoChurn handles the billing side that Crisp does not: smart retries timed to the decline reason and to likely paydays (on Stripe), AI-written recovery emails that you review, and a hosted card update page you can link to from a Crisp message. Its Crisp connector is read-only, so it does not send Crisp messages for you; your campaigns stay in Crisp. It reads conversations and ratings, matched to customers by email (doubtful matches are suggested, never merged automatically), and uses them in the churn score and as evidence in disputes. See [NoChurn + Crisp](/integrations/crisp/). --- # How to build a customer health score that predicts churn Source: https://www.nochurn.sh/blog/customer-health-score/ A customer health score is a single number per customer that says how likely they are to stay. Many teams build one by picking a few signals, assigning weights that feel right and coloring accounts green, yellow and red. The result looks precise and often predicts little. This guide builds one the other way round: start from your own churn history, keep the signals that actually separate churned customers from retained ones, check the score against the past before trusting it, and connect every band to an action. All numbers are hypothetical. ## Step 1: define what the score predicts "Health" is vague. Pick a concrete outcome and a time horizon: ```text target = customer churns (voluntarily or through failed payment) within the next 90 days ``` Decide whether failed-payment churn counts. It usually should, because it is lost revenue either way, but the signals differ: product usage predicts cancellation; card expiry and past failures predict payment churn. Many teams keep one score with signals for both, or two sub-scores. The horizon should be long enough to act in. A score that predicts churn in the next 7 days leaves no time for anything but a last-minute offer. ## Step 2: list candidate signals Group them so you cover more than product usage: | Family | Example signals | |---|---| | Usage | Active days in last 30, key action count, trend vs previous 30 days, seats used ÷ seats paid | | Adoption | Activation milestone reached, number of features used, integrations connected | | Billing | Failed payments in last 90 days, card expiring before next renewal, plan downgrades, discount ending | | Relationship | Support tickets, unresolved tickets, satisfaction or NPS answers, champion left | | Profile | Plan, billing interval, company size, signup source, payment method type, tenure | Two rules for candidate signals: - **Measure each at a fixed point in time.** For a customer who churned in May, compute the signals as they were in February, not as they were when they left. Otherwise you are describing churn, not predicting it. - **Prefer trends to levels.** A customer who went from 20 active days to 5 is a different case from one who has always used the product 5 days a month. For which attributes to collect in the first place, see [how to find what predicts churn](/blog/predict-churn-with-customer-data/). ## Step 3: test each signal against history Take a past snapshot date, for example 6 months ago. For every customer active on that date, record each signal's value then, and whether they churned in the following 90 days. For each signal, split customers into groups and compare churn rates: ```text relative risk = churn rate in the group with the signal ÷ churn rate in the group without it ``` ### Example (hypothetical numbers) | Signal on snapshot date | Customers | Churned in 90 days | Churn rate | Relative risk | |---|---|---|---|---| | Active days in last 30 fell by half or more | 120 | 30 | 25.0% | 3.6 | | Active days stable or up | 880 | 61 | 6.9% | (reference) | | Failed payment in last 90 days | 60 | 15 | 25.0% | 3.1 | | No failed payment | 940 | 76 | 8.1% | (reference) | | Seats used under half of seats paid | 200 | 28 | 14.0% | 1.8 | | Seats used half or more | 800 | 63 | 7.9% | (reference) | Keep signals with a meaningful relative risk and enough customers in each group. A relative risk of 4 based on 6 customers is noise. Look at confidence intervals, and be wary when you test dozens of signals: some will look strong by chance. The [predict churn guide](/blog/predict-churn-with-customer-data/) covers sample size and multiple comparisons. ## Step 4: combine signals into a score ### Option A: points (simple, explainable) Give each kept signal points roughly in proportion to its relative risk, then cap the total at 100: ```text score = 100 − (points for each risk signal present) ``` Example weights from the table above: usage halved −30, failed payment −25, seats under half −10. A customer with a failed payment and halved usage scores 45. Points are easy to explain to a customer success team, which matters: a score nobody trusts gets ignored. ### Option B: a statistical model Logistic regression on the same snapshot data gives each signal a weight learned from history and accounts for signals that overlap (customers with halved usage may also be the ones with unused seats). It needs more data and someone who can check it. Whatever model you use, keep it explainable enough to say why a given customer scored low. ## Step 5: backtest before you trust it Score every customer as of an older snapshot date that the weights were not built on, then check what happened over the next 90 days. ### Churn rate by band | Band | Customers | Churned in 90 days | Churn rate | |---|---|---|---| | 0–39 | 80 | 26 | 32.5% | | 40–69 | 260 | 31 | 11.9% | | 70–100 | 660 | 30 | 4.5% | Hypothetical numbers again. What you want to see: churn rate falls steadily from the lowest band to the highest, and the bands are far apart. If the middle band churns like the top band, the thresholds are wrong or the score adds little. ### Capture ```text capture (lowest band) = churned customers in the lowest band ÷ all churned customers ``` Here 26 ÷ 87 ≈ 30%: the lowest band holds 8% of customers and 30% of churn. That is useful. But 70% of churn came from customers who did not look at risk, which tells you the score is a help, not a radar. Say that plainly to whoever uses it. ## Step 6: connect each band to an action A score without an action is a dashboard decoration. Write the playbook: | Band | Action | |---|---| | Low (0–39) | Personal outreach within a week; check billing; offer help or a better-fitting plan | | Middle (40–69) | Automated, specific nudge based on the signal that pulled the score down | | High (70–100) | Nothing extra; consider for expansion or referrals | Make the action depend on the reason, not just the number. A low score from a failed payment needs a card update link. A low score from falling usage needs help using the product. The same "we miss you" email for both helps neither. ## Step 7: maintain it - **Re-run the backtest every quarter.** Products, pricing and customers change; weights drift. - **Watch for the score changing behavior.** If the team works hard on low-score accounts, their churn drops and the signals look weaker next time. That is success, not a broken score; keep a small untouched holdout if you want to measure it. - **Log score changes.** "Score dropped from 72 to 41 because active days halved" is something a person can act on. "Score: 41" is not. ## Common mistakes 1. **Weights chosen by opinion.** Test against history. 2. **Signals measured at churn time.** That is description, not prediction. 3. **No backtest.** You do not know whether the score works. 4. **Too many bands.** Three is plenty if each has a different action. 5. **Treating correlation as cause.** A signal that predicts churn may not cause it. Customers who connect an integration may churn less because they were more committed to begin with. Test interventions with a holdout before investing heavily. ## Doing this with NoChurn NoChurn gives every customer a churn score from 0 to 100 at signup and on every change, using signals such as the payment method and payment history. You can send your own attributes and events by API (usage, activation, signup source, support data) and NoChurn shows which ones go together with churn: churn drivers, correlation not causation. To act on the score, it runs failed payment recovery, cancel flows with one offer per reason and one-click cancel always visible, and win-back emails at day 30, 60 and 90 by reason. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # Downgrade offers: when a cheaper plan beats a discount Source: https://www.nochurn.sh/blog/downgrade-offers/ When a customer says "it's too expensive," the reflex is a discount: 30% off for three months, please stay. Sometimes that is right. Often a cheaper plan is better for both sides. The customer pays for what they actually use, and you keep a customer whose price does not jump back up in three months. This guide is about that one choice. For the wider comparison of pauses, discounts, downgrades and calls, see [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). ## The difference in one table | | Discount | Downgrade | |---|---|---| | What the customer gets | Same plan, lower price for a while | Smaller plan, lower price for good | | What happens later | Price returns to normal | Price stays at the lower plan | | What it signals | "The price is negotiable" | "Here is a plan that fits you" | | Typical risk | Churn when the discount ends | Revenue lost on customers who would have stayed anyway | | Best for | A temporary squeeze | A lasting mismatch between plan and use | The key question is whether the customer's problem is **temporary** or **lasting**. A startup between funding rounds has a temporary problem. A team that bought ten seats and uses three has a lasting one. A discount on ten seats only delays the same conversation. ## Compare them on expected revenue You do not need a model to compare the two offers, just a simple formula and honest guesses that you later replace with your own data. ```text expected revenue over 12 months = sum over months m = 1..12 of price in month m × probability the customer is still subscribed in month m ``` ### Worked example (hypothetical numbers) A customer on a $100/month plan clicks cancel and picks "too expensive." Two possible offers: - **Discount:** 50% off for 3 months, then $100. - **Downgrade:** a $60/month plan with fewer seats. Suppose, purely for illustration, that customers who accept the discount stay with probability 90% per month during the discount and 75% per month after it ends, and that customers who downgrade stay with probability 92% per month throughout. Discount path, rounded: ```text months 1–3: $50 × (0.90, 0.81, 0.73) ≈ $122 months 4–12: $100 × 0.73 × (0.75, 0.56, 0.42, 0.32, 0.24, 0.18, 0.13, 0.10, 0.08) ≈ $100 × 0.729 × 2.77 ≈ $202 total ≈ $324 ``` Downgrade path: ```text $60 × (0.92 + 0.92² + … + 0.92¹²) = $60 × 0.92 × (1 − 0.92¹²) ÷ (1 − 0.92) ≈ $60 × 7.27 ≈ $436 ``` With these made-up probabilities, the downgrade earns more over the year, even though its monthly price is lower than the discount's eventual return to $100. Change the probabilities and the answer can flip: if customers really do recover after a short squeeze, the discount wins. The point is not these numbers. It is that you should run the comparison with your own retention after each offer, measured over months, not the acceptance rate on the day. ## When a downgrade is the better offer - **Usage is well below the plan.** Seats unused, limits far from reached, features never touched. Your product data tells you this before the customer says it. - **The customer has been on the plan for a while.** Long-tenured customers who say "too expensive" usually mean "too expensive for what I use now." - **A cheaper plan exists that still covers what they use.** If the only cheaper plan removes the one feature they rely on, it is not an offer. - **You do not want to train discount-seeking.** Customers talk. A cancel button that always produces 50% off becomes a known trick. ## When a discount is the better offer - **The problem is temporary.** Budget freeze, seasonal slowdown, a short gap between projects. - **The customer uses the full plan.** Downgrading would break their workflow. - **You only have one plan.** Then the alternatives are a discount, a pause or nothing. - **The customer is on the cheapest plan already.** Nothing to downgrade to. ## Which plan to show Show one plan, not the pricing page. Pick it from what the customer actually uses: 1. List the plans cheaper than the current one. 2. Remove plans that lack a feature the customer used in the last 30 days, or whose limits the customer exceeds. 3. Of what remains, show the most expensive one. It solves the price problem with the smallest drop in revenue. Then say exactly what changes: the new price, what they keep, what they lose, and when it starts. "Switch to Team for $60/month. You keep all projects and history. Seats go from 10 to 5; you currently use 3. Starts at your next renewal on December 12." ## Setting it up in Stripe A downgrade is a subscription update to a cheaper price. A few Stripe behaviours to know (from [Stripe's docs](https://docs.stripe.com/billing/subscriptions/change-price) and [customer portal configuration](https://docs.stripe.com/customer-management/configure-portal), accessed November 2026): - **Proration.** By default, an update creates prorations; for a downgrade that means a credit for unused time applied to the next invoice. Set `proration_behavior` to `none` if the change should simply take effect from the next period without a credit. - **Downgrade at period end.** The customer portal has an option to schedule downgrades for the end of the billing period instead of applying them immediately. Stripe implements this with a subscription schedule, and it only works between prices of the same product. - **Coupons.** If the customer had a coupon on the old plan, decide whether it carries over. A coupon calculated for the expensive plan may make the cheaper plan nearly free. Applying the downgrade at period end is usually fairest: the customer has paid for the current period on the bigger plan and keeps it until then. ## Guardrails - **Make acceptance instant.** One click, then a confirmation with the new price and date. No "our team will contact you." - **Keep "cancel now" visible.** A downgrade offer is an option, not a gate. Rules on cancellation in several places require the cancel path to stay clear; see [click-to-cancel rules](/blog/click-to-cancel-rules/). - **Let them upgrade back easily.** A downgraded customer who grows again should be able to return to the bigger plan in a click. - **Do not show it twice in a row.** A customer who downgraded last quarter and now cancels again has told you something; offer a pause or let them go. ## Measuring downgrade offers Downgrades do not stop all revenue loss; they turn churn into contraction. Measure both: | Metric | Formula | |---|---| | Downgrade acceptance rate | Downgrades accepted ÷ downgrade offers shown | | Downgrade retention (N days) | Downgraded customers still subscribed after N days ÷ downgrades accepted | | Revenue kept | MRR after downgrade, still active after N days | | Re-upgrade rate | Downgraded customers who later upgrade ÷ downgrades accepted | Then compare with a holdout of customers who saw no offer, or with customers offered a discount, on the same reason. Look at 30, 60 and 90 days. A downgrade that keeps 60% of a customer's revenue for a year beats a discount that keeps them for three months and then loses them. ## Doing this with NoChurn NoChurn's cancel flows ask why the customer is leaving and show one offer per reason: a discount, a pause or a plan change. A one-click "Cancel now" stays visible on every step. You can use the hosted modal or build the screens yourself with the headless API in your web, desktop or mobile app. Your own usage data, sent by API, feeds churn drivers (correlation, not causation) and a churn score from 0 to 100 for each customer. Customers who still leave get win-back emails at day 30, 60 and 90 based on their reason. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # Friendly fraud in subscriptions: why customers dispute charges they made Source: https://www.nochurn.sh/blog/friendly-fraud-subscriptions/ Most chargebacks on subscription businesses are not stolen cards. They are real customers, using their own card, disputing a charge for a service they signed up for. The industry calls this "friendly fraud"; Visa and Mastercard increasingly use the more precise term **first-party misuse**. Sometimes it is deliberate. Much more often it is confusion: a forgotten trial, an unrecognized descriptor, a cancellation the customer thought had worked. This guide explains why it happens in subscriptions, what the card networks have put in place to deal with it, and what you can do on your side. Network facts come from Visa's [friendly fraud explainer](https://corporate.visa.com/en/solutions/visa-protect/insights/friendly-fraud.html) and [Order Insight](https://corporate.visa.com/en/products/order-insight.html) page, Mastercard's [First-Party Trust](https://www.mastercard.com/us/en/business/cybersecurity-fraud-prevention/identity/first-party-trust.html) page and its [2024 article on first-party fraud](https://www.mastercard.com/us/en/news-and-trends/stories/2024/sellers-beware-getting-to-the-bottom-of-first-party-fraud.html), and Stripe's docs on [Visa Compelling Evidence 3.0](https://docs.stripe.com/disputes/api/visa-ce3) and [dispute prevention](https://docs.stripe.com/disputes/get-started/prevention) (all accessed November 2026). ## What counts as friendly fraud Mastercard describes first-party fraud as a cardholder making a legitimate purchase, receiving the goods or services, and then claiming it was fraud. The intent varies: | Type | What happened | Typical reason code family | |---|---|---| | Honest confusion | The customer does not recognize the charge or forgot the subscription | Fraud (Visa 10.4, Mastercard 4837 or 4863) | | Family or team use | A partner, child or colleague used the card | Fraud | | Cancel confusion | The customer believes they cancelled, or tried to | Cancelled recurring (Visa 13.2, Mastercard 4841) | | Buyer's remorse | The customer regrets the purchase and uses the bank instead of asking for a refund | Fraud or "not as described" | | Deliberate abuse | The customer uses the service and disputes to get it free | Any | The table matters because your response depends on it. Honest confusion is mostly a prevention problem. Deliberate abuse is an evidence problem. ## Why subscriptions attract it Subscription billing has features that make friendly fraud more likely than a one-off purchase: - **The charge comes without a fresh action.** A renewal happens months after the customer last thought about you. Nothing on their side marks the moment. - **The descriptor may not match the brand.** If the statement shows your legal entity name instead of the product name, the line looks foreign. See [billing descriptors](/blog/billing-descriptor-chargebacks/). - **Trials convert silently.** A free trial that becomes a paid plan is a classic "I never agreed to this" moment. Visa's [trial rules](https://usa.visa.com/dam/VCOM/global/support-legal/documents/visa-new-subscription-rules-flier.pdf) require a reminder with a cancel link at least seven days before the first charge after a trial or promotional period. - **Cancelling is hard to find.** If the cancel path is buried, the bank's dispute button is easier. That is how a cancel request becomes a 13.2 chargeback. - **Annual renewals are large.** A $600 surprise is far more likely to be disputed than a $10 one. - **Digital goods leave no parcel.** There is no delivery confirmation; your proof is logs. ## What the networks now offer merchants Both major networks have moved in recent years to give merchants a fairer hearing on first-party misuse. ### Visa Compelling Evidence 3.0 For card-absent fraud disputes (Visa reason code 10.4), Visa's Compelling Evidence 3.0 lets a merchant show that the same cardholder made earlier, undisputed purchases. Stripe's [CE 3.0 docs](https://docs.stripe.com/disputes/api/visa-ce3) list the core conditions: at least two prior undisputed transactions on the same payment method, between roughly 120 and 364 days before the disputed one, with matching identifiers such as IP address, device ID, customer account ID or address. For a subscription with a year of history, those prior renewals are exactly what you have. Details in [Visa Compelling Evidence 3.0 explained](/blog/visa-compelling-evidence-3/). ### Visa Order Insight [Order Insight](https://corporate.visa.com/en/products/order-insight.html) lets issuers and cardholders see purchase details when a cardholder asks about a charge, so the question can be answered before it becomes a dispute. On Stripe, this is part of the [dispute prevention](https://docs.stripe.com/disputes/get-started/prevention) product (Order Insights for Visa via Verifi, Consumer Clarity for Mastercard via Ethoca). ### Mastercard First-Party Trust Mastercard's [First-Party Trust](https://www.mastercard.com/us/en/business/cybersecurity-fraud-prevention/identity/first-party-trust.html) program lets merchants share data, either at authorization or during the dispute, to show that the cardholder made the purchase. Mastercard says merchants must send at least one data point from a device category and one from a delivery category to qualify for its liability protection. Participation is optional. Mastercard's [2026 press release](https://www.mastercard.com/news/europe/en/newsroom/press-releases/en/2026/mastercard-expands-first-party-trust-program-to-help-european-merchants-from-rising-friendly-fraud/) describes the rollout to Europe; check availability in your region with your processor. ## What you can control The network programs help with evidence. Most of the gains are still in your own product and billing. ### 1. Make the charge recognizable - Use a descriptor that matches the name customers know, and add a product suffix where your processor allows. - Send a receipt for every charge, with the amount, the plan, the next billing date and a link to manage or cancel. - Before annual renewals, send a reminder. Mastercard's [recurring billing standards](https://www.mastercard.us/content/dam/public/mastercardcom/na/global-site/documents/subscription_recurring-payments-and-negative-option-billing-merchants.pdf) require notices for subscriptions billed every six months or less frequently; see [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/). ### 2. Make cancelling easier than disputing A visible cancel button costs you a subscription; a dispute costs you the payment, a fee and some standing with the networks, and you lose the customer anyway. Offer a retention step if you want, but keep a one-click "cancel now" on every screen. See [cancel flow best practices](/blog/cancel-flow-best-practices/) and [click-to-cancel rules](/blog/click-to-cancel-rules/). ### 3. Make refunds easy to ask for Many friendly-fraud disputes are refund requests that went to the bank because the customer did not see another option. A clear "request a refund" path, or a support reply within a day, catches some of them. A refund you issue is cheaper than a chargeback you lose. ### 4. Collect the data that wins For subscriptions, the winning evidence is almost always the same, and you can only use it if you recorded it at the time: - IP address and device identifier at signup and at each login. - The customer account ID and email tied to each payment. - Acceptance of terms, with timestamp and the exact text shown. - Product usage with dates: logins, sessions, key actions. - The full history of cancellation attempts, including flows that were started and abandoned. - Every email and support conversation. Pass IP address, customer email and product descriptions on each payment where your processor supports it; Stripe's dispute prevention onboarding asks for these so CE 3.0 can work. ## When the customer is not friendly Some cases are genuinely abusive: a customer who used the product for months and disputes every charge. For these: 1. Stop future renewals on that card. Do not let the next charge add another dispute. 2. Defend the chargeback with the full usage record. The bank cannot see your logs unless you send them. 3. Keep the decision consistent. Write down your policy (for example, accounts with disputes are closed until the balance is settled) and apply it the same way every time. Do not treat every dispute as abuse. A customer who could not find the cancel button is telling you something about your product. ## A quick diagnostic Look at your last 20 disputes and ask, for each one: - Did the customer contact support first? If not, why not? - Was it the first charge after a trial, or an annual renewal? - Did the descriptor match the brand name? - Did the customer start a cancel flow before the charge? - Was there usage after the charge? Clusters in these answers tell you where to fix things. For the decision on each individual case, see [refund or fight](/blog/refund-or-fight-chargeback/). ## Doing this with NoChurn NoChurn's cancel flows keep a one-click cancel visible at every step and record each answer, so a cancellation never turns into "I tried to cancel". When a dispute arrives on Stripe or Braintree, NoChurn gathers the evidence automatically (cancel flow answers, emails sent, usage you send by API, help desk conversations read only) and drafts a reply with AI that a person reviews before it is sent. On Stripe, early fraud warnings come with a one-click refund. Every feature is on every plan; see [pricing](/pricing/). --- # How to add a cancel flow to GoCardless subscriptions Source: https://www.nochurn.sh/blog/gocardless-cancel-flow/ A Direct Debit customer who wants to leave has two ways out: your app, or their bank. If your app makes it hard, the bank is one phone call away, and a cancelled mandate or an indemnity claim is a worse ending for both of you than a clean cancellation. A good cancel flow on GoCardless is therefore partly about keeping customers and partly about making sure the ones who leave do it through you. This guide shows what GoCardless's Subscriptions API lets you do when a customer wants to cancel, and how to build a short cancel flow on top of it. It sticks to GoCardless's documentation: the [subscriptions API reference](https://docs.gocardless.com/docs/api-reference/subscription), the [subscription events reference](https://docs.gocardless.com/docs/api-reference/events/subscription) and the developer guide [Responding to mandate events](https://developer.gocardless.com/mandates/responding-to-mandate-events/) (all accessed November 2026). GoCardless's documentation site was not reachable from our research environment, so we checked endpoint behaviour against GoCardless's official API client libraries, such as [gocardless-pro-ruby](https://github.com/gocardless/gocardless-pro-ruby), which are generated from the same API schema and carry the same descriptions. ## What GoCardless gives you A GoCardless subscription creates payments on a mandate according to its schedule. Its `status` is one of: | Status | Meaning | |---|---| | `pending_customer_approval` | Waiting for customer approval | | `customer_approval_denied` | The customer did not approve it | | `active` | Will keep creating payments | | `paused` | Will not create payments | | `finished` | All scheduled payments have been created | | `cancelled` | Will no longer create payments | The four calls a cancel flow needs: ### Cancel `POST /subscriptions/:id/actions/cancel` immediately cancels the subscription; no more payments are created under it. It fails with `cancellation_failed` if the subscription is already cancelled or finished. A payment that was already created can only be cancelled while its status is `pending_submission` (`POST /payments/:id/actions/cancel`). Once it has been submitted to the banks, it will be collected or fail on its own. Check upcoming payments when you confirm the cancellation, so you do not promise "no further payments" when one is already on its way. ### Pause and resume `POST /subscriptions/:id/actions/pause` stops the subscription from creating payments: - Without `pause_cycles`, it is paused until you call resume. - With `pause_cycles`, it is paused for that number of cycles, and `upcoming_payments` still shows the later charge dates. - It works for subscriptions that run forever or collect a fixed `count` of payments, not for those with an `end_date`. It fails with `subscription_cannot_be_paused` when pausing is not possible. `POST /subscriptions/:id/actions/resume` restarts payment creation. The next payment's charge date is the subscription's `earliest_charge_date_after_resume`. This makes "pause instead of cancel" a native offer on GoCardless, which is not the case on every payment platform. ### Update `PUT /subscriptions/:id` changes fields such as the amount. GoCardless documents limits that matter for discount offers: - It fails with `number_of_subscription_amendments_exceeded` if the amount has already been changed 10 times. - It fails with `mandate_payments_require_approval` if the amount changes and the mandate requires approval. - It fails with `subscription_not_active` if the subscription is no longer active. A temporary discount therefore costs two amendments (down, then back up). Keep count. ### Leave the mandate alone Cancelling a subscription does not cancel the mandate. GoCardless's developer guide says to cancel a mandate only if the customer has explicitly asked for it. Keeping it means a returning customer can restart without setting up a new Direct Debit. If the customer asks you to cancel the Direct Debit itself, do it, and say so in the confirmation. ## Designing the flow ### 1. Ask why One question, a short list, one tap: - Too expensive - Not using it enough - Only needed it for a while - Missing something - Moving to another provider - Other Store the reason with the customer. You can also put it in the subscription's `metadata` before cancelling, so it stays with the GoCardless record. ### 2. One offer that fits the reason | Reason | Offer | On GoCardless | |---|---|---| | Only needed it for a while | Pause for 1 to 3 cycles | `pause` with `pause_cycles` | | Too expensive | A lower price for a few months | `update` the amount, schedule the update back (2 amendments) | | Not using it enough | A cheaper plan | `update` the amount, or cancel and create a new subscription on the same mandate | | Missing something, moving away | No discount; ask for detail | Nothing to change | State the exact effect before the customer accepts: for a pause, the date of the next charge; for a discount, the reduced amount, how many payments it covers and the amount after. ### 3. Cancel, always visible The cancel button belongs on every step, not after the offer. A customer who declines the offer is one click away from the confirmation, which says: - the subscription is cancelled; - whether any payment already submitted will still be collected, and its date; - until when they keep access; - whether the Direct Debit mandate stays in place (and how to cancel it too if they want). That last point matters on Direct Debit. A customer who sees a mandate still listed at their bank may cancel it there "to be sure". That is their right, and it is better that they know it is not needed. ## Wiring it up 1. **Load the subscription and its upcoming payments** when the flow opens. 2. **Use an idempotency key** on pause, resume and cancel calls (GoCardless's official client libraries handle idempotency conflicts on these actions), and disable buttons after the first click. 3. **Listen to subscription events** (see the [events reference](https://docs.gocardless.com/docs/api-reference/events/subscription) for the full list of actions) so your app stays in sync when changes come from the dashboard or GoCardless itself, for example when a mandate is cancelled and its subscriptions with it. 4. **Schedule the follow-ups** your offers need: the update back to full price, the end of an indefinite pause, a reminder before a paused subscription restarts. 5. **Log every step**: reason, offer shown, answer, cancellation time. If an indemnity claim arrives later, this record helps you understand what went wrong. ## Measure the right thing - Offers accepted, by reason. - Paused subscriptions that resume and are still paying three months later. - Cancellations through your flow compared with mandates cancelled at the bank. If many customers leave through their bank, the cancel option is too hard to find. ## Doing this with NoChurn GoCardless keeps the subscription, the mandate and collection. NoChurn adds the cancel flow: reasons, an offer that fits each reason and a one-click cancel that is always visible, hosted by NoChurn or built into your own interface with the headless API. On GoCardless, a cancellation ends the GoCardless subscription and the mandate stays as the customer chooses. Cancel reasons drive win-back emails at day 30, 60 and 90 and feed the churn score. See [NoChurn + GoCardless](/integrations/gocardless/). --- # GoCardless charge-backs and indemnity claims explained Source: https://www.nochurn.sh/blog/gocardless-chargebacks-indemnity-claims/ Direct Debit puts the customer in a strong position. Under schemes such as Bacs in the UK and SEPA in Europe, a customer can ask their bank to return a payment, and in many cases the bank does it without asking you. On GoCardless this shows up as a **charge-back** (the bank side calls it an **indemnity claim**). It is not a card dispute: in most cases there is no evidence to submit and no decision to wait for. This guide explains how long customers can claim, how a charge-back moves through GoCardless's payment events, how it differs from a late failure, what GoCardless lets you challenge, and what to do about the customer. It sticks to GoCardless's documentation: the [payment events reference](https://docs.gocardless.com/docs/api-reference/events/payment), the help centre articles [Bacs Chargeback process](https://support.gocardless.com/hc/en-us/articles/115002878369-Bacs-Chargeback-process), [SEPA Chargeback process](https://support.gocardless.com/hc/en-gb/articles/115002883945-SEPA-Chargeback-Process) and [Challenge Chargebacks FAQ](https://support.gocardless.com/hc/en-au/articles/17143485669148-Challenge-Chargebacks-FAQ), and GoCardless's guides on the [Direct Debit Guarantee](https://gocardless.com/direct-debit/guarantee) and [SEPA customer protection](https://gocardless.com/guides/sepa/protection) (all accessed November 2026). GoCardless's sites were not reachable from our research environment, so we relied on these pages as indexed by search and on the descriptions in GoCardless's official API client libraries; check the live pages before quoting a deadline to anyone. ## How long customers can claim The rules come from the schemes, and GoCardless describes them as follows: | Scheme | Customer's right | |---|---| | Bacs (UK) | Under the Direct Debit Guarantee, GoCardless says there is currently no time limit on indemnity claims. | | SEPA Core | A no-questions-asked refund within 8 weeks of the debit. For unauthorised payments, claims up to 13 months. | | SEPA B2B | No refund for authorised payments. Claims for unauthorised payments (where the payer shows they never agreed to a B2B mandate) up to 13 months. | GoCardless supports other schemes too (ACH, PAD, BECS, Autogiro, Betalingsservice and others), each with its own rules. Check GoCardless's help centre for the scheme you collect on. The practical point: on Bacs especially, a payment you collected long ago is not final. Your records of what the customer agreed to and used should be kept for as long as the customer could claim. ## What a charge-back looks like in the API A charged-back payment ends in the `charged_back` status, which GoCardless's API defines as "the payment has been charged back". The payment events tell the story: | Payment event action | What happened | |---|---| | `charged_back` | The customer asked their bank to refund the payment under the Direct Debit Guarantee (or the scheme's equivalent), and it was returned to them. | | `chargeback_cancelled` | The customer's bank cancelled the charge-back request, which GoCardless says is almost always at the customer's request. | | `chargeback_settled` | The payment had already been paid out to you, and the amount has now been debited from a payout. | Each event carries `details.cause`, `details.origin` and, for bank-originated events, a scheme-specific `details.reason_code`. GoCardless warns that reason codes are inconsistent between banks, so use them for investigation, not for automation. Your finance side will see `chargeback_settled` as a deduction in a payout. Your customer side should react to `charged_back`, which comes first. ## Late failures are not charge-backs A payment can also fail **after** it was confirmed. GoCardless's API notes that payments can fail after being confirmed if the bank sends the failure message late. That is a **late failure**, not a claim: the money was never really collected. It has its own event, `late_failure_settled`, when the amount is taken back from a payout. The difference matters for how you talk to the customer: - **Late failure**: a payment problem. Treat it like any failed payment: tell the customer, and collect again if the mandate is still active. - **Charge-back**: a customer decision (or a mistake on their side, such as not recognising the debit). Do not collect again before talking to them. GoCardless's developer documentation also recommends waiting a minimum of 7 business days after a payment is confirmed before refunding it to a customer, to allow for late failures. ## Can you challenge a charge-back? Usually not. GoCardless's help centre describes a **Challenge Chargebacks** feature, part of its Protect+ offering, with conditions: according to the [FAQ](https://support.gocardless.com/hc/en-au/articles/17143485669148-Challenge-Chargebacks-FAQ), on Bacs it is limited to UK customers on the Pro plan, and you have 7 working days to submit evidence. For SEPA Core, GoCardless describes the first 8 weeks as a no-questions-asked refund, so for an authorised payment in that window there is nothing to argue. Even where a challenge is possible, the customer still has their bank on their side and a relationship with you that a challenge will not improve. Save challenges for clear abuse: a customer who keeps using the service, received what they paid for and claims anyway. ## What to do when a charge-back arrives 1. **Mark the customer.** Record the payment, amount, cause, date and the subscription it belongs to. 2. **Hold further collection.** Do not let the next scheduled payment go out before you know what happened. Pausing the subscription (GoCardless's `pause` action works on subscriptions that run indefinitely or for a fixed count) keeps your options open without cancelling anything. 3. **Check the mandate.** Look at its status and recent mandate events. A charge-back often comes with, or just before, a cancelled mandate. 4. **Write to the customer, without accusing them.** "We received a refund request from your bank for your payment of X on date Y. Was this intended?" Offer three ways forward: they meant to cancel (confirm the cancellation), they did not recognise the debit (explain it and offer to continue), or it was a mistake (ask how they want to settle the amount). 5. **Collect again only with agreement.** If the customer wants to continue or pay what is owed, take a payment on an active mandate after they have agreed to it, or set up a new mandate. 6. **Decide on access.** Whatever your terms say about unpaid periods, apply them consistently. ## Prevent the next one Most Direct Debit claims are avoidable: - **Make the debit recognisable.** Use a payment description and reference that the customer will connect with you on their bank statement. - **Send advance notices that are easy to read.** GoCardless's help centre explains its [payer notifications](https://support.gocardless.com/hc/en-us/articles/17144912552220-Payer-notifications); if you send your own, make the amount and date obvious. - **Remind before annual or price-changed renewals.** A large unexpected debit is a classic claim. - **Make cancelling easy.** A customer who can cancel in your app has no reason to go to their bank. See [how to add a cancel flow to GoCardless subscriptions](/blog/gocardless-cancel-flow/). - **Refund when you would anyway.** A refund you initiate is cleaner than a claim. ## Doing this with NoChurn GoCardless and the banks handle charge-backs; NoChurn does not submit anything for them. Direct Debit claims show up on the customer's timeline in NoChurn and count in the churn score from 0 to 100, since there is no evidence to send. Where NoChurn helps is before a claim: a cancel flow with a one-click cancel always visible, recovery emails that you review when a mandate is cancelled, and win-back emails at day 30, 60 and 90 based on the cancel reason. See [NoChurn + GoCardless](/integrations/gocardless/). --- # How to recover failed Direct Debit payments with GoCardless Source: https://www.nochurn.sh/blog/gocardless-failed-payments/ A failed Direct Debit is not a declined card. There is no card to update, the bank answers days after you asked for the money, and the customer can sometimes claim the money back long after it left their account. Recovery on GoCardless follows its own rules, and most of them come from the bank schemes (Bacs, SEPA, ACH and others) rather than from GoCardless itself. This guide explains why GoCardless payments fail, how retries work, what to do when a mandate is cancelled or expired, and how charge-backs (indemnity claims) are handled. It sticks to GoCardless's own documentation: the [payment events reference](https://docs.gocardless.com/docs/api-reference/events/payment), the [mandate events reference](https://docs.gocardless.com/docs/api-reference/events/mandate), the [Success+ guide](https://docs.gocardless.com/docs/optimise/reduced-failed-payments-with-success-plus), the help centre articles on [payment failures](https://support.gocardless.com/hc/en-gb/articles/360001467265-Payment-failures) and [which failed payments Success+ can retry](https://support.gocardless.com/hc/en-gb/articles/27873170789916-Which-failed-payments-can-be-retried-with-Success), and the descriptions in GoCardless's official API client libraries (all accessed November 2026). ## How a Direct Debit payment moves A GoCardless payment goes through a series of statuses. The API documents these values for `status`: | Status | Meaning | |---|---| | `pending_submission` | Created, not yet submitted to the banks | | `submitted` | Submitted to the banks | | `confirmed` | Confirmed as collected | | `paid_out` | Included in a payout to you | | `failed` | The payment failed to be processed | | `charged_back` | The payment has been charged back | | `cancelled` | The payment was cancelled before collection | Two details matter for recovery: 1. **Failures arrive after the charge date.** GoCardless's help centre says failure reports usually arrive one working day after the charge date. You find out a little later than with cards, and your dunning should start from the failure event, not from the charge date. 2. **A confirmed payment can still fail.** The API reference notes that payments can fail after being confirmed if the bank sends the failure message late. Do not treat `confirmed` as final when you grant or remove access. ## Why Direct Debit payments fail Every failure comes with an event. On payment events, GoCardless sends a `details` object with: - `cause`: GoCardless's simplified, predictable key for what happened. - `origin`: who triggered the event, for example `bank`, `gocardless`, `api` or `customer`. - `reason_code`: when the bank is the origin, the scheme-specific code the bank reported. GoCardless warns that it can be inconsistent between banks, so build your logic on `cause`, and keep `reason_code` for investigation. - `description`: a human-readable text, which GoCardless says can change without notice. The causes listed in the [payment events reference](https://docs.gocardless.com/docs/api-reference/events/payment) include `insufficient_funds`, `refer_to_payer`, `mandate_cancelled`, `bank_account_closed`, `invalid_bank_details`, `direct_debit_not_enabled`, `bank_declined_payment`, `payment_stopped` and `account_blocked_for_any_financial_transaction`. They fall into three groups: | Group | Causes | What to do | |---|---|---| | Not enough money | `insufficient_funds`, `refer_to_payer` | Retry, ideally after the customer is likely to have been paid. GoCardless describes `refer_to_payer` (a Bacs code) as almost always meaning insufficient funds. | | Mandate gone | `mandate_cancelled` | Do not retry. The customer needs a new mandate. | | Account problem | `bank_account_closed`, `invalid_bank_details`, `direct_debit_not_enabled`, `account_blocked_for_any_financial_transaction` | Do not retry. Ask for other bank details or another payment method. | | Stopped by the customer or bank | `payment_stopped`, `bank_declined_payment` | Contact the customer before trying again. A stopped payment may be a sign they want to leave. | ## Retries with Success+ GoCardless's own retry product is **Success+**. According to the [Success+ guide](https://docs.gocardless.com/docs/optimise/reduced-failed-payments-with-success-plus) and the [help centre](https://support.gocardless.com/hc/en-gb/articles/360013070139-Switching-on-intelligent-retries): - It is switched on in the GoCardless dashboard by an admin user, with settings per scheme. - API integrations must also opt each payment in by sending `retry_if_possible: true` when creating payments, subscriptions or instalment schedules. The default is `false`. - By default it retries up to 3 times within 4 weeks. You can set your own window in calendar days, and retries happen on business days inside it. - It only retries failures it judges retryable, mainly failures for lack of funds. Cancelled mandates, closed accounts and direct bank refusals are not retried. The [list of retryable codes](https://support.gocardless.com/hc/en-gb/articles/27873170789916-Which-failed-payments-can-be-retried-with-Success) is per scheme. - For Bacs, the payer must be told the retry date before the payment is taken. - Each retry is a new payment attempt for billing purposes, so check your GoCardless pricing. On the failure event, the field `will_attempt_retry` tells you whether Success+ will retry. When it is `false`, `not_retried_reason` explains why: `failure_filter_applied` (GoCardless expects the retry to fail) or `other`. GoCardless's help centre also notes that not every software partner supports Success+. If your billing runs through a partner app, check there first. ## Manual retries through the API Without Success+, or for a payment it will not retry, you can retry yourself with `POST /payments/:id/actions/retry`. The API documents three rules: 1. The underlying mandate must be active. 2. A payment can be retried up to 3 times. 3. The call fails with `retry_failed` if the payment has not failed. After the call you receive a `resubmission_requested` event, then the same sequence as a new payment: `submitted`, followed by `confirmed` or `failed`. The retry needs a new charge date, so choose it on purpose. For an `insufficient_funds` failure, a date just after a common payday in the customer's country is a reasonable choice. Retrying the next day is usually not. ### Tell the customer before you retry Unlike a card retry, a Direct Debit retry is visible on the customer's bank statement, and for Bacs GoCardless requires advance notice of the retry date. A good message: 1. Says the payment did not go through, with the amount and the plan. 2. Gives the date of the next attempt. 3. Offers a way to change bank details or pay another way if the account will not have funds. 4. Is sent from an address that a person reads. ## Cancelled and expired mandates A payment needs an active mandate. The API documents these mandate statuses, among others: `active`, `suspended_by_payer`, `cancelled`, `expired` (expired due to dormancy), `failed`, `consumed` and `blocked`. Watch mandate events (`resource_type: mandates`) as closely as payment events: a cancelled mandate means every future payment on it will fail. When a mandate is cancelled by the customer at their bank, a payment against it fails with the cause `mandate_cancelled`. Do not retry; you need a new mandate. Steps: 1. **Find out why.** A customer who cancels their Direct Debit at the bank may simply have changed bank, or may want to stop paying. The email should ask, not assume. 2. **Send a link to set up a new mandate.** On GoCardless, a new mandate is collected through a Billing Request, usually with a hosted Billing Request Flow. Send the customer that link, not a form asking for bank details by email. 3. **Recreate the payment** on the new mandate once it is active. GoCardless's API also has a `reinstate` action for cancelled or expired mandates (up to 10 times per mandate). It resubmits the mandate to the banks and you then receive `submitted`, followed by `reinstated` or `failed`, up to two working days later. Use it only when you know the mandate should still be valid. When the customer cancelled on purpose, reinstating it without asking is not the right move. ## Charge-backs (indemnity claims) Direct Debit gives customers strong refund rights, and they differ by scheme. GoCardless's help centre and guides describe them: | Scheme | Customer's right to claim | |---|---| | Bacs (UK) | Under the Direct Debit Guarantee, GoCardless says there is currently [no time limit](https://support.gocardless.com/hc/en-us/articles/115002878369-Bacs-Chargeback-process) on indemnity claims. | | SEPA Core | [No-questions-asked refund within 8 weeks](https://gocardless.com/guides/sepa/protection) of the debit; up to 13 months for unauthorised payments. | | SEPA B2B | No refund for authorised payments; claims for unauthorised payments up to 13 months. | A claimed payment moves to `charged_back` and the amount is taken back from you. Unlike card disputes, there is usually no evidence process. GoCardless describes a chargeback challenge feature in its [help centre](https://support.gocardless.com/hc/en-au/articles/17143485669148-Challenge-Chargebacks-FAQ), with plan and scheme conditions; check whether it applies to you. What you can control is what happens before the claim: - **Make cancelling easy.** A customer who cannot find how to cancel will stop the Direct Debit at their bank or file a claim. A clear cancel button on your side costs less. - **Send advance notices that are easy to read.** A customer who forgot about a renewal is more likely to claim. - **Treat a charge-back as a cancellation signal.** Stop future payments on that mandate until you have spoken to the customer. ## Webhooks to listen to A minimal recovery integration on GoCardless follows these events: | Resource | Action | Why | |---|---|---| | `payments` | `failed` | Start recovery; read `cause`, `will_attempt_retry` | | `payments` | `resubmission_requested`, `submitted`, `confirmed` | Track a retry | | `payments` | `charged_back` | Indemnity claim; pause and contact the customer | | `mandates` | `cancelled`, `expired` | Ask for a new mandate before the next payment | Remember that one failure can produce several events (for example a mandate cancelled and its pending payments cancelled), so deduplicate on the event ID and group by customer before emailing anyone. ## Doing this with NoChurn NoChurn connects to your GoCardless account, imports customers, mandates, subscriptions and payments, and follows GoCardless webhooks. When a payment fails, it sends AI-written recovery emails that you review, timed for Direct Debit, and when a mandate is cancelled the email links the customer to set up a new one. Collection, retries and Success+ stay with GoCardless, and charge-backs show up on the customer timeline, since Direct Debit claims have no evidence to send. NoChurn also adds cancel flows with a one-click cancel always visible, win-back emails at day 30, 60 and 90 based on the cancel reason, and a churn score. See [NoChurn + GoCardless](/integrations/gocardless/). --- # What to do when a GoCardless mandate is cancelled Source: https://www.nochurn.sh/blog/gocardless-mandate-cancelled/ On GoCardless, every payment hangs on a mandate: the customer's authorisation to debit their account. When the mandate is cancelled, nothing else works. Pending payments stop, subscriptions on it end, and no retry can help. It is the most important event to handle well in a Direct Debit business, and also the one where an automated "please update your details" email is most likely to be wrong. This guide covers why mandates end, what happens to the subscriptions and payments on them, how to read the cause, and how to get a new mandate when the customer wants to keep paying. It sticks to GoCardless's documentation: the [mandate events reference](https://docs.gocardless.com/docs/api-reference/events/mandate), [subscription events reference](https://docs.gocardless.com/docs/api-reference/events/subscription), the developer guide [Responding to mandate events](https://developer.gocardless.com/mandates/responding-to-mandate-events/) and the help centre article on [mandate statuses](https://support.gocardless.com/hc/en-gb/articles/17144912089884-Mandate-statuses) (all accessed November 2026). GoCardless's documentation site was not reachable from our research environment, so we also checked field and endpoint descriptions against GoCardless's official API client libraries (for example [gocardless-pro-ruby](https://github.com/gocardless/gocardless-pro-ruby)), which are generated from the same API schema. For the payment side of recovery, see [how to recover failed Direct Debit payments with GoCardless](/blog/gocardless-failed-payments/). ## Mandate statuses GoCardless documents these mandate statuses: | Status | Meaning | |---|---| | `pending_customer_approval` | Not yet signed by a second signatory | | `pending_submission` | Not yet submitted to the customer's bank | | `submitted` | Submitted, not yet processed | | `active` | Set up by the customer's bank; payments can be taken | | `suspended_by_payer` | Suspended by the payer | | `failed` | Could not be created | | `cancelled` | Cancelled | | `expired` | Expired due to dormancy | | `consumed` | Used and not reusable (only for schemes authorised per payment) | | `blocked` | Blocked; payments cannot be created | Only `active` mandates can be charged, and a manual payment retry requires an active mandate. Each mandate also has a `next_possible_charge_date`, which matters when you set up a replacement and want to know when you can collect. ## Why a mandate gets cancelled The `cancelled` event comes with `details.cause`, `details.origin` and, when the bank is the origin, `details.reason_code`. Use `cause` for your logic. GoCardless warns that `reason_code` is scheme-specific and can be inconsistent between banks. GoCardless's developer guide lists several causes for a cancelled mandate, including: - **`bank_account_closed`**: the customer's bank account was closed. - **`invalid_bank_details`**: the bank details are not valid. - **`mandate_cancelled`**: the mandate was cancelled. On the last one, GoCardless's pages are not consistent with each other. The [mandate events API reference](https://docs.gocardless.com/docs/api-reference/events/mandate) describes `mandate_cancelled` as a mandate cancelled by the customer or their bank, while the older developer guide uses it for cancellations made through the dashboard or API and describes a bank-side cancellation by the customer differently. Do not rely on `cause` alone to tell "the customer cancelled at their bank" from "we cancelled it": read `origin` too (`bank`, `api`, `gocardless`, `customer` and so on). An `api` origin means your own system, or an app you connected, did it. An **expired** mandate is different: GoCardless expires mandates due to dormancy. Nobody decided to stop; the mandate simply was not used. ## What happens to payments and subscriptions A cancelled mandate takes things with it: - **Pending payments.** GoCardless's API reference for the cancel endpoint says cancelling a mandate cancels all associated cancellable payments. A payment that is already submitted to the banks can still be collected or fail on its own. - **Subscriptions.** GoCardless's subscription events reference shows subscriptions being cancelled because their mandate was cancelled, with causes such as `mandate_cancelled`, `bank_account_closed` and `invalid_bank_details`. - **Later payments.** A payment against a cancelled mandate fails with the cause `mandate_cancelled`. Retrying it is not possible: retries require an active mandate. So one cancellation produces several events: the mandate, the subscription, and possibly payments. Group them by customer before sending any email, or the customer may get three messages about one thing. ## Decide what the cancellation means Before writing to the customer, sort the cancellation into one of three cases: | Case | Signals | Right response | |---|---|---| | Customer changed or closed their account | `bank_account_closed`, or a cancellation followed by the customer saying they moved banks | Ask for new bank details through a new mandate | | Customer wants to stop paying | Cancelled at the bank, often near a renewal; no reply | Treat it as a cancellation: confirm it, ask why, end access cleanly | | Your side cancelled it | `origin` is `api` or the dashboard | Check your own logs before telling the customer anything | GoCardless's developer guide is clear on one point: only cancel a mandate yourself if the customer has explicitly asked for it. ## Setting up a new mandate When the customer wants to continue: 1. **Email once, plainly.** Say the Direct Debit has been cancelled, that no further payments can be taken on it, and that they can set up a new one in a minute if they want to keep it. GoCardless's guide recommends notifying the customer and prompting them to set up a new mandate if needed. 2. **Link to a hosted flow.** On GoCardless, new mandates are collected with a Billing Request and its hosted Billing Request Flow. Send that link; never ask for bank details by email. 3. **Wait for `active`.** A new mandate goes through `pending_submission` and `submitted` before `active`. If it fails (for example because the new account does not support Direct Debit), you receive a `failed` event; ask the customer to try another account. 4. **Recreate what was lost.** Create a new subscription on the new mandate, and a payment for any amount still owed, on or after the mandate's `next_possible_charge_date`. 5. **Tell the customer what will be collected and when**, before it happens. ### What about reinstating? GoCardless's API has a `reinstate` action for cancelled or expired mandates. It resubmits the mandate to the banks; you then receive `resubmission_requested`, `submitted`, and `reinstated` or `failed` up to two working days later, and a mandate can be resubmitted up to 10 times. Use it only when you know the mandate should still be valid, for example after an error on your side. When the customer cancelled at their bank, reinstating it without their agreement goes against their decision, and is likely to lead to a failure or a claim. ## Expired mandates An expired mandate is the easiest to recover, because nobody objected. If you plan to charge a customer whose mandate has been idle (an annual plan, or a customer who paused), check the mandate status before the charge date. If it has expired, ask the customer to set up a new mandate in advance, rather than discovering it through a failed payment. ## A checklist - [ ] Your webhook handler processes mandate events, not only payment events. - [ ] Events are grouped by customer before any email goes out. - [ ] `cause` and `origin` are both stored and read. - [ ] Cancellations by your own system are recognised and not sent to customers as "your bank cancelled". - [ ] The new-mandate email links to a hosted Billing Request Flow. - [ ] Subscriptions are recreated only after the new mandate is active. - [ ] Mandates are checked before infrequent charges. ## Doing this with NoChurn GoCardless keeps the mandates, the collection and the bank details. NoChurn imports customers, mandates, subscriptions and payments, follows GoCardless webhooks, and reads mandate status (active, cancelled, expired). When a mandate is cancelled, NoChurn's AI-written recovery email, which you review, links the customer to set up a new one; when the customer wants to stop instead, the cancel flow with a one-click cancel always visible and win-back emails at day 30, 60 and 90 take over. See [NoChurn + GoCardless](/integrations/gocardless/). --- # How to win back customers on GoCardless Source: https://www.nochurn.sh/blog/gocardless-win-back/ On GoCardless, a customer who cancelled their subscription has often left something useful behind: an active Direct Debit mandate. If it is still active, a returning customer can restart without filling in their bank details again. If it is gone, they need a new one, which GoCardless also makes simple with a hosted flow. Either way, the hard part of win-back is not the payment. It is the message, its timing, and the customer's agreement to be charged again. This guide covers what to check before contacting a former customer, the two ways to restart, what to offer based on why they left, and how to measure the result. It sticks to GoCardless's documentation: the [subscriptions API reference](https://docs.gocardless.com/docs/api-reference/subscription), the [mandate events reference](https://docs.gocardless.com/docs/api-reference/events/mandate), the developer guide [Responding to mandate events](https://developer.gocardless.com/mandates/responding-to-mandate-events/) and the help centre article on [payer notifications](https://support.gocardless.com/hc/en-us/articles/17144912552220-Payer-notifications) (all accessed November 2026). GoCardless's documentation site was not reachable from our research environment, so we checked endpoint and status descriptions against GoCardless's official API client libraries, such as [gocardless-pro-ruby](https://github.com/gocardless/gocardless-pro-ruby), which are generated from the same API schema. ## Who you are writing to Not every former customer is in the same place. Sort them first: | Situation | How to tell | Win-back path | |---|---|---| | Cancelled the subscription, mandate still active | Subscription `cancelled`, mandate `active` | Restart on the existing mandate, with their agreement | | Mandate cancelled at the bank | Mandate `cancelled`; see `details.cause` and `origin` on the event | New mandate through a hosted flow | | Mandate expired | Mandate `expired` (GoCardless expires mandates due to dormancy) | New mandate | | Left after a charge-back | Payment `charged_back` | Talk first; win-back only if the issue is resolved | | Subscription ended after failed payments | Payment failures, then a cancelled subscription | Recovery, not win-back: see [recovering failed Direct Debit payments](/blog/gocardless-failed-payments/) | Check the mandate's status right before you send anything, not when the customer cancelled. A mandate can expire or be cancelled in the meantime. ## Path 1: restart on an active mandate GoCardless's guide says to cancel a mandate only when the customer explicitly asks, so many customers who cancel a subscription keep an active mandate. A new subscription can be created on it with one API call. Technically possible is not the same as appropriate. The customer chose to stop. Before any new payment: 1. **Get explicit agreement.** The win-back email links to a page showing the plan, the amount, the interval and the first charge date. The customer confirms with a button, while signed in. 2. **Create the subscription** on the existing mandate, with a start date no earlier than the mandate's `next_possible_charge_date`. 3. **Confirm in writing** what will be collected and when, and how to cancel again. 4. **Respect advance notice.** Payers are told about upcoming Direct Debits; GoCardless's help centre on [payer notifications](https://support.gocardless.com/hc/en-us/articles/17144912552220-Payer-notifications) explains what it sends. If you send these notices yourself, make sure the new schedule is notified in time. A customer who is charged again without a clear "yes" is a likely indemnity claim, and on Bacs, GoCardless says there is currently no time limit on those. ## Path 2: set up a new mandate When the mandate is cancelled or expired, the customer needs to authorise a new one: 1. **Create a Billing Request** for the customer and send the link to its hosted Billing Request Flow. The customer enters their bank details on GoCardless's page; you never handle them. 2. **Wait for the mandate to become `active`.** It goes through `pending_submission` and `submitted` first. If it fails (for example because the account cannot take Direct Debits), ask the customer to try another account. 3. **Create the subscription** on the new mandate. If the customer cancelled the mandate at their bank because they wanted to stop paying, a new mandate is the only respectful path, even if GoCardless's API offers a `reinstate` action for cancelled mandates. Reinstating resubmits the old authorisation to the bank; it is meant for mandates that should still be valid, not for overruling a customer's decision. ## What to send, and when Base the message on the reason the customer gave when they left. A schedule that suits many subscription businesses: | Day after cancellation | Message | |---|---| | 30 | What changed since they left, tied to their reason. No offer yet. | | 60 | An offer that fits their reason, if there is one. | | 90 | A short last note with a direct way back. Then stop. | By reason: - **Too expensive**: a lower price for a set number of payments. On GoCardless, you can create the new subscription at the reduced amount and update it later (each amount change counts toward GoCardless's limit of 10 amendments per subscription), or create a subscription with a fixed `count` at the offer price followed by a regular one. State the full price and the date it applies. - **Only needed it for a while**: point out that next time they can pause instead of cancelling. GoCardless lets you pause subscriptions that run indefinitely or for a fixed count, for a set number of cycles. - **Missing a feature or had a problem**: write only once it is fixed, and say exactly what changed. - **Moved to another provider**: one honest message, then stop. Keep the emails short, from a real person's address, with one link. And honour opt-outs: win-back emails are marketing in most jurisdictions, unlike payment notifications. ## Measure what matters - **Restarts by path.** How many came back on an existing mandate and how many through a new one. If the new-mandate path converts badly, look at the flow. - **Months retained after return.** One discounted month followed by a second cancellation is not a win. - **Claims after return.** Any indemnity claim from a returning customer means the consent step was not clear. - **By original reason.** Which reasons come back, and which do not, tells you where the product needs work. Tag the new subscription in its `metadata` with the campaign and the original cancellation date, so the payments it creates can be traced back. ## Doing this with NoChurn GoCardless keeps the mandates, collection and bank details. NoChurn reads customers, mandates and subscriptions from GoCardless, including mandate status, and sends win-back emails at day 30, 60 and 90 written from the reason the customer gave in NoChurn's cancel flow, with a link to come back. The cancel flow itself keeps a one-click cancel always visible, and returning customers are tracked with the churn score from 0 to 100. See [NoChurn + GoCardless](/integrations/gocardless/). --- # Google Play's cancellation survey and how to reduce Android cancellations Source: https://www.nochurn.sh/blog/google-play-cancellation-survey/ Android subscribers usually cancel in the Google Play Store, not in your app. Google runs that flow, and when the user completes it, Play can ask them why they are leaving. The answer is not lost: it is stored on the subscription, and you can read it from the Google Play Developer API. Combined with pause, plan changes and restore, it gives you more to work with than many developers realize. This guide shows where the survey answer lives, what Google lets you offer before and after a cancellation, and how to build an in-app flow that keeps the cancel button one tap away. It is based on Google's documentation: the [subscription lifecycle](https://developer.android.com/google/play/billing/lifecycle/subscriptions), [subscriptions: deep links and customer management](https://developer.android.com/google/play/billing/subscriptions), the [RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference) and the Google Play Developer API reference for [purchases.subscriptionsv2](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2) (all accessed November 2026). ## Where cancellations come from Google's lifecycle guide lists three sources: - **The user**, from the Play subscriptions center. - **Automatically**, when a subscription does not recover after [account hold](https://developer.android.com/google/play/billing/lifecycle/subscriptions#account-hold). The same guide says users who don't accept an opt-in price increase before renewal are also unsubscribed automatically. - **You**, through `purchases.subscriptionsv2.cancel`. In every case, a regular auto-renewing subscription sends a `SUBSCRIPTION_CANCELED` notification, the state becomes `SUBSCRIPTION_STATE_CANCELED`, and `expiryTime` holds the date access should end. The user keeps access until then. Google warns that removing access to content the user is still entitled to violates its subscriptions policy. ## Reading the cancel survey After a `SUBSCRIPTION_CANCELED` notification, call `purchases.subscriptionsv2.get` with the purchase token. The response has a `canceledStateContext` with one of four branches: | Branch | Meaning | |---|---| | `userInitiatedCancellation` | The user canceled | | `systemInitiatedCancellation` | Google canceled, for example because of a billing problem | | `developerInitiatedCancellation` | You canceled | | `replacementCancellation` | The subscription was replaced by a new one | For user cancellations, `userInitiatedCancellation` contains `cancelTime` and a `cancelSurveyResult`. The API reference describes the latter as "information provided by the user when they complete the subscription cancellation flow (cancellation reason survey)." The `reason` field takes one of these values: | Value | Meaning | |---|---| | `CANCEL_SURVEY_REASON_NOT_ENOUGH_USAGE` | Not enough usage of the subscription | | `CANCEL_SURVEY_REASON_TECHNICAL_ISSUES` | Technical issues while using the app | | `CANCEL_SURVEY_REASON_COST_RELATED` | Cost related issues | | `CANCEL_SURVEY_REASON_FOUND_BETTER_APP` | The user found a better app | | `CANCEL_SURVEY_REASON_OTHERS` | Other reasons, with the user's free text in `reasonUserInput` | | `CANCEL_SURVEY_REASON_UNSPECIFIED` | Unspecified | Three practical notes: 1. **Read it at cancellation time.** The `canceledStateContext` is present only while the subscription is canceled or expired, and the purchase token stops working 60 days after expiration. If the user restores, Google says all cancellation fields are cleared. 2. **Expect gaps.** You cannot assume every user answered. Plan for unspecified reasons. 3. **Store the free text as untrusted data.** It is whatever the user typed. Five fixed reasons are coarse, but they map well to actions: cost, usage, quality, competition. ## What Google lets you offer instead ### Pause Google's lifecycle guide says all subscriptions have pause enabled by default (you can disable it in the Play Console). Users choose a pause length based on the billing period: | Billing period | Pause lengths | |---|---| | Weekly | 1, 2, 3 or 4 weeks | | Monthly, three-month, six-month, annual | 1, 2 or 3 months | Google notes the lengths are subject to change. The pause starts at the end of the current period; during the pause the user has no access and does not pay; at the end, Google tries to renew. Your backend sees `SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED` when the user schedules it, `SUBSCRIPTION_PAUSED` when it starts, and `SUBSCRIPTION_RECOVERED` when it resumes (or `SUBSCRIPTION_ON_HOLD` if the payment fails on resume). Google suggests providing a way to resume manually, through a deep link to Google Play. For a user who cancels because they "won't use it for a while", a pause is often the honest answer. ### Plan changes You can let users change tier or billing period in your app, with an offer if you want (Google's example is a discount on the first year when switching from monthly to annual). The **replacement mode** decides when the change applies and how unused time is credited. `DEFERRED`, for example, applies the change at the next renewal. A cheaper tier is a natural answer to `COST_RELATED`. ### Restore A canceled subscription that has not expired can be restored by the user from the Play Store subscriptions center with the **Resubscribe** button. Google requires all developers to support it. You receive `SUBSCRIPTION_RESTARTED` and the subscription renews as before. ## Building an in-app cancel flow Google's subscriptions guide says your app should include a link on a settings screen to let users manage their subscriptions, and that you "can also provide an option for users to cancel in your app or on your website." That gives you two designs. ### Option A: your screen, then Play 1. "Manage subscription" in settings opens your screen. 2. One question: why do you want to cancel? Use reasons close to Google's five, so the data lines up. 3. One relevant answer per reason: pause for low usage, cheaper plan for cost, a fix or a contact for technical issues. 4. A **Continue to cancel** button, always visible, that opens the deep link to the subscription's page in Play: `https://play.google.com/store/account/subscriptions?sku=` your product ID `&package=` your package name. Google says users can manage payment methods there and access "cancellation, resubscription, and pause." ### Option B: cancel in your app Your backend can cancel through `purchases.subscriptionsv2.cancel`. The `cancellationType` matters: - `USER_REQUESTED_STOP_RENEWALS`: cancellation requested by the user; it only stops the next renewal and **the subscription can be restored**. - `DEVELOPER_REQUESTED_STOP_PAYMENTS`: requested by the developer; it **cannot be restored**. For a user who asked to cancel, use `USER_REQUESTED_STOP_RENEWALS`, so they keep access until the end of the period and can still change their mind in the Play Store. With this design, the "Cancel" button in your flow really cancels, in one tap, which is the cleanest way to respect click-to-cancel expectations. Google describes its survey answer as coming from Play's own cancellation flow, so for cancellations made through your app, rely on the reason you collect yourself. Either way: same visual weight for "Cancel" and for the offer, no confirmation loops, no "contact support to cancel." ## After a cancellation Between `SUBSCRIPTION_CANCELED` and `SUBSCRIPTION_EXPIRED`, the user is still a subscriber. - Google suggests showing a message in your app with the expiration date. - Google also notes you can detect cancellations in real time and "send them push notifications or in-app messages to ask them to resubscribe." - Match the message to the survey reason, and send one, not five. - After expiry, move to win-back: see [how to win back lapsed subscribers on Google Play](/blog/google-play-win-back/). ## Measuring Per month and per reason: cancellations (from `SUBSCRIPTION_CANCELED` with a user-initiated context), restores (`SUBSCRIPTION_RESTARTED`), pauses scheduled, plan changes, and the share that actually expired. Compare reasons across app versions: a jump in `TECHNICAL_ISSUES` after a release is a bug report. ## Doing this with NoChurn NoChurn reads the cancel survey answer from Google Play with every cancellation and puts it on the customer's timeline, next to the reasons collected in your own flow. Its cancel flow is available as a headless API for your Android app: reasons, one offer (discount, pause or plan change), and a cancel button that is always visible and opens Google Play's subscription page. Google keeps payments, retries and its own cancel button. Reasons then drive win-back emails and the churn score. See [NoChurn + Google Play](/integrations/google-play/). --- # How to reduce churn on Google Play: grace period and account hold Source: https://www.nochurn.sh/blog/google-play-grace-period-account-hold/ On Google Play, Google charges the customer, retries failed payments and shows the cancel button. You cannot retry a charge or touch the customer's payment method. What you do control: how long the grace period and account hold last, whether the customer keeps access, what your app shows them, and how quickly you react when a subscription recovers or ends. This guide covers the grace period, account hold, the real-time developer notifications (RTDN) and `subscriptionsv2` states behind them, in-app messaging for payment declines, deep links to the subscription center, restore and resubscribe, and voided purchases. It sticks to Google's documentation: [subscription lifecycle](https://developer.android.com/google/play/billing/lifecycle/subscriptions), [about subscriptions](https://developer.android.com/google/play/billing/subscriptions), the [RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference) and [Help Google dispute chargebacks](https://developer.android.com/google/play/billing/provide-refund-and-chargeback-suggestions) (all accessed November 2026). ## What Google does when a renewal fails When a renewal payment fails, Google notifies the user and keeps trying to renew for some time before the subscription ends. Google's docs call this the recovery period, made of a **grace period** followed by an **account hold**. During it, Google sends the user emails and notifications asking them to update their payment method. | Phase | User's access | `subscriptionState` | RTDN when it starts | |---|---|---|---| | Grace period | Keeps access | `SUBSCRIPTION_STATE_IN_GRACE_PERIOD` | `SUBSCRIPTION_IN_GRACE_PERIOD` (6) | | Account hold | Loses access | `SUBSCRIPTION_STATE_ON_HOLD` | `SUBSCRIPTION_ON_HOLD` (5) | | Recovered | Access restored | `SUBSCRIPTION_STATE_ACTIVE` | `SUBSCRIPTION_RECOVERED` (1) | | Not recovered | Access ended | `SUBSCRIPTION_STATE_CANCELED`, then `EXPIRED` | `SUBSCRIPTION_CANCELED` (3), then `SUBSCRIPTION_EXPIRED` (13) | ### Grace period Google's [lifecycle guide](https://developer.android.com/google/play/billing/lifecycle/subscriptions) says: - Grace period is enabled by default on all auto-renewing base plans. You can change its length or turn it off in the Play Console, and Google warns that a shorter length may reduce the number of subscriptions recovered. - During the grace period the user should keep access. `autoRenewEnabled` stays `true`, and Google extends `expiryTime` until the grace period ends. - If the user fixes their payment method, the subscription renews with its **original renewal date**. - Changing the grace period length only affects renewals that enter the grace period after the change. - If you set 0 days, Google still waits at least 1 day (a "silent grace period") to leave time for retries. The subscription stays active during those 24 hours and you will not receive a grace period RTDN. If your app only uses `queryPurchasesAsync()` to check entitlement, grace periods are handled for you, because the Play Billing Library keeps returning those purchases as active. ### Account hold Account hold follows the grace period: - It is enabled by default, and its default length is 60 days minus the grace period. You can change it or turn it off in the Play Console, with the same warning about shorter lengths. - Before the subscription enters account hold, Google makes additional attempts to charge for up to 48 hours, while the user keeps access. - During account hold you should **block access**. `expiryTime` is in the past and `queryPurchasesAsync()` no longer returns the subscription. - If the user fixes their payment, you get `SUBSCRIPTION_RECOVERED`, the purchase token stays the same, and you must restore access. Unlike recovery during the grace period, the **billing date moves to the date of recovery**. - If the hold ends without a fix, you get `SUBSCRIPTION_CANCELED` and then `SUBSCRIPTION_EXPIRED`. - A paused subscription that resumes with a failing payment method goes straight into account hold. Google also notes that users can cancel, restore or repurchase while on hold, so your backend must keep handling those events. ## Real-time developer notifications RTDNs are delivered through Cloud Pub/Sub and only carry the notification type and purchase token. Google's guidance is to call `purchases.subscriptionsv2.get` from your backend on each notification to read the full state. The [RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference) lists the subscription types; the ones that matter most for churn: | Code | Type | What to do | |---|---|---| | 6 | `SUBSCRIPTION_IN_GRACE_PERIOD` | Keep access; ask the user to fix their payment | | 5 | `SUBSCRIPTION_ON_HOLD` | Remove access; tell the user why | | 1 | `SUBSCRIPTION_RECOVERED` | Restore access (also sent when a subscription resumes from pause) | | 2 | `SUBSCRIPTION_RENEWED` | Normal renewal | | 3 | `SUBSCRIPTION_CANCELED` | Voluntary or involuntary cancellation; check `canceledStateContext` | | 7 | `SUBSCRIPTION_RESTARTED` | User restored a cancelled, not yet expired subscription | | 12 | `SUBSCRIPTION_REVOKED` | Revoked before expiry, for example after a chargeback; remove access | | 13 | `SUBSCRIPTION_EXPIRED` | Remove access | | 4 | `SUBSCRIPTION_PURCHASED` | New purchase, including a resubscribe | On a cancellation, `canceledStateContext` tells you whether the user, the system or you cancelled, and for user cancellations `userInitiatedCancellation` can include the reason the user gave. Use it: a cancellation after account hold is a payment problem, not a decision to leave. ## In-app messaging for payment declines Google offers a ready-made message for payment problems. If you call `BillingClient.showInAppMessages()` with `InAppMessageCategoryId.TRANSACTIONAL`, Google Play shows a temporary snackbar telling the user their payment was declined, with a deep link to fix their payment method on Google Play. According to Google's [subscriptions guide](https://developer.android.com/google/play/billing/subscriptions), the message is shown once per day during the grace period and account hold, and Google recommends calling the API each time the user opens the app. If the user fixes their payment, the call returns `SUBSCRIPTION_STATUS_UPDATED` with a purchase token. Refresh the subscription from your backend and restore access straight away. For users who reach your content outside the app (on the web, for example), Google suggests a push notification or an email when access stops because of account hold. ## Deep links to the subscription center Your app should link to subscription management from its settings screen. Google documents two URLs: 1. All subscriptions: `https://play.google.com/store/account/subscriptions` 2. One subscription (recommended): `https://play.google.com/store/account/subscriptions?sku=your-sub-product-id&package=your-app-package` The second opens the management page for that subscription, where the user can manage their payment methods, cancel, resubscribe or pause. Use it in your own payment emails, too. ## Restore, resubscribe and win-back Google separates two actions, both shown to the user as a **Resubscribe** button in the Play Store: - **Restore**: before expiry, a cancelled subscription is restored and continues to renew as if it were never cancelled. It keeps the same purchase token and you receive `SUBSCRIPTION_RESTARTED`. Google says all apps must support restore. - **Resubscribe**: after expiry, if the base plan allows it, the user buys again from the Play Store. This is a new purchase with a new token and a `SUBSCRIPTION_PURCHASED` RTDN. You must acknowledge it; the `outOfAppPurchaseContext` field helps you link it to the previous subscription and user. Inside your app, Google's guide describes winning back users who cancelled by offering a re-signup screen (for example with a Reactivate button), either before expiry or after. Subscription offers can target eligible users with discounts; eligibility rules are set in the Play Console. ## Refunds, voided purchases and chargebacks When a purchase is refunded or charged back, it is voided. You receive a `voidedPurchaseNotification` RTDN with the purchase token, order ID, `productType` and `refundType` (full refund or quantity-based partial refund). Google's lifecycle guide adds that a subscription charged back, or revoked by your backend with `purchases.subscriptionsv2.revoke`, triggers `SUBSCRIPTION_REVOKED`, and you should remove access. The Voided Purchases API gives you more detail over a time range. For chargebacks, Google lets you weigh in. When a chargeback needs developer review, Google Play sends a `PendingRefundReviewNotification` RTDN, and you have 24 hours to respond with the ReviewRefund API, giving a refund preference and any purchase usage evidence. Google records only your first call. ## A checklist - [ ] RTDNs are delivered to your backend, and each one triggers a `subscriptionsv2.get`. - [ ] Grace period and account hold are on, with lengths chosen on purpose. - [ ] Access stays on during the grace period and stops during account hold. - [ ] `showInAppMessages()` is called at app launch. - [ ] Your settings screen and emails use the specific subscription deep link. - [ ] Restore and resubscribe purchases are handled and acknowledged. - [ ] Each purchase carries an obfuscated account ID, so you can match it to your user. - [ ] Voided purchases and chargeback review notifications are handled. ## Doing this with NoChurn Google keeps payments, retries, the grace period, account hold and the cancel button; NoChurn does not change that. NoChurn reads your real-time developer notifications, matches each subscription to your user through the obfuscated account ID, and puts grace periods, holds, cancellations, recoveries and voided purchases on the customer timeline and in a churn score from 0 to 100. Where Google allows it, it acts: messages in your app or by email linking to the Play subscription page, a cancel flow your app shows through the headless API before linking to Google Play, and win-back emails at day 30, 60 and 90 based on the cancel reason. See [NoChurn + Google Play](/integrations/google-play/). --- # Google Play refunds and voided purchases: what to do with them Source: https://www.nochurn.sh/blog/google-play-refunds-voided-purchases/ On Google Play, money can go back to a subscriber in several ways: the user gets a refund, you refund them from the Play Console or the API, a purchase is never acknowledged, or the payment is charged back. Google groups all of these under one term: a **voided purchase**. If you grant access or credits from your own backend, you need to know about every one of them. This guide explains where voided purchases show up, what Google tells you about each one, the newer refund review for chargebacks, and how to respond. It sticks to Google's documentation: the [real-time developer notifications reference](https://developer.android.com/google/play/billing/rtdn-reference), the [security best practices on voided purchases](https://developer.android.com/google/play/billing/security), [handling rejected purchases](https://developer.android.com/google/play/billing/integrate), the [subscription lifecycle](https://developer.android.com/google/play/billing/lifecycle/subscriptions), and the Google Play Developer API reference for [voided purchases](https://developers.google.com/android-publisher/voided-purchases), [orders.refund](https://developers.google.com/android-publisher/api-ref/rest/v3/orders/refund) and [orders.reviewrefund](https://developers.google.com/android-publisher/api-ref/rest/v3/orders/reviewrefund) (all accessed November 2026). ## What counts as a voided purchase Google's [security page](https://developer.android.com/google/play/billing/security) defines voided purchases as "purchases that have been canceled, revoked, or charged back," and lists the main causes: - The purchase is canceled by the user, the developer or Google, including purchases auto-canceled because they were never acknowledged. For subscriptions, this means canceling the purchase itself, not just turning off renewal. - The purchase is charged back. - The developer cancels or refunds an order and checks the "revoke" option. A normal subscription cancellation (the user stops renewal) is not a voided purchase. It is a `SUBSCRIPTION_CANCELED` event, and the user keeps access until the end of the period. ## Refund, revoke or both You have three actions, and they do different things: | Action | API | Money | Access | |---|---|---|---| | Refund only | `orders.refund` without `revoke` | Refunded | Kept | | Refund and revoke | `orders.refund` with `revoke=true`, or `purchases.subscriptionsv2.revoke` with a full refund | Refunded | Ended immediately | | Cancel | `purchases.subscriptionsv2.cancel` | Not refunded | Kept until the period ends | Points from Google's docs worth knowing: - `orders.refund` cannot refund orders older than three years. With `revoke` set to true, access ends immediately and, for a recurring subscription, all future payments stop. - Google's [integration guide](https://developer.android.com/google/play/billing/integrate) says that developer revocations and refunds with revoke trigger notifications and appear in the Voided Purchases API with `voidedSource` set to developer. For subscriptions, you get both `SUBSCRIPTION_REVOKED` and a `VoidedPurchaseNotification`. - A refund **without** revoke "doesn't trigger a revocation or voided purchase notification." If you use it, record it yourself. - If you do not acknowledge a new subscription within three days, the user is automatically refunded and the purchase is revoked. Google asks you not to rely on this to reject purchases: revoke and refund explicitly instead. ## Where voided purchases show up ### In real time: VoidedPurchaseNotification If your Play app has [real-time developer notifications](https://developer.android.com/google/play/billing/getting-ready) enabled, a voided purchase arrives as a `voidedPurchaseNotification` with: - `purchaseToken`: the purchase that was voided. - `orderId`: the exact order. For subscriptions, each renewal has its own order ID, so this tells you which payment was voided. - `productType`: `1` subscription, `2` one-time product. - `refundType`: `1` full refund, `2` quantity-based partial refund (multi-quantity purchases only). Google notes that this is enough to "locate the right purchase and order for entitlement adjustments." For subscriptions, a revocation also sends a `SUBSCRIPTION_REVOKED` subscription notification; the [lifecycle guide](https://developer.android.com/google/play/billing/lifecycle/subscriptions) says to revoke the user's entitlement immediately in that case. ### In bulk: the Voided Purchases API `purchases.voidedpurchases.list` is a pull API. From the API reference: - It covers the **last 30 days**: `startTime` cannot be older than that. - By default it returns only one-time products. Pass `type=1` to include subscriptions. - Each record has a `voidedReason`: `0` Other, `1` Remorse, `2` Not_received, `3` Defective, `4` Accidental_purchase, `5` Fraud, `6` Friendly_fraud, `7` Chargeback, `8` Unacknowledged_purchase. - And a `voidedSource`: `0` user, `1` developer, `2` Google. The reason codes are the most useful part, because the notification does not include them. One caveat from the security page: voided purchases "without any associated clawback content are not exposed by the Voided Purchases API." Use both: the notification to act within seconds, and a daily API pull to get reasons and catch anything you missed. ## Chargebacks: the refund review Google has added a way for developers to weigh in on some chargebacks. When a user requests a chargeback that needs developer review, you receive a `pendingRefundReviewNotification`. According to the [RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference), you should evaluate the request and send "a refund suggestion and purchase usage evidence within 24 hours" by calling `orders.reviewrefund`. Pending reviews currently support only `CHARGEBACK` as the reason. The request body, per the API reference: | Field | Meaning | |---|---| | `pendingRefundToken` | From the notification; required | | `refundPreference` | `APPROVE`, `DECLINE` or `NEUTRAL`; required | | `sampleContentProvided` | Whether you offered a free sample, trial or description before purchase; required | | `consumptionPercentageMilliunits` | Optional, 0 to 100,000 (45,200 means 45.2%) | | `consumptionUsageEvents` | Optional list of usage events (time, item description, IP address, location, obfuscated account or profile ID); lists over 1,000 items are rejected | The notification includes the `obfuscatedAccountId` and `obfuscatedProfileId` if you set them at purchase. Without them, you will struggle to find the user's usage within 24 hours. Be truthful. If the user could not use what they paid for, `APPROVE` is the right answer. If they used the subscription throughout the period, a `DECLINE` with concrete usage events is what the field is for. ## What to do with each voided purchase Google's [security guide](https://developer.android.com/google/play/billing/security) recommends, depending on the reason and the user's history: 1. **Claw back** unused items, such as in-app currency that was granted. 2. **Multiple strikes**: an in-app warning for a first case, stronger measures for repeat cases. 3. **Temporarily disable purchases** while you look into it. 4. **Restrict access** to your app in extreme, repeated cases. 5. **Call the Voided Purchases API more often** once you detect voided purchases. For a subscription app, a practical policy looks like this: | Reason | Suggested response | |---|---| | Accidental purchase, remorse | End access for the refunded period; no warning. Maybe ask for feedback | | Not received, defective | Treat as a product bug; investigate the user's account | | Unacknowledged purchase | Fix your purchase processing; this is your bug, not the user's | | Fraud, friendly fraud, chargeback | End access, flag the account, block new purchases until reviewed | ## Common mistakes - **Only handling `SUBSCRIPTION_CANCELED`.** It means "stop renewing", not "refunded". Revocations come as `SUBSCRIPTION_REVOKED` and voided purchase notifications. - **Refunding without revoke and forgetting it.** No notification will remind you. - **Polling the API less than monthly.** Anything older than 30 days is gone from the API. - **No obfuscated account ID.** You cannot answer a refund review in time if you cannot find the user. - **Punishing remorse refunds like fraud.** The reason codes exist so you can tell them apart. ## Doing this with NoChurn NoChurn reads your Google Play real-time developer notifications and the Voided Purchases API, so refunds, revocations and chargebacks appear on each customer's timeline with their reason and feed the churn score. On Google Play, refunds are read-only in NoChurn: refund decisions and refund reviews stay with you and Google, and payments and retries stay with Google. To match purchases to customers, set an obfuscated account ID at purchase. See [NoChurn + Google Play](/integrations/google-play/). --- # Tracking churn with Google Play real-time developer notifications Source: https://www.nochurn.sh/blog/google-play-rtdn-churn-tracking/ Google Play tells your backend about subscription changes through **real-time developer notifications** (RTDN), published to a Google Cloud Pub/Sub topic. They are the basis of any serious churn tracking for an Android app: who canceled, who is in a billing problem, who paused, who actually left. There is a catch that shapes everything else: a notification only says that something changed. This guide covers the setup, how to process each message, how notification types map to churn metrics, and the mistakes that skew the numbers. It is based on Google's documentation: [configuring RTDN](https://developer.android.com/google/play/billing/getting-ready), the [RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference), the [subscription lifecycle](https://developer.android.com/google/play/billing/lifecycle/subscriptions) and the API reference for [purchases.subscriptionsv2](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2) (all accessed November 2026). ## Setting up notifications Google's [setup guide](https://developer.android.com/google/play/billing/getting-ready) walks through it: 1. Create a Pub/Sub topic in a Google Cloud project. 2. Give the service account `google-play-developer-notifications@system.gserviceaccount.com` the Pub/Sub Publisher role on the topic. 3. Create a subscription on the topic: **push** to an HTTPS endpoint on your backend, or **pull** from a worker. 4. In the Play Console, enter the topic name for your app and click **Send Test Message**. 5. Choose the notification types: subscriptions and voided purchases only, or everything including one-time products. Acknowledge every message. For pull subscriptions, Google says to acknowledge pulled messages "to avoid repeated delivery by Cloud Pub/Sub"; for push, a successful response code serves as the acknowledgement. ## Processing a message Each Pub/Sub message has a base64 `data` field. Decoded, it contains `version`, `packageName`, `eventTimeMillis` and exactly one of `subscriptionNotification`, `oneTimeProductNotification`, `voidedPurchaseNotification`, `pendingRefundReviewNotification` or `testNotification`. A subscription notification carries only a `notificationType` and a `purchaseToken`. Google's reference is explicit: you "must call the Google Play Developer API after receiving Real-time developer notifications to get the complete status," because notifications "do not give you complete information about the purchase." The lifecycle guide calls `purchases.subscriptionsv2.get` "the source of truth for subscription management." So the pipeline is: 1. Receive, check `messageId` for duplicates (Google recommends it), store the raw message, acknowledge. 2. Call `purchases.subscriptionsv2.get` with the purchase token. 3. Store the resulting state as a snapshot with the notification type and `eventTimeMillis`. 4. Update your entitlement and your metrics from the snapshot, not from the notification alone. Keep in mind that the purchase token works only until 60 days after expiration. Fetch the state when the notification arrives, not weeks later. ## The subscription notification types From the [RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference): | Code | Type | What happened | |---|---|---| | 1 | `SUBSCRIPTION_RECOVERED` | Recovered from account hold, or resumed from pause | | 2 | `SUBSCRIPTION_RENEWED` | An active subscription renewed | | 3 | `SUBSCRIPTION_CANCELED` | Canceled, voluntarily or involuntarily | | 4 | `SUBSCRIPTION_PURCHASED` | New subscription purchased | | 5 | `SUBSCRIPTION_ON_HOLD` | Entered account hold | | 6 | `SUBSCRIPTION_IN_GRACE_PERIOD` | Entered grace period | | 7 | `SUBSCRIPTION_RESTARTED` | User restored a canceled, not yet expired subscription | | 9 | `SUBSCRIPTION_DEFERRED` | Renewal date extended | | 10 | `SUBSCRIPTION_PAUSED` | Pause took effect | | 11 | `SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED` | Pause scheduled or changed | | 12 | `SUBSCRIPTION_REVOKED` | Revoked before expiry | | 13 | `SUBSCRIPTION_EXPIRED` | Expired | | 18 | `SUBSCRIPTION_CANCELLATION_SCHEDULED` | Installment plan cancellation scheduled for the end of the commitment | | 20 | `SUBSCRIPTION_PENDING_PURCHASE_CANCELED` | A pending transaction was canceled | There are a few more (items changed, price change updates, price step-up consent). Code 8 is deprecated. ## The states that matter for churn The `subscriptionState` field from the API is more reliable than the notification type for counting. The lifecycle guide describes what each state means for access: | State | User has access? | Churn meaning | |---|---|---| | `SUBSCRIPTION_STATE_ACTIVE` | Yes | Subscriber | | `SUBSCRIPTION_STATE_IN_GRACE_PERIOD` | Yes | At risk: payment failed | | `SUBSCRIPTION_STATE_ON_HOLD` | No | At risk: payment failed, access blocked | | `SUBSCRIPTION_STATE_PAUSED` | No | Paused, not churned | | `SUBSCRIPTION_STATE_CANCELED` | Until `expiryTime` | At risk: renewal stopped | | `SUBSCRIPTION_STATE_EXPIRED` | No | Churned | Grace period and account hold come with defaults worth knowing. Grace period is enabled by default on all auto-renewing base plans. Account hold is also on by default, with a length Google calculates as 60 days minus the grace period. Both can be changed in the Play Console. Before account hold starts, Google makes additional charge attempts for up to 48 hours. ## From events to churn metrics ### Count churn at expiry `SUBSCRIPTION_CANCELED` means renewal stopped, not that the user left. They keep access until `expiryTime`, and can restore it (`SUBSCRIPTION_RESTARTED`). Count churn on `SUBSCRIPTION_EXPIRED`, and use cancellations as a leading indicator. ### Split voluntary and involuntary churn The subscription resource's `canceledStateContext` says who canceled: - `userInitiatedCancellation`: voluntary. It may also contain the user's [cancel survey answer](/blog/google-play-cancellation-survey/). - `systemInitiatedCancellation`: canceled by the system, "for example because of a billing problem". This is your involuntary churn. - `developerInitiatedCancellation`: you canceled. - `replacementCancellation`: replaced by a new subscription, for example after a plan change. Not churn. The billing path has a recognizable sequence: `SUBSCRIPTION_IN_GRACE_PERIOD`, then `SUBSCRIPTION_ON_HOLD`, then either `SUBSCRIPTION_RECOVERED` or, at the end of account hold, `SUBSCRIPTION_CANCELED` followed immediately by `SUBSCRIPTION_EXPIRED`. ### Don't count pauses as churn `SUBSCRIPTION_RECOVERED` fires both when a subscription leaves account hold and when it resumes from a pause. Check the previous state before counting it as a billing recovery. ### Handle plan changes and re-signups Upgrades, downgrades and in-app re-signups before expiry create a new purchase with a new token. The new subscription has a `linkedPurchaseToken` pointing to the old one. If you don't follow these links, every plan change looks like one churned subscriber and one new subscriber. Resubscriptions from the Play Store after expiry are different: Google says they do not carry a `linkedPurchaseToken`, but the API response includes `outOfAppPurchaseContext` with the expired token until you acknowledge the purchase. Count those as reactivations. ### Revocations `SUBSCRIPTION_REVOKED` means access ended early: you revoked it, or the purchase was charged back. The state becomes expired. Report it separately from normal churn, alongside [voided purchases](/blog/google-play-refunds-voided-purchases/). ## A monthly report 1. **Active at start**: subscriptions in active, grace period, or canceled-but-not-expired states. 2. **Voluntary churn**: expirations whose context is user-initiated. 3. **Involuntary churn**: expirations whose context is system-initiated. 4. **Billing recovery rate**: subscriptions that entered grace period or account hold and were recovered, over all that entered. 5. **Restores**: `SUBSCRIPTION_RESTARTED`. 6. **Paused**: count, and how many resume. 7. **Reactivations**: Play Store resubscriptions and in-app re-signups after expiry. The general formulas are in [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ## Common mistakes - **Trusting the notification type alone.** Always fetch the subscription state. - **Counting cancellations as churn.** It inflates churn and hides restores. - **Ignoring linked purchase tokens.** Plan changes become fake churn. - **Calling the API too late.** Tokens stop working 60 days after expiration. - **Not acknowledging Pub/Sub messages.** You get duplicates and wasted API quota. - **No obfuscated account ID at purchase.** You cannot join Play data with your own user data. ## Doing this with NoChurn You point your Play real-time developer notifications to NoChurn and give it a service account with access to your Play Console. NoChurn fetches the subscription state for each event, follows linked purchase tokens, separates voluntary, billing and revoked churn, and keeps a timeline per customer, matched through the obfuscated account ID you set at purchase. Grace period, account hold and cancellations feed the churn score from 0 to 100, and you can add your own attributes by API. Google keeps payments, retries and the cancel button. See [NoChurn + Google Play](/integrations/google-play/). --- # How to win back lapsed subscribers on Google Play Source: https://www.nochurn.sh/blog/google-play-win-back/ On Google Play, a subscriber who leaves goes through two stages. First they cancel: renewal stops but access continues until the end of the period. Then the subscription expires. Google gives you different tools for each stage, some inside your app and some in the Play Store itself, and a returning subscriber can come back through any of them. This guide maps those tools, shows how to target offers at lapsed users, and explains the backend work needed so a returning subscriber is linked to the right account. It sticks to Google's documentation, mainly [subscriptions: customer management](https://developer.android.com/google/play/billing/subscriptions), the [subscription lifecycle](https://developer.android.com/google/play/billing/lifecycle/subscriptions), [promo codes](https://developer.android.com/google/play/billing/promo) and the Google Play Developer API reference for [subscription offers](https://developers.google.com/android-publisher/api-ref/rest/v3/monetization.subscriptions.basePlans.offers) (all accessed November 2026). ## The four ways back Google's subscriptions guide has a table of "winback" options by stage and place. Summarized: | | Before expiry, in app | Before expiry, in Play Store | After expiry, in app | After expiry, in Play Store | |---|---|---|---|---| | Feature | New in-app purchase | Restore | New in-app purchase | Resubscribe | | Checkout flow | Yes | No | Yes | Yes | | New purchase token | Yes | No | Yes | Yes | | Enabled by default | No | Yes, all developers must support it | No | Yes for apps on Billing Library 2.0+, can opt out | | When the user pays | Same product: end of current period | End of current period | Immediately | Immediately | ### Before expiry: restore While a canceled subscription is still active, the user can tap **Resubscribe** in the Play Store's subscriptions center. Google calls this a *restore*: the cancellation is undone, the subscription keeps its purchase token and renews as if nothing happened. Supporting it is required for all developers. Your backend receives `SUBSCRIPTION_RESTARTED`, and Google suggests you record that the subscription will renew and stop showing restoration messages. From your app, you can do the same with a new purchase. For the same product, the new subscription replaces the old one and keeps the same renewal date. For a different product or a winback price, Google suggests an upgrade or downgrade with the `WITHOUT_PRORATION` replacement mode, so the user is charged the new price on the original expiry date. ### After expiry: Resubscribe in the Play Store If enabled for the base plan (the default for eligible apps), the user can buy the same subscription again from the Play Store. Google's subscriptions guide says this works "for up to one year after expiration"; the lifecycle guide adds that the button may not appear for various reasons, for example when a subscription expired long ago. This creates a new purchase with a new token, made outside your app. You must process it on your backend (see below), or the user is refunded automatically after three days. ### After expiry: in your app A user who still has your app can subscribe again through the normal purchase flow. Here you choose what to show: the regular plan, or a discounted one. ## Making a winback offer Google's guide talks about a "winback SKU": a product or offer with special pricing for returning users, shown in your app or sent "outside of the app, such as in email." With base plans and offers, a winback discount is an **offer** on a base plan. Each offer can have up to two phases (for example, three discounted months, then the base price) and per-region prices: a fixed price, an absolute discount, a relative discount, or free. ### Who sees the offer Offer targeting in the API reference supports two rule types: - **Acquisition**: the user never had this subscription, or any subscription in the app. - **Upgrade**: the user currently has this subscription or a specific one, optionally with a given billing period, and optionally only once per user. Neither rule says "lapsed subscriber". The reference adds that these are the requirements Play evaluates, and that "developers may further filter these offers themselves." In practice, a winback offer is an offer you show only to users your backend knows have lapsed, filtered in your app using offer tags (up to 20 per offer). ### Free trials for returning users Two details from Google's guide: - A user who resubscribes to the same product is "no longer eligible for free trials or introductory price." Your UI must not promise one. - If you put a free trial or intro price on a winback product, make sure the **Allow one free trial per app** setting in the Play Console does not exclude returning users. ### Promo codes [Promo codes](https://developer.android.com/google/play/billing/promo) give a free trial on a subscription. Google says users who previously subscribed but no longer are "are still eligible for a free trial through a promotion." Limits to know: - Promo codes give free trials, not free subscriptions. - One promo code per subscription product. - Up to 10,000 one-time use codes per quarter per subscription product; unused codes do not carry over. - Custom (shared) codes can only be redeemed by users who have not subscribed before, so for win-back use one-time codes. - A promotion can last up to one year. ## Bringing users to the right place Google recommends a link in your app's settings to manage subscriptions, and documents two deep links: - All subscriptions: `https://play.google.com/store/account/subscriptions` - One subscription: the same URL with `?sku=` your product ID and `&package=` your package name. The first is the one Google suggests "to help a user restore a canceled subscription." For users whose subscription has expired, send them to your app's subscription screen instead, where you can show the winback offer. ## Processing a returning purchase This is where many winbacks quietly fail. 1. **Listen for `SUBSCRIPTION_PURCHASED`.** A Play Store resubscription is a new purchase with a new token, made outside your app. 2. **Call `purchases.subscriptionsv2.get`.** For resubscriptions from the Play Store, the response includes `outOfAppPurchaseContext`, with the expired subscription's purchase token and the obfuscated account and profile IDs from that previous subscription, if you set them. Use either to find the user. 3. **Acknowledge it from your backend** within three days, even if the user never opens the app. Otherwise Google refunds and revokes it. 4. **For in-app re-signups before expiry**, the new purchase carries a `linkedPurchaseToken` pointing to the old one. Google asks you to invalidate the old token. ## A practical plan 1. **Track the stage.** Canceled but active (`SUBSCRIPTION_CANCELED`, future expiry), expired (`SUBSCRIPTION_EXPIRED`), or lost to billing after account hold. Each needs a different message. 2. **Read why they left.** The subscription resource's `canceledStateContext` tells you whether the user, the system or you canceled, and the user's cancel survey answer if they gave one. See [Google Play's cancellation survey](/blog/google-play-cancellation-survey/). 3. **Before expiry**, one message in the app with the end date and a restore link. No discount yet. 4. **After expiry**, a sequence spaced over weeks, matched to the reason: cost gets the winback offer, "not enough usage" gets news and maybe a promo-code trial, technical issues get an honest update on the fix. 5. **Email only those who gave you their address.** Play's real-time notifications don't include the user's email address. You need your own account and the obfuscated account ID set at purchase to connect the two. 6. **Measure returns** with `SUBSCRIPTION_PURCHASED` linked to a previously expired user, and check whether they stay past the discounted phase. ## Doing this with NoChurn NoChurn reads your Google Play real-time developer notifications and the subscription state, so it knows who canceled, who expired, who was lost after account hold, and what they answered in the cancel survey. It sends win-back emails at day 30, 60 and 90 based on that reason, to users whose email you share from your app, pointing them to your app or to Google Play. Google keeps the checkout, the offer pricing and the payment. See [NoChurn + Google Play](/integrations/google-play/). --- # How to use Gorgias tickets as chargeback evidence Source: https://www.nochurn.sh/blog/gorgias-chargeback-evidence/ Subscription stores see a particular kind of chargeback: "I cancelled and was charged anyway", "I never received this month's box", "I don't recognise this charge". In each case, your support history in Gorgias may hold the answer: the customer asking to skip a shipment, confirming an address, thanking you for a replacement, or never asking to cancel at all. This guide shows how to turn Gorgias tickets into evidence a card issuer can use: what to look for, how to get complete, dated messages out of Gorgias, and how to put them together with order and payment data. Gorgias details come from its documentation: [reviewing customer history](https://docs.gorgias.com/en-US/review-customer-history-in-gorgias-2390890), [exporting tickets](https://docs.gorgias.com/en-US/export-tickets-from-gorgias-404844), the [Recharge integration](https://docs.gorgias.com/en-US/recharge-81874) and the API's [List messages](https://developers.gorgias.com/reference/list-messages) and [TicketMessage object](https://developers.gorgias.com/reference/the-ticketmessage-object). Dispute details come from Stripe's [dispute categories](https://docs.stripe.com/disputes/categories) and [best practices](https://docs.stripe.com/disputes/best-practices), and Braintree's [evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/php) (all accessed November 2026). ## Who handles the dispute Ecommerce stores take payments through different processors, and the dispute is answered wherever the payment was taken. This guide covers disputes you answer on **Stripe** or **Braintree**. If your store uses another processor, the evidence below is still useful, but submit it where that processor asks. ## What reviewers look for in subscription commerce | Dispute story | What helps | Where in Gorgias | |---|---|---| | "I cancelled" | No cancellation request before the charge, or a request made after it; or your confirmation of a later cancellation date | Tickets, subscription actions | | "Never received it" | Messages about delivery, address confirmations, thanks for a replacement | Tickets next to the order | | "Didn't authorise it" | The customer discussing the subscription or past orders from the account email | Customer timeline | | "Not as described" | The customer's own description of the problem and what you offered | The ticket thread | For the "subscription canceled" category, Stripe's [dispute categories](https://docs.stripe.com/disputes/categories) point to `cancellation_rebuttal` and `customer_communication`. Stripe's [best practices](https://docs.stripe.com/disputes/best-practices) recommend combining several communications into one file. On Braintree, the [evidence requirements guide](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/php) lists emails or other correspondence with the customer among helpful evidence. ## Step 1: open the customer timeline Gorgias's [customer history](https://docs.gorgias.com/en-US/review-customer-history-in-gorgias-2390890) feature is the fastest starting point. From a ticket, open the customer's profile in the sidebar and click **Open Timeline**. Per Gorgias: - The timeline lists the customer's tickets and, for Shopify stores, their orders, with number, status, date, total and item count. You can filter to show only orders. - The sidebar previews the three most recent tickets and shows up to 10 recent orders. - AI summaries can be generated from the timeline. Use the summary to find the right tickets, not as evidence. A reviewer needs the customer's words, not an AI's paraphrase. ## Step 2: pick the tickets that matter Read every ticket in the 60 days around the disputed charge. You are looking for: - **Skips, swaps or frequency changes** the customer asked for. They show the customer managed the subscription actively. - **Delivery conversations**: "the box arrived damaged", "thanks, got it". They show receipt. - **Cancellation requests**, with their exact date and your reply. If the customer asked to cancel before the charge and the request was missed, the honest answer is usually to accept the dispute and refund. If you use the Recharge integration, agents can cancel, reactivate and refund from the ticket sidebar ([Recharge integration](https://docs.gorgias.com/en-US/recharge-81874)). A confirmation reply sent at that moment is the best possible evidence of what was agreed and when. ## Step 3: export the messages with timestamps Gorgias offers several routes, documented in [exporting tickets](https://docs.gorgias.com/en-US/export-tickets-from-gorgias-404844): | Route | What you get | Limits Gorgias documents | |---|---|---| | Export from a view | CSV of ticket data (ID, tags, subject, timings) | No message bodies; link emailed, valid 14 days | | Analytics drill-down, "Export with message content" | Tickets with public messages, oldest first | Most recent 30 days of the period; internal notes and events excluded | | API: [List messages](https://developers.gorgias.com/reference/list-messages) with `ticket_id` | Every message with its `created_datetime` | Paginated, up to 100 per page | Gorgias lists the account owner, admins and leads as the roles that can export. For a single dispute, the API route is the most precise: it gives each message with its own timestamp, and you can include only the tickets you chose. The analytics export is handy when the dispute is recent and you want several tickets at once; it already leaves out internal notes, which you should exclude anyway. ## Step 4: assemble the file 1. **One timeline.** Orders and charges from your store and processor, subscription changes, and the selected messages, in date order, in one time zone you name. 2. **Quotes in full.** Date, time, sender (the customer's email or your agent), full text. Mark any cut with "[…]". 3. **A cover note** of three or four sentences: "The customer was charged on [date] for their monthly box, delivered on [date]. On [date] they wrote to ask for a flavour swap for the next box (message 2). They did not request cancellation before the dispute." 4. **Nothing extra.** No internal notes, no other customers' details, no card data. Gorgias tickets sometimes contain addresses and phone numbers; include them only when they matter (for example, a confirmed delivery address in a "not received" case). Submit before the deadline. Braintree states it will not forward a response unless it is finalized before the reply-by date ([managing disputes](https://developer.paypal.com/braintree/docs/guides/disputes/managing)). ## Step 5: make the next one easier - **Tag subscription actions** (`skip`, `swap`, `cancel-done`) when they happen, so they are easy to find. - **Confirm every cancellation by message**, with the date it takes effect and whether an upcoming order will still ship. - **Use the Resolution ticket field** to record the outcome of refund and cancellation tickets. - **Answer "I'll call my bank" the same day.** A quick refund is usually cheaper than a dispute; see [how to handle refund requests in Gorgias](/blog/gorgias-refund-requests/). ## Common mistakes - **Sending an AI summary instead of the messages.** Summaries help you find tickets. Reviewers need the customer's own words with dates. - **Forgetting the subscription app.** A skip or cancellation done in your subscription app's admin, without a ticket reply, leaves no customer-facing record. Confirm changes by message. - **Mixing time zones.** Gorgias, your store and your processor may show different zones. Convert everything to one before building the timeline. - **Fighting a dispute you should accept.** If the customer clearly asked to cancel before the charge and the request was missed, refund or accept. Contesting a fair claim wastes time and is unlikely to succeed. - **Leaving it to the last day.** Exports can take time to arrive by email. Start collecting evidence the day the dispute opens. ## Doing this with NoChurn NoChurn's Gorgias connector is read-only: it reads tickets and never replies, tags or runs actions in Gorgias. Tickets are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. For disputes on Stripe or Braintree, NoChurn gathers the evidence automatically (cancel flow answers, emails sent, usage, and matched Gorgias messages quoted verbatim with their dates), drafts the response with AI, and submits it only after you review it. Disputes on other processors are not handled by NoChurn. See [NoChurn + Gorgias](/integrations/gorgias/). --- # How to spot churn signals in Gorgias tickets Source: https://www.nochurn.sh/blog/gorgias-churn-signals/ In a subscription store, most cancellations are preceded by a support ticket that did not say "cancel". A late box. A damaged jar. A question about why the price went up. A request to skip, then another skip. Each one is handled, closed and forgotten, and two months later the subscription ends. This guide shows how to use Gorgias's built-in signals (intents, sentiments, managed ticket fields, tags and the customer timeline) to see those patterns, and how to check which ones actually come before cancellations in your store. It relies on Gorgias's documentation: [intents and sentiments](https://docs.gorgias.com/en-US/customer-intents-81924), [customer sentiments](https://docs.gorgias.com/intents-sentiments/customer-sentiments), [ticket fields](https://docs.gorgias.com/en-US/articles/ticket-fields-63498), [rules](https://docs.gorgias.com/en-US/create-rules-to-take-automatic-actions-on-tickets-81746), [customer history](https://docs.gorgias.com/en-US/review-customer-history-in-gorgias-2390890), [helpdesk performance reports](https://docs.gorgias.com/en-US/ticket-insights-statistics-406733), the [tags report](https://docs.gorgias.com/en-US/gather-ticket-insights-tags-208290) and [exporting tickets](https://docs.gorgias.com/en-US/export-tickets-from-gorgias-404844) (all accessed November 2026). For handling the cancellation itself, see [subscription cancellations in Gorgias](/blog/gorgias-subscription-cancellations/). ## The signals that matter in subscription commerce These are hypotheses to test, not rules: | Signal | Example | Gorgias source | |---|---|---| | Delivery problems | Late, lost or damaged box | Intents such as Order/Damaged, Shipping/Status | | Product disappointment | "Didn't like this flavour" | Negative sentiment, Contact Reason | | Repeated skips or frequency changes | Third skip in a row | Subscription intents, tags | | Price questions | "Why was I charged more?" | Contact Reason, tags | | Threats to leave | "I'll buy elsewhere" | Threatening sentiment | | Repeat contact | Same issue, several tickets | Customer timeline | ## Intents and sentiments: free, automatic labels Gorgias detects intent and sentiment on incoming messages automatically ([intents and sentiments](https://docs.gorgias.com/en-US/customer-intents-81924)). If it cannot assign one confidently, it leaves it blank. **Intents** describe what the customer wants. Gorgias's list includes subscription intents (such as subscription/cancel and subscription/change), order intents (such as Order/Damaged, Order/Wrong and Order/Cancel), Shipping/Status, and refund, return and exchange requests. **Sentiments** describe how they feel. Gorgias's [sentiments page](https://docs.gorgias.com/intents-sentiments/customer-sentiments) documents, among others: - **negative**: general dissatisfaction with a product or the service; - **threatening**: the customer threatens legal action, buying elsewhere or a negative review; - **urgent**: impatience after several unsuccessful contacts, or an urgent need such as cancelling an order before it ships. For churn, "threatening" is the most direct signal: "I'll buy elsewhere" is a cancellation in waiting. "urgent" after repeated contacts says your support is losing the customer, whatever the original problem was. ### Turn them into tags with rules Intents and sentiments are visible on messages, but tags are easier to report on. Gorgias [rules](https://docs.gorgias.com/en-US/create-rules-to-take-automatic-actions-on-tickets-81746) can add tags based on detected intents and sentiments. Use **ticket created** or **new message** as the trigger: Gorgias notes that "ticket updated" does not fire on intent changes. For example: 1. WHEN new message, IF message sentiments contain "threatening", THEN add tag `risk-threat` and set priority high. 2. WHEN ticket created, IF intents contain Order/Damaged, THEN add tag `risk-delivery`. Tags are case-sensitive in Gorgias, so agree on one spelling. ## Contact Reason: the human label Gorgias's managed [ticket fields](https://docs.gorgias.com/en-US/articles/ticket-fields-63498) include **Contact Reason**, **Resolution** and **Product**, with suggested dropdown values you can edit. Gorgias can pre-fill Contact Reason with AI once it has enough labelled history. Its advice is to describe what the customer sees ("Delayed shipment"), not the internal cause ("Warehouse problem"). Contact Reason and Product together answer a question intents cannot: which product generates the most disappointment. Make sure agents confirm the field before closing a ticket. ## Repeat contact: the customer timeline Gorgias's [customer timeline](https://docs.gorgias.com/en-US/review-customer-history-in-gorgias-2390890) shows a customer's tickets alongside their Shopify orders (for Shopify stores). The sidebar shows a ticket count and previews the three most recent tickets. Make it a habit for agents: when a customer has several recent tickets, open the timeline before replying. Three tickets about late deliveries in two months is a customer about to leave, even if each ticket was "resolved". ## Where to look: Analytics Gorgias's [helpdesk performance reports](https://docs.gorgias.com/en-US/ticket-insights-statistics-406733) let you track tags, ticket fields and intents over time and break them down by store, channel or agent. The [tags report](https://docs.gorgias.com/en-US/gather-ticket-insights-tags-208290) shows the 10 most used tags for the period, a trend chart and a full table you can export as CSV; you can choose whether the date range applies to when the tag was added or when the ticket was created. A monthly review: 1. Trend of `risk-` tags and of negative and threatening sentiment. 2. Contact Reason by Product: which products drive complaints. 3. Resolution on subscription tickets: how many ended in a cancellation versus a skip or swap. ## Checking signals against real cancellations Gorgias shows you what customers talk about. Only your subscription data shows who left. To connect them: 1. **Export tickets.** From a view, you get ticket data such as tags, subject and timings; from the Analytics drill-down you can export with message content for the most recent 30 days of the period ([exporting tickets](https://docs.gorgias.com/en-US/export-tickets-from-gorgias-404844)). 2. **Export subscriptions** from your subscription app: customer email, start date, cancellation date and reason if captured. 3. **Join on email.** For each subscriber who cancelled, list their tags and Contact Reasons in the 90 days before. Do the same for a similar group who did not. 4. **Compare.** Keep the signals that show up clearly more often before cancellations. Show counts with every percentage; a pattern in eight customers is a lead, not a fact. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) covers the method, including why correlation is not cause. ## What to do when you see a signal - **Delivery problem**: fix it and say so. A replacement or credit on the second problem often matters more than the first. - **Product disappointment**: offer a swap if your subscription app supports it. - **Repeated skips**: suggest a slower frequency instead of another skip. - **Threat to leave**: answer the complaint itself, promptly, from a person. - **Clear cancellation request**: cancel. Do not use signals as a reason to delay. ## Common mistakes - **Too many tags.** Ten `risk-` tags nobody applies consistently are worse than three that everyone trusts. Start small and add only when a new signal proves useful. - **Treating sentiment as a verdict.** AI-detected sentiment is a hint. "This is killing me, I love it" can read as negative. Agents should correct obvious errors. - **Counting tickets, not customers.** One very vocal subscriber can produce ten negative tickets. Report signals per customer as well as per ticket. - **Ignoring the quiet ones.** Many subscribers cancel without ever opening a ticket. Support signals cover only the customers who talk to you; usage, skips and failed payments cover the rest. - **Reviewing once and forgetting.** Signals change with seasons, products and prices. Repeat the comparison every quarter. ## Doing this with NoChurn NoChurn's Gorgias connector is read-only: it reads tickets and never adds tags, replies or runs actions in Gorgias. Tickets are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. They feed a churn score from 0 to 100 and a churn drivers view that ranks attributes by correlation with churn, and are kept as dated, verbatim evidence for disputes on Stripe and Braintree. Intents, rules, fields and Analytics stay in Gorgias. See [NoChurn + Gorgias](/integrations/gorgias/). --- # Using Gorgias satisfaction surveys to keep subscribers Source: https://www.nochurn.sh/blog/gorgias-csat/ Gorgias sends a short survey after a ticket closes: how satisfied were you, from 1 to 5? For a subscription store, each low score is a subscriber telling you, in private, that something went wrong, while they are still a subscriber. Most stores look at the average and move on. The value is in the individual answers, and in what you do in the next 48 hours. This guide explains how Gorgias CSAT surveys are sent and scored, what the satisfaction report does and does not tell you, and how to set up a follow-up routine that uses low scores to keep subscribers. It relies on Gorgias's documentation: [sending CSAT surveys](https://docs.gorgias.com/en-US/send-customer-satisfaction-%28csat%29-surveys-207765), [measuring satisfaction](https://docs.gorgias.com/en-US/measure-ticket-quality-satisfaction-6422690), [excluding tickets from surveys](https://docs.gorgias.com/en-US/exclude-tickets-from-receiving-the-satisfaction-survey-%28csat%29-188964), [chat preferences](https://docs.gorgias.com/en-US/configure-chat-preferences-289563), the [rule builder](https://docs.gorgias.com/en-US/gorgias-rule-builder-variables-and-conditions-81882) and the API's [SatisfactionSurvey object](https://developers.gorgias.com/reference/the-satisfactionsurvey-object) (all accessed November 2026). ## How Gorgias sends surveys Per Gorgias's [CSAT documentation](https://docs.gorgias.com/en-US/send-customer-satisfaction-%28csat%29-surveys-207765): - You choose which ticket types get a survey, write the survey message, and set how long after closing it is sent. With no delay selected, it goes out **2 hours** after the ticket closes; reopening the ticket before then stops it. - A survey is only sent if the ticket has at least one customer message and one agent reply (rule messages and notes do not count), the last agent reply was less than a week before closing, and the channel is chat, email, contact form or Help Center. Social media tickets do not receive surveys. - For chat, CSAT is switched on in the chat integration's Preferences tab ("Send CSAT"), and needs a connected email address to send from ([chat preferences](https://docs.gorgias.com/en-US/configure-chat-preferences-289563)). - You can [exclude tickets](https://docs.gorgias.com/en-US/exclude-tickets-from-receiving-the-satisfaction-survey-%28csat%29-188964) with rules, for example by channel, tag, language or customer email. The API's [SatisfactionSurvey object](https://developers.gorgias.com/reference/the-satisfactionsurvey-object) stores a score from 1 to 5, and there is one survey per ticket. ## What the satisfaction report measures Gorgias's [satisfaction report](https://docs.gorgias.com/en-US/measure-ticket-quality-satisfaction-6422690) defines the **satisfaction score** as the share of rated surveys scoring 4 or 5 among all surveys rated in the period, and the **response rate** as the share of sent surveys that got a response. It shows the 1 to 5 distribution and lets you switch between positive (4–5) and negative (1–3) comments. That is a quality measure for your support team. It is not a churn measure, for three reasons: 1. **It rates one ticket.** A 2 may be about the agent, the product, the delivery company or your refund policy. 2. **Responders are self-selected.** Delighted and furious customers answer more than the indifferent middle. 3. **An average hides the person.** A score that stays steady can contain a handful of very unhappy subscribers. ## Decide which tickets to survey Before you use scores for retention, decide what you want to measure: - **Cancellation tickets.** A survey after a cancellation measures how smooth it was. That is worth knowing, but those scores should not be mixed with the rest. Tag them (`subscription-cancel`) and either exclude them from the survey or report on them separately. - **Refund disputes and complaints in progress.** If a customer is already angry about a charge, a survey link can feel tone-deaf. Consider excluding tickets tagged with an open refund or dispute. - **Everything else.** Delivery issues, product questions, subscription changes: these are where a low score is an early warning. ## Write a survey message that invites a useful answer Gorgias lets you write the survey message yourself ([sending CSAT surveys](https://docs.gorgias.com/en-US/send-customer-satisfaction-%28csat%29-surveys-207765)). A few choices make the answers more useful for retention: - **Keep it short and specific to the ticket.** "How did we do with your question about your last box?" reads better than a generic request for feedback. - **Ask for a comment, not just a score.** One line inviting the customer to say what could have been better gives you the reason behind a low score, which is what you will act on. - **Do not promise a reward for a good rating.** It skews the answers and makes the score meaningless. - **Say who reads it.** "A member of our team reads every answer" is only worth writing if it is true, and it makes customers more likely to explain themselves. ## The follow-up routine The goal is simple: every subscriber who scores 1 or 2 hears from a person within one working day. ### Step 1: find low scores quickly Gorgias's [rule builder](https://docs.gorgias.com/en-US/gorgias-rule-builder-variables-and-conditions-81882) includes a **Satisfaction Survey Responded** trigger, which runs when a customer submits a response. Use it to tag or reopen tickets for review. Whether your rule builder lets you filter that rule by the score itself is something to check in your account; the documentation we reviewed does not spell it out. If it does not, review the negative comments view in the satisfaction report every morning instead. ### Step 2: read before replying Open the customer timeline. Is this their first problem or their third? Did a box arrive late last month too? Are they on their first order or their twentieth? The reply depends on the answer. ### Step 3: reply to the specific problem A follow-up that says "Sorry you had a bad experience, here's 10% off" teaches nothing and costs margin. A follow-up that says "You said the replacement arrived damaged too. I've sent another by express and flagged the packaging issue to our warehouse" keeps subscribers. Match the response to the cause: | What the low score was about | Useful follow-up | |---|---| | Delivery late or damaged | Replacement or credit, and what you changed | | Product disappointment | Offer a swap to another product | | Slow or unhelpful reply | Apology from a lead, and the actual answer | | Price or policy | Clear explanation; offer what you genuinely can | | Cancellation process | Fix the process; do not try to win them back in the same message | ### Step 4: record the outcome Add a tag such as `csat-followed-up` and use the Resolution ticket field. After a quarter, you can see whether subscribers who got a follow-up stayed longer than those who did not. ## Checking whether scores predict cancellations Do it once with your own data before building a habit around it: 1. Export low and high scores with customer email and date. 2. Join with subscription data: who cancelled within 90 days. 3. Compare groups: scored 1–2, scored 3, scored 4–5, never responded. 4. Report counts, not just percentages. With a few dozen low scores, small differences mean nothing. If low scorers cancel clearly more often, the follow-up routine is worth its time. If not, CSAT stays a support quality tool and you look for churn signals elsewhere, such as [intents and sentiments](/blog/gorgias-churn-signals/), repeated skips or failed payments. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) covers the method. ## Doing this with NoChurn NoChurn's Gorgias connector is read-only: it reads tickets and never sends surveys, tags or replies in Gorgias. Tickets are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. Matched tickets feed a churn score from 0 to 100 and a churn drivers view (correlation, not causation, with sample sizes), and serve as dated, verbatim evidence for disputes on Stripe and Braintree. Survey settings, follow-ups and the satisfaction report stay in Gorgias. See [NoChurn + Gorgias](/integrations/gorgias/). --- # How to handle refund requests in Gorgias Source: https://www.nochurn.sh/blog/gorgias-refund-requests/ For a subscription store, a refund request is a fork in the road. Answered quickly and clearly, it ends with a refund or an explanation the customer accepts. Left for three days, it often ends with the customer calling their bank, and a chargeback that costs you the payment, a fee and your time. This guide sets up a refund process in Gorgias that keeps requests on the first path: detect them automatically, route them to someone who can decide, refund from the ticket with macros, and leave a record that holds up if a dispute comes anyway. Gorgias details come from its documentation: [intents and sentiments](https://docs.gorgias.com/en-US/customer-intents-81924), [rules](https://docs.gorgias.com/en-US/create-rules-to-take-automatic-actions-on-tickets-81746), [macros](https://docs.gorgias.com/en-US/macros-101-81846), [macro actions](https://docs.gorgias.com/en-US/macro-actions-81913), [ticket fields](https://docs.gorgias.com/en-US/articles/ticket-fields-63498) and the [Recharge integration](https://docs.gorgias.com/en-US/recharge-81874). Refund and dispute rules come from Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) and [refunds](https://docs.stripe.com/refunds) pages (all accessed November 2026). ## Why speed matters If your store takes payments through Stripe, its documentation is clear on the timing: - **While a formal dispute is open, you cannot refund outside the dispute process** ([how disputes work](https://docs.stripe.com/disputes/how-disputes-work)). You accept or challenge. - **At the inquiry stage**, a full refund can resolve the case without a dispute fee; inquiries on partially refunded charges can still escalate. - **If a dispute arrives while a refund is pending**, Stripe recommends handling the dispute rather than refunding again, to avoid refunding twice. Other processors have their own rules, but the logic is the same: a refund issued before the customer contacts their bank is almost always cheaper than a dispute. ## Step 1: detect refund requests automatically Gorgias detects intents on incoming messages ([intents and sentiments](https://docs.gorgias.com/en-US/customer-intents-81924)). Its list includes **Refund/Request** (requests to process a refund) and **Refund/Status**, along with return and exchange requests and order problems such as **Order/Damaged** and **Order/Wrong**. Its sentiments include **threatening** (legal action, buying elsewhere, negative reviews) and **urgent**. A refund request with a threatening sentiment ("refund me or I'll dispute it") is the one to answer first. Build a [rule](https://docs.gorgias.com/en-US/create-rules-to-take-automatic-actions-on-tickets-81746): 1. **WHEN** ticket created (or new message; Gorgias notes that "ticket updated" does not fire on intent changes). 2. **IF** intents contain Refund/Request, and the message is not from an agent. 3. **THEN** add the tag `refund-request`, assign to the team that can approve refunds, and set priority high. Add a second rule for messages with threatening sentiment that also mention a charge, and route them to a lead. ## Step 2: decide with a written policy Agents should be able to decide most refunds without escalation. A simple table, matched to your published terms: | Situation | Typical decision | |---|---| | Charged after a cancellation request you missed | Full refund, apology, cancel the subscription | | Box arrived damaged or wrong | Replacement or refund, customer's choice | | Box never arrived, tracking shows a problem | Replacement or refund | | Forgot to skip, box not shipped yet | Cancel the order and refund | | Forgot to skip, box already delivered | Per your policy; a partial refund or credit is common | | "I didn't authorise this" | Check the account; if it looks like fraud, refund and secure the account | Write down who can approve what, and above which amount a lead decides. A refusal must come with a reason and a reference to your terms, not silence. ## Step 3: refund from the ticket with macros Gorgias [macro actions](https://docs.gorgias.com/en-US/macro-actions-81913) let a macro do the refund and send the reply in one step. Per Gorgias's documentation: - **Shopify actions** include cancelling the last order or a specific order, refunding the last order's shipping cost, and a partial refund of the last order, where the agent chooses the amount. - **Recharge actions** include Cancel last subscription, Activate last subscription, Refund last charge and Refund last order. - Actions run when the macro is sent, and if a macro action fails, the ticket is reopened. The [Recharge integration](https://docs.gorgias.com/en-US/recharge-81874) also lets agents refund a charge, partially or fully, from the ticket sidebar, and notes that orders created through Recharge must be cancelled from the Recharge order, not the Shopify order. Useful macros: 1. **Refund last charge + keep subscription**: for a damaged or missing box. Reply confirming the amount and that the subscription continues. 2. **Refund last charge + cancel subscription**: for "I asked to cancel and was charged". Reply confirming both, with the date. 3. **Partial refund**: for partial issues, with the amount stated in the reply. 4. **Decline with reason**: no action, a reply explaining the decision and the terms, and an offer of what you can do. Two cautions: "last" means the most recent order or charge, so check the sidebar before sending when the customer has several; and Gorgias notes that some Shopify actions fail when a customer has profile data in more than one connected store. ## Step 4: record the outcome Gorgias's managed [ticket fields](https://docs.gorgias.com/en-US/articles/ticket-fields-63498) include **Contact Reason** and **Resolution**. Set Resolution on every refund ticket: Full refund, Partial refund, Replacement, Store credit, Declined. Add the reason from the customer's point of view in Contact Reason (Damaged item, Not received, Charged after cancelling, Forgot to skip). After a quarter, you can answer: why do customers ask for refunds, how long do we take to answer, and which declined requests turned into disputes. If declined requests often turn into lost disputes, the policy or how you explain it needs work. ## Common mistakes - **Store credit as the only option.** Credit is a good offer, but when a customer asks for their money back and is entitled to it, insisting on credit pushes them toward their bank. - **Refunding without stopping the next charge.** If the customer wants to leave, refund and cancel in the same step, or the next renewal brings a new complaint. - **Partial refunds by default.** They feel like a compromise, but on Stripe an inquiry on a partially refunded charge can still escalate. - **Running "last order" macros blind.** Check which order or charge is the last one before sending, especially for customers with several subscriptions. - **No reply after the refund.** Confirm the amount and the timing in writing. That message is your record if the customer disputes anyway. ## When a dispute comes anyway Some customers will dispute even after a clear answer. Then the ticket is your evidence: the dated request, your reply, the refund or the reasoned refusal, and any earlier tickets showing delivery or use. See [how to use Gorgias tickets as chargeback evidence](/blog/gorgias-chargeback-evidence/). And if a cancellation request is behind the refund, fix that first: [handling subscription cancellations in Gorgias](/blog/gorgias-subscription-cancellations/). ## Doing this with NoChurn NoChurn's Gorgias connector is read-only: it reads tickets and does not issue refunds, run macros or reply in Gorgias. Tickets are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. If a dispute opens on Stripe or Braintree, NoChurn gathers the evidence (cancel flow answers, emails sent, usage, and the matched refund ticket quoted verbatim with dates), drafts a response with AI and submits it only after you review it; disputes on other processors are not handled by NoChurn. Refund decisions stay with you. See [NoChurn + Gorgias](/integrations/gorgias/). --- # How to handle subscription cancellations in Gorgias Source: https://www.nochurn.sh/blog/gorgias-subscription-cancellations/ Ecommerce subscriptions (coffee, supplements, pet food, skincare refills) are cancelled differently from SaaS. Customers often write "please stop my next box" in a chat or an email reply to their shipping notice, sometimes a day before the order ships. If your store runs support on Gorgias, those messages arrive next to order-status questions and returns, and speed matters: a cancellation handled after the charge turns into a refund, and sometimes into a chargeback. This guide shows how to detect cancellation requests in Gorgias, act on them quickly from the ticket, record why customers leave, and read satisfaction surveys on those tickets. It sticks to Gorgias's documentation: [intents and sentiments](https://docs.gorgias.com/en-US/customer-intents-81924), [rules](https://docs.gorgias.com/en-US/create-rules-to-take-automatic-actions-on-tickets-81746), [macros](https://docs.gorgias.com/en-US/macros-101-81846) and [macro actions](https://docs.gorgias.com/en-US/macro-actions-81913), [ticket fields](https://docs.gorgias.com/en-US/articles/ticket-fields-63498), the [Recharge integration](https://docs.gorgias.com/en-US/recharge-81874) and [CSAT surveys](https://docs.gorgias.com/en-US/satisfaction-survey-%28csat%29-101-81850) (all accessed November 2026). ## Where the cancellation actually happens Gorgias is a help desk; the subscription lives in a subscription app on your store. Gorgias documents a [Recharge integration](https://docs.gorgias.com/en-US/recharge-81874) that shows Recharge subscriptions in the ticket sidebar and lets agents cancel or reactivate a subscription and refund a charge, partially or fully, without leaving the ticket. To cancel from the sidebar, the agent opens Subscriptions, clicks Cancel, then Confirm. One caveat from that page: orders that went through Recharge must be cancelled with the Cancel button on the Recharge order, not on the Shopify order, or the cancellation will not work. Gorgias also documents AI Agent actions for [Recharge subscriptions](https://docs.gorgias.com/en-US/ai-agent-actions-manage-recharge-subscriptions-757839) and for [Loop Subscriptions](https://docs.gorgias.com/en-US/ai-agent-actions-loop-subscriptions-943225). If you use another subscription app, check its own Gorgias documentation; without an integration, agents cancel in the app's admin and confirm in the ticket. ## Step 1: detect cancellation requests ### Intents Gorgias detects intent and sentiment on incoming messages automatically ([intents and sentiments](https://docs.gorgias.com/en-US/customer-intents-81924)). Its intent list includes **subscription/cancel** (requests to cancel a subscription, such as an auto-shipment or monthly order) and **subscription/change** for edits. If the system cannot assign an intent confidently, it leaves it blank, so intents are a strong hint, not a guarantee. ### A rule to tag and route them Gorgias [rules](https://docs.gorgias.com/en-US/create-rules-to-take-automatic-actions-on-tickets-81746) follow a WHEN, IF, THEN structure. A rule for cancellations: 1. **WHEN** a ticket is created (Gorgias notes that "ticket updated" triggers do not fire on changes to message intents, so use ticket created or new message). 2. **IF** the message intents contain subscription/cancel, and the message is not from an agent. 3. **THEN** add the tag `subscription-cancel`, assign the ticket to the team that handles subscriptions, and set a high priority. Tags in Gorgias are case-sensitive (`Subscription-Cancel` and `subscription-cancel` are two different tags), so agree on one spelling and stick to it. Gorgias's rule templates also include an auto-tag template for subscription cancellations labelled as Recharge only. ## Step 2: cancel fast, with one macro Gorgias [macros](https://docs.gorgias.com/en-US/macros-101-81846) combine a reply with actions that run when the macro is sent. The [macro actions](https://docs.gorgias.com/en-US/macro-actions-81913) page lists Recharge actions including **Cancel last subscription**, **Activate last subscription**, **Refund last charge** and **Refund last order**. Gorgias also notes that if a macro action fails, the ticket is reopened. A "Cancel subscription" macro could: 1. Reply to the customer confirming the cancellation, with the date and whether an upcoming order is still shipping. 2. Run Cancel last subscription. 3. Add the tag `cancel-done`. 4. Set the Contact Reason and Resolution fields (step 3). Two cautions before you let everyone use it: - **"Last subscription" means one subscription.** If a customer has several (two products on different schedules), check which one they mean in the sidebar before sending the macro. - **Check the next order.** If an order has already been generated, the customer needs to know whether it will ship and be charged, and you may need to cancel that order in Recharge too. ## Step 3: record the reason and the outcome Gorgias's [ticket fields](https://docs.gorgias.com/en-US/articles/ticket-fields-63498) include three managed, ecommerce-specific fields: **Contact Reason**, **Resolution** and **Product**. Contact Reason and Resolution come with suggested dropdown values you can edit. Gorgias's advice for Contact Reason is to describe what the customer can see, not the internal cause. Only admins create fields; anyone who can reply can fill them in. For cancellations, useful Resolution values are: Cancelled, Skipped next order, Changed frequency, Swapped product, Paused, Customer withdrew request. Useful reason values, captured from what the customer wrote: Too much product, Too expensive, Didn't like product, Shipping problem, Moving, Other. That gives you a monthly view of why subscribers leave and what share accepted an alternative, using your own data rather than an industry benchmark. ## When to offer skip, frequency change or swap Ecommerce subscriptions have alternatives that SaaS lacks. A customer who writes "I have too much coffee" usually needs a skip or a slower frequency, not a discount. A rough guide: | What the customer says | Reasonable alternative | Just cancel | |---|---|---| | "I have too much left" | Skip next order or change frequency | If they say they are done | | "Too expensive" | Smaller size or less frequent delivery | If they already decided | | "Didn't like the flavour" | Swap product | If they want to stop | | "Moving / travelling" | Pause or skip | | | "Shipping keeps arriving late" | Fix the shipping problem, apologise | Often | The rule that does not change: if the customer asks to cancel, cancel. Mention one alternative in the same reply if it fits the reason; do not hold the cancellation until they answer. See our [click-to-cancel rules](/blog/click-to-cancel-rules/) and [pause vs discount](/blog/pause-vs-discount-retention-offers/) guides. ## Step 4: read CSAT on cancellation tickets separately Gorgias [CSAT surveys](https://docs.gorgias.com/en-US/satisfaction-survey-%28csat%29-101-81850) are configured from Workflows, then Tools, then CSAT for email, contact form and Help Center tickets, and from the chat preferences for chat. The docs list eligibility conditions: the ticket needs at least one customer message and one agent reply, the last agent reply must be less than a week old when the ticket closes, and the channel must be chat, email, contact form or Help Center. Scores go from 1 to 5, and Gorgias's [satisfaction report](https://docs.gorgias.com/en-US/measure-ticket-quality-satisfaction-6422690) counts 4 and 5 as positive. You can [exclude tickets from the survey](https://docs.gorgias.com/en-US/exclude-tickets-from-receiving-the-satisfaction-survey-%28csat%29-188964) with rules, for example by tag. Whether to survey cancellation tickets is your call. If you do, filter them by your `subscription-cancel` tag and read them apart from other tickets: a 5 means the cancellation was quick and clear, which is what you want. A 1 with "I asked twice and was still charged" is a process problem, and a likely chargeback. ## Doing this with NoChurn NoChurn's Gorgias connector is read-only: it reads tickets and never replies, tags or runs actions in Gorgias. Tickets are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. They feed the churn score and churn drivers, and are kept as dated, verbatim evidence if a customer later disputes a charge processed on Stripe or Braintree. Subscription changes made from Gorgias, such as the Recharge cancel button and macros, stay in Gorgias and your subscription app. See [NoChurn + Gorgias](/integrations/gorgias/). --- # How to handle cancellation requests in Help Scout Source: https://www.nochurn.sh/blog/help-scout-cancellation-requests/ Many subscription businesses still receive a good share of cancellations by email: "please cancel my account", "stop charging me", "how do I unsubscribe?". If your support runs on Help Scout, those emails land in the same inbox as bug reports and how-to questions, and they are handled however the agent on shift sees fit. This guide sets out a consistent, fair way to handle them: cancel promptly, ask one optional question, offer something only when it fits the reason, and confirm in writing. It shows how to support that process with Help Scout's own tools, based on its documentation: [saved replies](https://docs.helpscout.com/article/18-create-saved-replies-for-fast-answers), [variables](https://docs.helpscout.com/article/468-work-with-variables), [tags](https://docs.helpscout.com/article/13-create-and-manage-tags), [workflows](https://docs.helpscout.com/article/22-get-started-with-workflows), [automatic workflows](https://docs.helpscout.com/article/1399-automatic-workflows), [email satisfaction ratings](https://docs.helpscout.com/article/386-gather-feedback-with-satisfaction-ratings) and the [Happiness report](https://docs.helpscout.com/article/383-reports-happiness) (all accessed November 2026). Help Scout does not manage your billing, so the cancellation itself happens in your billing system or app. ## The ground rule: never harder than signing up Whatever you do in the inbox, cancelling by email should not be harder than signing up was. In practice: - **A cancellation request is executed.** If the customer clearly asks to cancel, you cancel. You do not wait for them to answer a survey, call you, or reply to an offer. - **Offers are optional and come once.** You can mention an alternative in the same reply that confirms the cancellation, or in a reply that asks a genuinely necessary question. You do not reply with an offer and leave the cancellation pending. - **The customer gets a written confirmation** with the date the cancellation takes effect. Rules differ by country and change over time; our guide on [click-to-cancel rules](/blog/click-to-cancel-rules/) summarises where things stand. The process below is designed to stay on the right side of them, but it is not legal advice. ## Step 1: recognise cancellation emails with a workflow Help Scout [workflows](https://docs.helpscout.com/article/22-get-started-with-workflows) come in two kinds: automatic workflows, which run in the background on conversations that match their conditions, and manual workflows, which an agent runs on demand and which skip the conditions step. Per Help Scout's [automatic workflows article](https://docs.helpscout.com/article/1399-automatic-workflows): - Conditions support AND and OR logic, up to 30 conditions per workflow, and condition values are not case-sensitive. - An automatic workflow runs on a given conversation only once. - "Apply to Previous" can apply the actions retroactively to existing conversations that match. A simple setup: 1. Create an automatic workflow with OR conditions on the subject or body containing phrases such as "cancel my", "cancel subscription", "close my account", "unsubscribe" and "stop charging". 2. Add the action **Add Tag(s)** with `cancellation-request`. Tags can be added from both automatic and manual workflows ([tags article](https://docs.helpscout.com/article/13-create-and-manage-tags)). 3. Assign the conversation to the person or team who can cancel accounts. 4. Create a manual workflow "Cancellation handled" that agents run after cancelling: it adds a tag with the outcome (see step 4) and closes the conversation. Keyword rules will catch some emails that are not cancellations ("can I cancel the invite I sent?"). Agents should remove the tag when it is wrong; that keeps your counts honest. ## Step 2: write saved replies for each case Help Scout's [saved replies](https://docs.helpscout.com/article/18-create-saved-replies-for-fast-answers) are managed per inbox under Settings > Inboxes > your inbox > Saved Replies, and can include [variables](https://docs.helpscout.com/article/468-work-with-variables) for the customer's name, the agent's name and other fields. Three replies cover most requests. **Cancelled, no offer.** For customers who are clearly done: the product does not fit, the company closed, they found another tool. > Hi [first name], your subscription is cancelled. You will not be charged again. You keep access until [date], the end of the period you already paid for. If you have a moment, what was the main reason you cancelled? Replying is completely optional. **Cancelled, with a relevant alternative.** For reasons where an alternative might genuinely help, such as a temporary break or budget. The cancellation is still done; the alternative is an easy way back. > Hi [first name], your subscription is cancelled and you will not be charged again. Since you mentioned [reason], one option if it helps: we can [pause your account for up to N months / move you to the smaller plan] instead, so your data stays as it is. Just reply "pause" and we will switch it. Otherwise, nothing else to do. **Need one detail.** Only when you truly cannot identify the account (several accounts on one email, a different email from the one on file). Ask for the minimum, and cancel as soon as you have it. Keep the brackets as placeholders your agents fill in; do not promise anything your billing system cannot do. ## Step 3: when a pause or discount is worth offering Offers work when they answer the reason the customer gave, and backfire when they look like a toll gate. A rough guide: | Reason given | Reasonable alternative | Usually better to just cancel | |---|---|---| | "Taking a break", seasonal use | Pause | | | "Too expensive right now" | Smaller plan or a time-limited discount | If they already said they are switching | | "Missing feature X" | Tell them honestly if X is planned, without dates you cannot keep | Yes, in most cases | | "We are closing the company" | | Yes | | "Bad experience with support" | An apology and a fix, not a discount | Often | Do not offer the same discount to everyone who writes "cancel": customers learn that asking to cancel is how you get a discount. Our guide to [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/) goes into more detail. ## Step 4: tag the outcome, not just the request Add a second tag when the conversation is closed, so you can measure what happened: - `cancel-done` - `cancel-paused` (customer chose a pause) - `cancel-downgraded` - `cancel-withdrawn` (customer changed their mind on their own) Help Scout's views and workflow filters support conditions such as "is tagged with any", "is tagged with all" and "is not tagged with" ([tags article](https://docs.helpscout.com/article/13-create-and-manage-tags)). A view of conversations tagged `cancellation-request` but with no outcome tag shows requests that were left hanging, which is the one number you want at zero. ## Step 5: read satisfaction ratings with care Help Scout's [email satisfaction ratings](https://docs.helpscout.com/article/386-gather-feedback-with-satisfaction-ratings) are enabled per inbox and add rating links to outgoing replies. Customers pick Great, Okay or Not Good, can add an optional comment, and have 10 days from a reply to rate it or change their rating. The [Happiness report](https://docs.helpscout.com/article/383-reports-happiness) shows the share of each rating and a Happiness Score (percentage of Great minus percentage of Not Good). Ratings are indexed by the date of the reply, not the date of the rating. On cancellation conversations, a rating measures how the cancellation was handled, not whether the customer likes your product. A "Great" on a fast, clean cancellation is a good result. A "Not Good" with "I had to email three times" points to a broken process. Help Scout suggests using workflows to flag poor ratings with comments for follow-up; on cancellations, that follow-up is to fix whatever went wrong, not to win the customer back. ## Doing this with NoChurn NoChurn's Help Scout connector is read-only: it reads conversations and never replies, tags or closes anything in Help Scout. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. They feed the churn score and churn drivers, and serve as dated, verbatim evidence if a cancelled customer later files a chargeback on Stripe or Braintree. If you want fewer cancellations arriving by email at all, NoChurn's cancel flow gives customers a self-serve path with a reason, an optional offer (discount, pause or plan change) and a one-click cancel button that is always visible, hosted or through the API. See [NoChurn + Help Scout](/integrations/help-scout/). --- # How to use Help Scout conversations as chargeback evidence Source: https://www.nochurn.sh/blog/help-scout-chargeback-evidence/ Email support creates exactly the kind of record a dispute reviewer trusts: dated messages, sent from the customer's own address, in their own words. If you use Help Scout, every one of those messages is there. The difficulty is getting them out in a form that a reviewer at a card issuer can read in a few minutes, because Help Scout has no single "export this conversation as PDF" button documented. This guide covers what to collect, how to extract complete threads with their timestamps, and how to present them on Stripe or Braintree. Help Scout details come from its documentation: [customer profiles](https://docs.helpscout.com/article/73-customer-profiles), [merging conversations](https://docs.helpscout.com/article/31-merging-conversations), [exporting reporting data](https://docs.helpscout.com/article/849-export-reporting-data), [data export options](https://docs.helpscout.com/article/466-data-export-options), and the Inbox API's [List Conversations](https://developer.helpscout.com/mailbox-api/endpoints/conversations/list/) and [List Threads](https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/list/) endpoints. Dispute details come from Stripe's [dispute categories](https://docs.stripe.com/disputes/categories), [best practices](https://docs.stripe.com/disputes/best-practices) and [Update a dispute](https://docs.stripe.com/api/disputes/update), and Braintree's [evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/php) (all accessed November 2026). ## Why email threads make good evidence A reviewer is trying to answer a few questions. For subscriptions: - Did the customer know they would be charged? - Did they use the service after the charge? - Did they ask to cancel, and what happened? An email thread can answer all three with the customer's own words and a date the customer cannot easily contest, because it came from their address. That makes it stronger than an internal log or a summary you write after the fact. On Stripe, these messages fit the `customer_communication` field; Stripe's [best practices](https://docs.stripe.com/disputes/best-practices) recommend combining several communications into one file. Text fields such as `uncategorized_text` accept up to 20,000 characters ([Update a dispute](https://docs.stripe.com/api/disputes/update)). On Braintree, the [evidence requirements guide](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/php) lists emails or other correspondence with the customer among helpful evidence; whether it goes in as text or as a file depends on the reason code. ## What to collect | Item | Why it helps | Where in Help Scout | |---|---|---| | Messages after the disputed charge | Shows continued use | The customer's conversations | | Questions that mention the plan, invoice or renewal | Shows awareness of the subscription | Same | | Any cancellation request and your reply | Shows what was asked and what you did | Same, often tagged | | Your confirmation of cancellation or refund | Shows the resolution | Your reply in the thread | | Satisfaction rating on that reply, if any | Context only | The conversation | Leave out internal notes. Help Scout threads include notes alongside customer and agent messages; notes are written for colleagues, are rarely useful to a reviewer, and can read badly out of context. ## Step 1: find all the customer's conversations Open the [customer profile](https://docs.helpscout.com/article/73-customer-profiles): it shows the full conversation history for that contact. Two things to check: - **Permissions.** Help Scout's [customers list documentation](https://docs.helpscout.com/article/1328-customers-list) says account owners and administrators see all of a customer's conversations, while users only see conversations in inboxes they can access. Have an admin collect the evidence, or you may miss a thread. - **Other addresses.** Customers write from work and personal addresses. Search for their name and company too. ## Step 2: get each thread with its timestamps Two ways, depending on volume. **One dispute, a few conversations.** Open each conversation and print it from your browser to PDF. Check that every message in the printout shows its date and time; if your browser view hides them, use the API route instead. **Regular disputes.** Use the Inbox API: 1. Collect the customer's conversation IDs from their profile, or find them with [List Conversations](https://developer.helpscout.com/mailbox-api/endpoints/conversations/list/). Pass `status=all`: by default the endpoint lists only active conversations, and a closed cancellation thread is exactly what you need. 2. For each conversation, call [List Threads](https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/list/). Each thread has a `type` (customer, message, note, chat and others) and a `createdAt`. 3. Keep `customer` and `message` threads, drop `note`, and sort everything by `createdAt`. 4. Render the result as a simple document: date and time with time zone, sender, full text. Help Scout's [reporting exports](https://docs.helpscout.com/article/849-export-reporting-data) (CSV or XLSX) do not include thread contents, so they help you find conversations but cannot serve as evidence themselves. ## Step 3: build one timeline Put Help Scout messages and billing events on the same timeline: - Signup, renewal reminders, the disputed charge, any refund. - Each relevant message from the customer, quoted in full. - Each relevant reply from your team. Put all times in one time zone and say which. Help Scout and your payment provider may display different zones; a message that looks like it came before a charge in one zone can come after it in another. ## Step 4: write the cover note and submit A short paragraph in plain language, then the evidence. For example: > The customer renewed on [date]. On [date] and [date], after the renewal, they wrote to support about [feature] (messages 1 and 2, sent from the account email). They did not ask to cancel before opening the dispute. Complete conversation history attached. Rules for the quotes: 1. **Quote, don't paraphrase.** Full messages, or excerpts marked with "[…]". 2. **Don't edit.** No corrected typos, no translations without the original next to them. 3. **Include what hurts.** If the customer asked to cancel and the reply was late, say so. If the request was missed, accepting the dispute and fixing the process may be the right call. 4. **Remove what isn't needed.** Other people's details in forwarded emails, internal notes, anything resembling card data. ## What a finished timeline looks like A reviewer should be able to read the whole story in under a minute. A simple table at the top of the file works well, with the full messages attached below it: | Date (UTC) | Event | Source | |---|---|---| | [date] | Annual plan renewed, receipt emailed | Billing system | | [date] | Customer asks how to add a teammate | Help Scout, message 1 | | [date] | Agent replies with instructions | Help Scout, message 2 | | [date] | Customer thanks the agent, asks about exports | Help Scout, message 3 | | [date] | Dispute opened | Stripe or Braintree | Every row that cites Help Scout points to a full quote further down. Keep the table factual: no adjectives, no conclusions. The conclusion belongs in the cover note, and it should follow obviously from the rows. ## Prepare before the next one - **Tag cancellation and refund conversations** when they happen, so you can find them in seconds. - **Confirm every cancellation in writing** with the date it takes effect; that reply becomes your evidence. - **[Merge conversations](https://docs.helpscout.com/article/31-merging-conversations) from the same customer** about the same topic, so the story is in one place. - **Keep one contact per person.** Duplicates split the history. For the full dispute process on Stripe, see [how to win chargebacks on Stripe](/blog/win-chargebacks-stripe/). ## Doing this with NoChurn NoChurn's Help Scout connector is read-only: it reads conversations and never changes anything in Help Scout. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. When a dispute opens on Stripe or Braintree, NoChurn gathers the evidence (cancel flow answers, emails sent, usage, and matched Help Scout messages quoted verbatim with their dates), drafts the response with AI, and submits it only after you review it. The decision stays with the card issuer. See [NoChurn + Help Scout](/integrations/help-scout/). --- # How to spot churn signals in Help Scout Source: https://www.nochurn.sh/blog/help-scout-churn-signals/ Help Scout is built to make each conversation feel personal, and it does that well. The side effect is that patterns across conversations are easy to miss: the customer who has written four times this quarter, the rise in "can I get a cheaper plan?", the account that asked how to export everything two weeks before cancelling. This guide shows how to make those patterns visible in Help Scout: what to label, how to label it consistently, where to look, and how to get the data out to check it against real cancellations. It relies on Help Scout's own documentation: [AI Topics](https://docs.helpscout.com/article/1773-categorize-conversations-automatically-with-ai-topics), [categorizing incoming email](https://docs.helpscout.com/article/1580-categorize-email), [tags](https://docs.helpscout.com/article/13-create-and-manage-tags), [custom fields](https://docs.helpscout.com/article/593-custom-fields) and [reporting on them](https://docs.helpscout.com/article/755-report-on-custom-fields), [customer profiles](https://docs.helpscout.com/article/73-customer-profiles), [views](https://docs.helpscout.com/article/1578-create-and-manage-views), [reports](https://docs.helpscout.com/article/385-reports), [data export options](https://docs.helpscout.com/article/466-data-export-options) and the [Inbox API](https://developer.helpscout.com/mailbox-api/endpoints/conversations/list/) (all accessed November 2026). For satisfaction ratings specifically, see our separate guide on [Help Scout ratings as a churn signal](/blog/help-scout-satisfaction-ratings/). ## Three kinds of signal Churn signals in a help desk come in three kinds, and Help Scout handles each differently: | Kind | Example | Best Help Scout tool | |---|---|---| | **What** the customer writes about | Pricing, export, cancellation, a competitor | Tags, AI Topics, custom fields | | **How often** they write | Third conversation about the same bug | Customer profile, Conversations card | | **How it went** | Long wait, several replies, unresolved | Reports, satisfaction ratings | Most teams only track the first. The second is often the strongest, and it is the one Help Scout makes easiest to see for a single customer and hardest to count across all of them. ## Labelling what customers write about ### Tags from workflows Help Scout's [categorizing guide](https://docs.helpscout.com/article/1580-categorize-email) describes adding tags from workflows based on keywords in the subject or body, on how long an email has waited for a reply, or on the sender. For churn, a small set of tags is enough: - `churn-cancel`: cancel, close account, unsubscribe - `churn-price`: too expensive, cheaper plan, discount - `churn-export`: export, download all, delete my data - `churn-competitor`: names of tools you lose customers to Keyword tags are noisy. Ask agents to remove wrong ones; a tag nobody trusts is worse than no tag. ### AI Topics Help Scout also offers [Topics](https://docs.helpscout.com/article/1773-categorize-conversations-automatically-with-ai-topics), currently in beta. Per Help Scout, when you enable it for an inbox, the AI proposes roughly 8 to 15 topics based on your history, which you review before approving; conversations it cannot classify go to an Uncategorized topic. During the beta, manual overrides do not feed back into the model, and Topics can be used as a condition in workflows but not as an action. Topics and your own tags answer the same question from different directions. Topics find themes you did not think of; tags track the specific signals you decided matter. Use both, and compare them once a month. ### Custom fields for the reason [Custom fields](https://docs.helpscout.com/article/593-custom-fields) are available on the Plus and Pro plans; a dropdown can have up to 100 options. A single dropdown "Risk reason" (Price, Missing feature, Bug, Support experience, Switching, None) set by the agent when closing a conversation gives cleaner data than tags. Help Scout can [report on custom fields](https://docs.helpscout.com/article/755-report-on-custom-fields) in the All Channels report, showing each option's share and the matching conversations. ## Seeing how often a customer writes Help Scout creates a [customer profile](https://docs.helpscout.com/article/73-customer-profiles) automatically when someone first writes in, and the profile shows their full conversation history. On Plus and Pro, the sidebar's Conversations card combines recent conversations from the contact and their company ([company management](https://docs.helpscout.com/article/1740-whats-new-with-company-management)). That is the right place for an agent to notice "this is the third time". Make it a habit: before replying to a customer with several recent conversations, read the last two. If the same problem keeps coming back, say so in the reply and escalate it. Counting repeat contacts across all customers is not something the standard reports show directly. That is a job for the API (below). ## Where to look each week Help Scout [views](https://docs.helpscout.com/article/1578-create-and-manage-views) filter conversations by conditions including tags ("is tagged with any", "is tagged with all", "is not tagged with"). Create one view per churn tag, and one combined view "Churn signals: last 7 days". The [All Channels report](https://docs.helpscout.com/article/385-reports) shows how often each tag is used and whether it is rising or falling, and report views can filter report data by inbox, tag, folder, custom field or conversation type. A rising `churn-price` line over two months is worth a conversation with whoever owns pricing. A weekly routine: 1. Open the "Churn signals: last 7 days" view and read each conversation, not just the subject. 2. Fix wrong tags and set the "Risk reason" field. 3. For each customer with a signal, check their profile for earlier conversations. 4. List customers worth a personal follow-up: high value, several signals, or an unresolved problem. ## Checking signals against real churn Tags tell you what customers talk about. Only your billing data tells you who left. To connect the two you need conversation data outside Help Scout. Help Scout's [reporting exports](https://docs.helpscout.com/article/849-export-reporting-data) (CSV or XLSX, for selected reports) contain data about each conversation but not the thread contents. For full conversations, Help Scout's [export options](https://docs.helpscout.com/article/466-data-export-options) point to the API. The [List Conversations](https://developer.helpscout.com/mailbox-api/endpoints/conversations/list/) endpoint returns conversations sorted by `createdAt` by default, and only active conversations unless you pass `status=all`. [List Threads](https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/list/) returns each message with its type and `createdAt`. With that data: 1. Join conversations to subscriptions by customer email. 2. For each customer who cancelled, look at the 90 days before: which tags, how many conversations, any unresolved ones. 3. Do the same for a similar group who did not cancel. 4. Keep the signals that show up clearly more often before cancellations. Drop the rest. Report counts with every percentage. A tag that appears before 4 cancellations out of 6 is a lead to investigate, not a finding. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) covers the method. ## What to do with a signal A churn signal is a reason to help, not a reason to sell: - **Price**: tell the customer about smaller plans or annual pricing if they exist. Do not invent a discount. - **Bug, again**: escalate, and tell the customer what you did. - **Export**: answer fully and quickly. Making export hard does not retain anyone. - **Cancel**: cancel. See our guide to [handling cancellation requests in Help Scout](/blog/help-scout-cancellation-requests/). ## Doing this with NoChurn NoChurn's Help Scout connector is read-only: it reads conversations and never replies, tags or edits anything in Help Scout. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. NoChurn combines them with billing data in a churn score from 0 to 100 and a churn drivers view that ranks attributes by correlation with churn, and keeps messages as dated, verbatim evidence for disputes on Stripe and Braintree. Tags, Topics, views and replies stay in Help Scout. See [NoChurn + Help Scout](/integrations/help-scout/). --- # How to handle refund requests in Help Scout Source: https://www.nochurn.sh/blog/help-scout-refund-requests/ A refund request is often the last step before a chargeback. A customer who asks for their money back and gets a slow or unclear answer may go to their bank instead, and then you lose the payment, pay a dispute fee, and spend time on evidence. A customer who gets a quick, clear answer usually does not. This guide sets out a refund process for teams that support customers in Help Scout: how to recognise refund requests, decide quickly, issue the refund without leaving the conversation if you bill with Stripe, and keep a record that will help if a dispute comes anyway. Help Scout details come from its documentation: the [Stripe app](https://docs.helpscout.com/article/1731-connect-stripe-with-help-scout-to-view-details-in-the-sidebar), [saved replies](https://docs.helpscout.com/article/18-create-saved-replies-for-fast-answers), [tags](https://docs.helpscout.com/article/13-create-and-manage-tags), [workflows](https://docs.helpscout.com/article/1399-automatic-workflows) and [custom fields](https://docs.helpscout.com/article/593-custom-fields). Refund and dispute rules come from Stripe's [refunds](https://docs.stripe.com/refunds), [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) and [dispute categories](https://docs.stripe.com/disputes/categories) pages (all accessed November 2026). ## Refund or dispute: why timing matters Stripe's documentation makes the stakes clear: - **Once a formal dispute is open, you cannot refund the payment outside the dispute process** ([how disputes work](https://docs.stripe.com/disputes/how-disputes-work)). You either accept the dispute or challenge it. - **At the inquiry stage**, before a formal chargeback, a full refund can close the case without a dispute fee; Stripe notes that inquiries on partially refunded charges can still escalate. - **If the customer disputes while a refund is pending**, Stripe recommends accepting or challenging the dispute rather than refunding again, to avoid paying twice. The practical lesson: the cheapest refund is the one you issue before the customer calls their bank. A refund request sitting unanswered for three days is a chargeback risk. ## Step 1: recognise refund requests fast Create an automatic workflow in Help Scout ([automatic workflows](https://docs.helpscout.com/article/1399-automatic-workflows)) with conditions on the subject or body containing words such as "refund", "money back", "charged twice", "didn't authorise", "unauthorized charge" and "chargeback". Actions: 1. Add the tag `refund-request` ([tags](https://docs.helpscout.com/article/13-create-and-manage-tags)). 2. Assign to whoever can approve refunds. Watch for two phrases in particular: "I didn't authorise this" and "I'll contact my bank". The first may be fraud or a family member using the card; the second means a dispute is close. Both deserve an answer the same day. ## Step 2: decide with a simple policy Agents should not have to ask a manager for every refund. Write down a policy that covers most cases and that matches what your terms say: | Situation | Typical decision | |---|---| | Charged after a cancellation request you missed | Refund in full, apologise | | Renewal the customer forgot about, no use since | Refund or partial refund, per your policy | | Duplicate charge | Refund the duplicate | | "I didn't authorise this" | Check the account; if it looks like fraud, refund and secure the account | | Partial use, wants full refund | Per your policy; explain clearly either way | | Long-term active user asking after months of use | Usually decline, politely, with the reason | Two things to keep in mind: - **Your refund policy only helps if the customer saw it.** In a dispute, Stripe's evidence fields include the refund policy and how it was disclosed to the customer before purchase ([dispute categories](https://docs.stripe.com/disputes/categories)). - **A refusal should be a reason, not silence.** If you decline, say why, refer to the terms, and offer what you can (cancelling future renewals, a credit). A clear "no" with a reason is better evidence than no answer. ## Step 3: issue the refund from the conversation If you bill with Stripe, Help Scout's [Stripe app](https://docs.helpscout.com/article/1731-connect-stripe-with-help-scout-to-view-details-in-the-sidebar) shows the customer's subscriptions and invoices in the sidebar and lets agents issue full or partial refunds without leaving the conversation. Per Help Scout: - It is installed under Settings > Apps > Stripe, and you choose which inboxes show it. - The person installing it needs admin-level permissions or above in Stripe. - **Every Help Scout user with access to those inboxes can issue refunds from the sidebar, regardless of their own Stripe permissions.** That last point matters. Only show the app in inboxes handled by people who are allowed to refund, or put refund requests in a dedicated inbox. If you bill elsewhere, agents refund in your billing system and confirm in the conversation. ## Step 4: confirm in writing Use [saved replies](https://docs.helpscout.com/article/18-create-saved-replies-for-fast-answers) so every refund gets a clear confirmation: > I've refunded [amount] to the card you paid with. Depending on your bank, it can take a few business days to appear. Your subscription is [cancelled / still active until (date)]. If anything still looks wrong on your statement, reply here and I'll sort it out. And for a refusal: > I've looked at your account. The charge on [date] is for [plan], which you've used since [date], so under our terms ([link]) it isn't refundable. I've cancelled future renewals so you won't be charged again. If I've missed something, reply here and I'll look again. Fill the brackets for each case. Never say a refund was issued before it actually was. ## Step 5: record the outcome Add a [custom field](https://docs.helpscout.com/article/593-custom-fields) (Plus and Pro plans) or tags for the outcome: `refund-full`, `refund-partial`, `refund-declined`. With the request tag from step 1, you can see: - how many refund requests you get, and from which reasons; - how long they take to answer; - which declined requests later turned into disputes. That last list is the one to study. If declined requests often become disputes you lose, your policy or the way it is explained needs work. ## Common mistakes - **Answering the refund request with a retention offer.** If the customer asked for their money back, a discount on next month does not answer the question. Answer it first; mention an alternative after, if at all. - **Partial refunds as a default compromise.** On Stripe, inquiries on partially refunded charges can still escalate. If you refund to avoid a dispute, consider whether a full refund is the safer choice. - **Refunding without cancelling.** If the customer wants out, a refund without a cancellation means another charge next month, and a dispute that time. - **Different answers from different agents.** A written policy and saved replies keep decisions consistent, which matters when a reviewer reads your reply next to your terms. - **Letting "I'll contact my bank" wait.** That message deserves the fastest answer in your queue. ## When a dispute comes anyway Some customers will dispute regardless. When that happens, the conversation you just had is your evidence: the dated request, your reply, the refund or the reasoned refusal. Our guide to [using Help Scout conversations as chargeback evidence](/blog/help-scout-chargeback-evidence/) explains how to extract and present it. Stripe's [early fraud warnings](/blog/stripe-early-fraud-warnings/) are a separate signal worth watching, since a proactive refund can sometimes prevent a fraud dispute. ## Doing this with NoChurn NoChurn's Help Scout connector is read-only: it reads conversations and does not issue refunds, tag or reply in Help Scout. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. If a dispute opens on Stripe or Braintree, NoChurn gathers the evidence (cancel flow answers, emails sent, usage, and the matched refund conversation quoted verbatim with dates), drafts a response with AI and submits it only after you review it. Refund decisions stay with you, in Stripe or your billing system. See [NoChurn + Help Scout](/integrations/help-scout/). --- # Help Scout satisfaction ratings as a churn signal Source: https://www.nochurn.sh/blog/help-scout-satisfaction-ratings/ Help Scout puts a small question under every reply: was this Great, Okay or Not Good? The answers add up to a Happiness Score that many teams watch closely. It is tempting to treat a falling score, or a customer's "Not Good", as a sign they are about to leave. Sometimes it is. Often it is not. This guide looks at Help Scout satisfaction ratings specifically as a churn signal: how they are collected, what the Happiness report really measures, where the useful information hides (the comments), and how to test whether ratings predict cancellations for your customers. Facts about Help Scout come from its documentation: [email satisfaction ratings](https://docs.helpscout.com/article/386-gather-feedback-with-satisfaction-ratings), [chat satisfaction ratings](https://docs.helpscout.com/article/1396-chat-satisfaction-ratings), the [Happiness report](https://docs.helpscout.com/article/383-reports-happiness), [workflow conditions and actions](https://docs.helpscout.com/article/502-workflow-condition-action), and the Inbox API's [ratings](https://developer.helpscout.com/mailbox-api/endpoints/ratings/get/) and [happiness reports](https://developer.helpscout.com/mailbox-api/endpoints/reports/happiness/reports-happiness-ratings/) endpoints (all accessed November 2026). ## How ratings are collected Per Help Scout's [email ratings guide](https://docs.helpscout.com/article/386-gather-feedback-with-satisfaction-ratings): - Ratings are turned on **per inbox** (Settings > Inboxes > your inbox > Satisfaction Ratings), and rating links are added to outgoing replies. - The customer picks **Great, Okay or Not Good**, lands on a page with an optional comment box, and the rating is saved when they press Send. - Customers have **10 days** from a reply to rate it or change their rating. Chat ratings from Beacon are collected separately and also feed the Happiness report ([chat ratings](https://docs.helpscout.com/article/1396-chat-satisfaction-ratings)). Three consequences for churn analysis: 1. **A rating is about one reply**, not about the product or the relationship. "Not Good" may mean "your answer didn't solve my problem", "I don't like your pricing", or "I wanted a refund and didn't get one". 2. **Only some customers rate.** Those who do are not a random sample. 3. **A rating can change** within 10 days, so a snapshot taken too early may differ from the final picture. ## What the Happiness report measures The [Happiness report](https://docs.helpscout.com/article/383-reports-happiness) shows how many ratings you received in the period and the share of Great, Okay and Not Good. The **Happiness Score** is the percentage of Great minus the percentage of Not Good. Ratings are indexed by the date of the reply, not the date the customer rated. Per-person ratings are in the Company report, under each user. On Standard plans, reports cover the last two years of data; Plus and Pro cover the lifetime of the account, according to the same page. The Happiness Score is a support quality metric. It tells you whether replies, in aggregate, are landing well. It is not designed to tell you which customers will cancel, and it moves with things that have nothing to do with churn: a new teammate, a seasonal spike, one bad release. ## Where the churn signal actually is The useful information is in three places, in this order. ### 1. The comment "Not Good" with no comment is a weak signal. "Not Good: third time I'm asking and still no fix, we're evaluating alternatives" is a strong one. Read every comment on a Not Good rating. Most weeks there are few enough to read them all. ### 2. The topic of the conversation A Not Good on a conversation tagged `billing` or `cancellation` means something different from one on a how-to question. Combine ratings with your tags: Not Good on a pricing conversation, or on a repeat bug report, is worth more attention than the score itself. ### 3. The pattern for one customer One bad rating is one bad reply. Two Not Good ratings from the same customer within a month, or a Not Good from someone who had always rated Great, is a change in the relationship. ## Acting on low ratings with workflows Help Scout suggests using workflows to follow up on ratings, for example flagging poor ratings that include a comment. Its [workflow conditions and actions](https://docs.helpscout.com/article/502-workflow-condition-action) page lists the available conditions and actions for building that. A practical setup: 1. An automatic workflow on conversations rated Not Good. 2. Actions: add a tag such as `rating-not-good`, assign to a team lead, and move the conversation back to active so it reappears in the queue. 3. A view of `rating-not-good` conversations from the last 14 days, reviewed every few days. The follow-up is a reply to what the customer said, from a person, without a discount attached. If the rating was about a cancellation that went badly, the follow-up is to fix it, not to win them back. ## Testing whether ratings predict churn for you Do not assume. Check it with your own data. ### Get the ratings out The Inbox API has a [Get Satisfaction Rating](https://developer.helpscout.com/mailbox-api/endpoints/ratings/get/) endpoint and reporting endpoints including [Happiness Ratings](https://developer.helpscout.com/mailbox-api/endpoints/reports/happiness/reports-happiness-ratings/), which encodes ratings as 1 (Great), 2 (Okay) and 3 (Not Good). Per Help Scout, the reporting endpoints are available on Plus and Pro plans. Collect, for each rating: customer email, conversation, rating, comment and date. ### Join with cancellations From your billing system, add whether and when each customer cancelled. For each customer, take their ratings in a quarter and compare: | Group in the quarter | Customers | Cancelled within 90 days | |---|---|---| | At least one Not Good with a comment | your count | your count | | At least one Not Good, no comment | | | | Only Great or Okay | | | | No ratings at all | | | Always include the "no ratings" row. It is usually the largest group, and leaving it out makes ratings look more predictive than they are. ### Read the result carefully - **Small numbers.** If the Not Good group has twelve customers, a difference of two cancellations is noise. Show counts next to every percentage. - **Correlation, not cause.** A bad rating and a cancellation may both come from the same broken feature. The rating is a flag to look closer, not an explanation. See [finding what predicts churn](/blog/predict-churn-with-customer-data/). - **Ratings on cancellation conversations.** Exclude them, or analyse them separately. A Great on a smooth cancellation is a good outcome, and a Not Good on a cancellation measures your process, not future churn. ## What to change if ratings do predict churn If customers with commented Not Good ratings cancel clearly more often: 1. Make the Not Good review a fixed weekly task with an owner. 2. Track the comments by theme (bug, price, missing feature, support speed) in a custom field or tags. 3. Send the top themes each month to whoever can fix them, with the customers' own words. 4. Re-run the comparison next quarter. If they do not, keep using ratings for what they are good at, coaching and support quality, and look for churn signals elsewhere: repeat contacts, billing conversations, failed payments, usage. ## Doing this with NoChurn NoChurn's Help Scout connector is read-only: it reads conversations and never changes ratings, tags or anything else in Help Scout. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. They feed a churn score from 0 to 100 and a churn drivers view that ranks attributes by correlation with churn, with sample sizes shown, and serve as dated, verbatim evidence for disputes on Stripe and Braintree. Rating collection, the Happiness report and follow-ups stay in Help Scout. See [NoChurn + Help Scout](/integrations/help-scout/). --- # How to handle cancellation requests in HubSpot Source: https://www.nochurn.sh/blog/hubspot-cancellation-workflow/ Cancellation requests reach HubSpot by every route: replies to invoices, the support email, live chat, a contact form, sometimes a message to the account manager. Each one ends up handled differently, and some sit in "Waiting on us" for days while the next renewal approaches. This guide sets up one consistent path for cancellation requests in HubSpot's help desk: a dedicated form, routing to the people who can act, pipeline automations that keep the request moving, and snippets for a clear confirmation. The process is built around one rule: cancelling should never be harder than signing up. HubSpot features are taken from its knowledge base: [form channels](https://knowledge.hubspot.com/help-desk/connect-a-form-channel-to-help-desk), [ticket routing](https://knowledge.hubspot.com/help-desk/route-tickets-in-help-desk), [ticket pipelines](https://knowledge.hubspot.com/tickets/customize-ticket-pipelines-and-statuses), [pipeline automations](https://knowledge.hubspot.com/object-settings/automate-ticket-pipelines), [snippets](https://knowledge.hubspot.com/conversations/use-snippets) and [workflow actions](https://knowledge.hubspot.com/workflows/choose-your-workflow-actions) (all accessed November 2026). HubSpot does not cancel the subscription in your billing system for you; that step happens wherever you bill. ## The principles first - **A clear request is executed.** "Please cancel my subscription" is enough. No call, no survey, no waiting for an answer to an offer. - **One optional question, at most.** You may ask why, but the cancellation does not depend on the answer. - **An alternative only when it fits.** Mention a pause or smaller plan only if the customer's reason suggests it would help, and in the same message that confirms the cancellation. - **A written confirmation** with the date the cancellation takes effect and what happens to access and data. Rules on cancellation differ by country; our guide on [click-to-cancel rules](/blog/click-to-cancel-rules/) summarises where they stand. This process is designed to sit comfortably within them, but it is not legal advice. ## Step 1: give cancellations their own pipeline HubSpot's default Support Pipeline has the statuses New, Waiting on contact, Waiting on us and Closed ([pipelines guide](https://knowledge.hubspot.com/tickets/customize-ticket-pipelines-and-statuses)). Create a separate "Account changes" pipeline with statuses that match the job: | Status | Meaning | |---|---| | Received | Request arrived, not yet handled | | Need account details | You genuinely cannot identify the account | | Cancelled | Done in the billing system, confirmation sent | | Closed | Nothing left to do | Keep "Need account details" for real ambiguity (several accounts on one email, a different email from the one on file). It is not a place to park requests while you try to change the customer's mind. ## Step 2: add a cancellation form A simple form makes the request easy to send and easy to track. HubSpot can turn form submissions into tickets: connect the form under Settings > Inbox & Help Desk > Channels > Form, and choose the pipeline, status and priority that new tickets get ([form channel guide](https://knowledge.hubspot.com/help-desk/connect-a-form-channel-to-help-desk)). HubSpot lists Service Hub Professional or Enterprise as a requirement for connecting a form to help desk. Keep the form short: 1. Email address (prefilled where possible). 2. "What would you like to do?" Cancel at the end of the period / Cancel now. 3. "Anything you want to tell us?" Optional free text. Link to it from your account settings page and from your renewal reminders. Do not hide it behind a help center search. Cancellation emails and chats that arrive through other channels still need handling. Move them into the same pipeline so they follow the same steps. ## Step 3: route to someone who can act HubSpot's [routing guide](https://knowledge.hubspot.com/help-desk/route-tickets-in-help-desk) explains that incoming tickets are unassigned by default, and that routing rules (which need a Service Hub seat) can assign tickets from a channel to specific users or teams, to the contact owner, or through a workflow, with load balanced, round robin or random distribution. Route cancellation tickets to a small team with access to the billing system. If a request lands with someone who cannot cancel, it waits; that is the most common way a simple cancellation turns into an angry second email or a chargeback. ## Step 4: keep requests moving with automations HubSpot's [pipeline automations](https://knowledge.hubspot.com/object-settings/automate-ticket-pipelines) can create a task or send an internal notification when a ticket enters a status. HubSpot lists Service Hub Starter, Professional or Enterprise for some of these automations. Two are worth setting: 1. **On Received**: create a task for the assigned owner, due the same working day. 2. **On Need account details**: create a follow-up task due in two working days, so the ticket does not sit forever waiting on the customer. For anything more complex, such as notifying a manager when a cancellation ticket has been open too long, the [workflow tool](https://knowledge.hubspot.com/workflows/choose-your-workflow-actions) offers actions to create tasks and send internal emails. ## Step 5: confirm with snippets HubSpot [snippets](https://knowledge.hubspot.com/conversations/use-snippets) are short reusable blocks of text: create them under CRM > Snippets with a shortcut, then type # followed by the shortcut in the editor to insert one. Three snippets cover most cases. **#cancel-confirm** > Your subscription is cancelled. You will not be charged again. You keep access until [date], the end of the period you already paid for. Your data stays available to export until [date]. If you'd like to tell us why you cancelled, just reply; it is completely optional. **#cancel-confirm-pause**, for customers who mentioned a temporary reason: > Your subscription is cancelled and you will not be charged again. Since you mentioned [reason]: if it's useful, we can pause your account instead for up to [N] months, keeping everything as it is. Reply "pause" and we'll switch it. Otherwise there's nothing else to do. **#cancel-need-details** > We want to cancel the right account. We see more than one account linked to this email: [list]. Which one should we cancel? Reply with the name and we'll do it straight away. Fill the brackets by hand; do not promise anything your billing system cannot do. For when a pause, discount or smaller plan makes sense, see [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). ## Step 6: record the reason without pressure Add a ticket property "Cancellation reason" (dropdown) and fill it from what the customer wrote, if they wrote anything. Do not chase them for it. Over a few months, this gives you a real reasons list to compare with your [cancellation survey](/blog/cancellation-reasons-survey/) and product feedback. A simple report on the Account changes pipeline (tickets by status, by reason, and time from Received to Cancelled) tells you whether the process works. The number to watch is tickets still in Received after one working day; it should be zero. ## A checklist - [ ] "Account changes" pipeline with four statuses. - [ ] Cancellation form connected to help desk, linked from account settings. - [ ] Routing to a team with billing access. - [ ] Same-day task automation on Received. - [ ] Three snippets, reviewed by whoever owns billing. - [ ] "Cancellation reason" property and a monthly report. ## Doing this with NoChurn NoChurn's HubSpot connector is read-only: it reads tickets and conversations and never writes to HubSpot, so the pipeline, routing and snippets above stay in HubSpot. Conversations are matched to your customers by email; doubtful matches are suggested and never merged automatically, and they feed the churn score and churn drivers. If you would rather customers cancel without writing in, NoChurn's cancel flow asks for a reason, can show an offer (discount, pause or plan change), and keeps a one-click cancel button visible at every step, hosted or through the API. See [NoChurn + HubSpot](/integrations/hubspot/). --- # How to use HubSpot tickets as chargeback evidence Source: https://www.nochurn.sh/blog/hubspot-chargeback-evidence/ When a subscriber files a chargeback, the issuer asks a simple question: did this customer know about the charge, and did they get what they paid for? If your support runs on HubSpot, the answer is often spread across several places: a help desk ticket, one-to-one emails on the contact record, a chat thread, and the company record they belong to. HubSpot's strength is that all of these live in one CRM. Its weakness, for disputes, is that no single button gives you the whole story. This guide shows how to collect a clean, dated timeline from HubSpot for a dispute response. It sticks to HubSpot's own knowledge base and developer docs: [managing tickets in help desk](https://knowledge.hubspot.com/help-desk/manage-tickets-in-help-desk), [creating and responding to tickets](https://knowledge.hubspot.com/help-desk/create-respond-to-tickets-in-help-desk), [record timelines](https://knowledge.hubspot.com/crm-setup/customize-activities-on-a-contact-company-deal-ticket-record-timeline), [exporting records](https://knowledge.hubspot.com/import-and-export/export-records), [exporting contact data](https://knowledge.hubspot.com/import-and-export/export-contact-data) and the [Conversations API](https://developers.hubspot.com/docs/api-reference/legacy/conversations/guide). Dispute fields come from Stripe's [dispute categories](https://docs.stripe.com/disputes/categories) and [best practices](https://docs.stripe.com/disputes/best-practices), and Braintree's [evidence requirements](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/php) (all accessed November 2026). ## Where the evidence lives in HubSpot Before you collect anything, know where each piece sits: | Evidence | Where it lives | Notes from HubSpot's docs | |---|---|---| | The support conversation | The ticket in help desk | Printable with the "Print conversation" action | | What happened to the ticket | The ticket's History tab | Creation, status changes, workflow enrollments, merges | | Emails outside the ticket | The contact's activity timeline | Emails sent from a ticket are also associated with the contacts emailed | | Which records were linked, and when | "View association history" on the record | Pick an object or activity type to see what was associated and when | | Survey answers | Feedback submissions on the contact and ticket | Useful context, rarely evidence on their own | HubSpot's [help desk documentation](https://knowledge.hubspot.com/help-desk/create-respond-to-tickets-in-help-desk) notes that one-to-one emails sent and calls made from a ticket are associated with the contacts emailed or called, so they also appear on the contact's timeline. Emails sent another way may only be associated with the contacts emailed, not with the ticket. That is why you should always check the contact record, not only the ticket. ## What reviewers want to see Reviewers at the card issuer read quickly. For subscription disputes, the useful material is usually: - **Proof the customer knew about the renewal**: a renewal reminder, or the customer mentioning their plan or next invoice. - **Proof of use after the charge**: a question about a feature, a bug report, a request for help, dated after the disputed payment. - **The cancellation story**: if the customer asked to cancel, when, and what you did. If they never asked, the absence of a request in a complete history is itself relevant. For the "subscription canceled" category, Stripe's [dispute categories](https://docs.stripe.com/disputes/categories) point to the `cancellation_rebuttal` and `customer_communication` fields; Stripe's [best practices](https://docs.stripe.com/disputes/best-practices) recommend combining several communications into one file. On Braintree, the [evidence requirements guide](https://developer.paypal.com/braintree/docs/guides/disputes/evidence-requirements/php) lists emails or other correspondence with the customer among helpful evidence, submitted as text or as a file depending on the reason code. ## Step by step: building the timeline ### 1. Find every record for the customer Search for the disputing customer's email in contacts. Check for duplicates (old addresses, a work and a personal address) and for the company record. If the customer has several contacts, collect them all; a reviewer will not see your CRM, only what you send. ### 2. Print the relevant tickets HubSpot's [ticket management guide](https://knowledge.hubspot.com/help-desk/manage-tickets-in-help-desk) describes a **Print conversation** action: in table or split layout, use the Actions menu on the ticket; in board layout, the three-dot menu. You can add ticket properties to the printout from the "Ticket properties to print" dropdown, or clear them to print only the conversation, then preview and print to PDF. What to include: - The ticket's create date and status, so the reviewer sees when it started and how it ended. - Not internal properties such as priority or owner. They mean nothing to a reviewer and can confuse the story. ### 3. Add emails from the contact timeline Open the contact record and filter the timeline to emails (HubSpot's [timeline filters](https://knowledge.hubspot.com/crm-setup/customize-activities-on-a-contact-company-deal-ticket-record-timeline) work by activity type, date range and owner). Look for renewal notices, receipts you sent from HubSpot, and any one-to-one email thread not linked to a ticket. ### 4. Check the ticket History tab The History tab shows when the ticket was created and when its status changed. If the customer says "I asked to cancel and nobody answered", the history shows when you replied and when the ticket closed. Use it to check your own timeline, and quote it only if it settles a disputed point. ### 5. Pull data in bulk if you need it For one dispute, printing is enough. If you handle disputes regularly, set up an export path: | Method | What you get | Limits | |---|---|---| | [Export records](https://knowledge.hubspot.com/import-and-export/export-records) (tickets) | Property values and associations | No message content; download link by email, valid 30 days | | [Export contact data](https://knowledge.hubspot.com/import-and-export/export-contact-data) | Contact properties, with an option to include associated activities | Per contact or list | | [Conversations API](https://developers.hubspot.com/docs/api-reference/legacy/conversations/guide) | Threads and full message history, each message with `createdAt` | Needs the `conversations.read` scope | The API route is the one that scales: list the threads for a contact, fetch each thread's messages, and sort by `createdAt`. ### 6. Write the cover note Two or three sentences in plain language, then the evidence in date order. For example: "The customer was charged on [date] for the annual renewal. On [date], after the charge, they contacted support about [feature] (message 1). They did not request cancellation at any point before the dispute (complete ticket history attached)." Quote messages in full, with date, time zone and sender. Do not paraphrase; a reviewer trusts the customer's words more than your summary of them. ## Keep it honest and clean - **Include unfavourable messages if they are relevant.** If the customer asked to cancel and the request was missed, the right answer may be to accept the dispute and fix the process, not to argue. - **Remove what is not needed.** Internal notes, other customers' names in a forwarded thread, unrelated personal data. - **Never include card numbers** or full payment details. You do not need them, and they should not be in your CRM in the first place. - **Watch the deadline.** Braintree states it will not forward a response to the bank unless it is finalized before the reply-by date ([managing disputes](https://developer.paypal.com/braintree/docs/guides/disputes/managing)). Stripe shows the due date on each dispute. ## Prepare before the next dispute A few settings make the next file faster to build: 1. **A property for billing requests** on tickets (cancel request, refund request, charge question), so you can filter quickly. 2. **A template for cancellation confirmations** that states the cancellation date, so the confirmation is a dated email on the contact timeline. 3. **Renewal reminders sent through HubSpot** or logged on the contact, if you send them elsewhere, so they appear on the same timeline. 4. **One contact per customer.** Merge duplicates when you find them; split evidence across three contacts is easy to miss. For the Stripe side of the process, see our guide to [winning chargebacks on Stripe](/blog/win-chargebacks-stripe/). ## Doing this with NoChurn NoChurn's HubSpot connector is read-only: it reads tickets and conversations and never writes to HubSpot. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. When a dispute opens on Stripe or Braintree, NoChurn gathers evidence automatically (cancel flow answers, emails sent, usage, and the matched HubSpot messages quoted verbatim with their dates), drafts a reply with AI, and sends it only after you review it. Ticket handling and printing stay in HubSpot, and the outcome is decided by the card issuer. See [NoChurn + HubSpot](/integrations/hubspot/). --- # How to predict churn from HubSpot tickets Source: https://www.nochurn.sh/blog/hubspot-churn-signals/ If your support runs on HubSpot, your tickets already sit in the same CRM as your contacts and companies. That is an advantage most help desks do not have: you can put a ticket, a survey answer and the account it belongs to in one report, without exporting anything. This guide shows how to turn that into an early warning for churn: which ticket properties and survey answers to watch, how to set them up in Service Hub, and how to build reports and workflows that flag at-risk accounts before renewal. It relies on HubSpot's own knowledge base: [ticket pipelines](https://knowledge.hubspot.com/tickets/customize-ticket-pipelines-and-statuses), [default ticket properties](https://knowledge.hubspot.com/properties/hubspots-default-ticket-properties), [customer support surveys](https://knowledge.hubspot.com/customer-feedback/how-do-i-send-a-customer-support-survey), [customer satisfaction surveys](https://knowledge.hubspot.com/customer-feedback/create-and-send-customer-satisfaction-surveys), [loyalty (NPS) surveys](https://knowledge.hubspot.com/customer-feedback/how-do-i-send-a-customer-loyalty-survey), [analyzing survey responses](https://knowledge.hubspot.com/customer-feedback/analyze-survey-responses), [help desk reports](https://knowledge.hubspot.com/reports/create-help-desk-reports-with-the-custom-report-builder) and [workflow enrollment triggers](https://knowledge.hubspot.com/workflows/set-filter-enrollment-triggers) (all accessed November 2026). ## Leading vs lagging signals A cancellation is a lagging signal: by the time you see it, the decision is made. What you want from support data are leading signals, things that tend to happen weeks before. In HubSpot terms, these fall into three groups: 1. **What customers contact you about** (ticket category, pipeline, your own properties). 2. **How the contact went** (reopened tickets, time waiting on your team, effort). 3. **What customers tell you when asked** (CSAT, CES and NPS survey answers). None of these predicts churn on its own. The point is to collect them consistently so you can check, against your own cancellations, which ones actually came first. ## Set up the ticket side ### Pipelines and statuses HubSpot's [pipeline guide](https://knowledge.hubspot.com/tickets/customize-ticket-pipelines-and-statuses) describes the default Support Pipeline with four statuses: New, Waiting on contact, Waiting on us and Closed. For churn work, two things help: - **A separate pipeline for billing and account requests** (cancellation, downgrade, refund, invoice questions). It keeps those tickets out of general support reports and lets you attach a specific survey to them, since each ticket pipeline can be linked to one support survey. - **Watching reopened tickets.** HubSpot's help desk docs say a reply to a closed ticket reopens it and moves it to the first open status in the pipeline. A ticket that keeps coming back is a customer whose problem was not solved. ### Properties HubSpot's [default ticket properties](https://knowledge.hubspot.com/properties/hubspots-default-ticket-properties) include **Category**, described as the main reason the customer reached out. On Service Hub Enterprise it can be set by AI from the first message, using default and custom options; this setting is off by default. On other plans, or in addition, create your own ticket properties. A practical minimum: | Property | Type | Why | |---|---|---| | Churn risk reason | Dropdown | Cancellation request, Price, Missing feature, Bug, Competitor, Onboarding, None | | Mentions leaving | Checkbox | Agent ticks it when the customer mentions cancelling or switching | | Affected feature | Dropdown | Lets you see which product areas generate risk | Keep the dropdown short. If agents have to think about which value to pick, they will pick "Other". ## Set up the survey side HubSpot's feedback surveys support three standard measures. Ticket and feedback submission properties need Service Hub Professional or Enterprise. | Survey | What it measures | Scale per HubSpot's docs | Best for | |---|---|---|---| | Customer support survey (CES) | Effort to get an issue resolved | 1–7: 1–3 Difficult, 4–5 Neutral, 6–7 Easy | Effort after a ticket | | Customer satisfaction (CSAT) | Satisfaction with an interaction | Stored as 0–2: Unhappy, Neutral, Happy | A specific interaction | | Customer loyalty (NPS) | Likelihood to recommend | 0–10: Detractor 0–6, Passive 7–8, Promoter 9–10 | The overall relationship | Details from HubSpot's [customer support survey guide](https://knowledge.hubspot.com/customer-feedback/how-do-i-send-a-customer-support-survey) that shape how you use them: - A ticket-based survey is sent when a ticket in the selected pipeline is closed, immediately or after a delay you choose. - It is sent **once per ticket**. If the ticket reopens and closes again, no second survey goes out. - Responses are associated with the contact, the company and the ticket. HubSpot calculates NPS as the percentage of promoters minus the percentage of detractors ([analyzing survey responses](https://knowledge.hubspot.com/customer-feedback/analyze-survey-responses)). For churn, the comment field matters more than the score. "Third time I have reported this" next to a Difficult rating is the kind of line you want someone to read the same day. ## Reports that surface risk HubSpot's [help desk report builder](https://knowledge.hubspot.com/reports/create-help-desk-reports-with-the-custom-report-builder) lets you choose tickets, conversations, contacts, companies or feedback submissions as the primary data source, then add secondary sources. Reports worth building: 1. **Companies with tickets marked "Mentions leaving" in the last 90 days**, with their renewal date or plan from your CRM properties. 2. **Feedback submissions with Difficult effort or Unhappy satisfaction**, grouped by company, so one bad week for one account stands out. 3. **Ticket count per company per month in the billing pipeline**, to spot accounts whose billing questions are rising. 4. **Churn risk reason over time**, to see whether "Price" or "Missing feature" is growing. Then check them against reality. Once a month, take the companies that cancelled and look at what their tickets and surveys showed in the 60 to 90 days before. If a signal rarely appears before cancellations, drop it. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) explains how to do this without confusing correlation and cause. HubSpot also offers a customer success workspace with a configurable [health score](https://knowledge.hubspot.com/help-desk/customize-a-health-score-in-the-customer-success-workspace). If you use it, the properties above are candidates for it, once you have checked they actually come before churn. ## Workflows that act on signals HubSpot's [enrollment triggers guide](https://knowledge.hubspot.com/workflows/set-filter-enrollment-triggers) says feedback submissions can be enrolled based on their properties, such as sentiment or survey name, and on associated contact and ticket information. The [workflow actions](https://knowledge.hubspot.com/workflows/choose-your-workflow-actions) include creating tasks. Two workflows and one routine cover most of the value: 1. **Negative feedback follow-up.** Enroll feedback submissions with negative sentiment; create a task for the account owner to read the comment and reply within a working day. 2. **Leaving mentioned.** Enroll tickets where "Mentions leaving" is checked; notify the account owner and set a follow-up task. The follow-up is a conversation, not a sales pitch. 3. **Repeat contact.** Review report 3 weekly and create a task for any company above the threshold you chose. Automate it later, once you know the threshold is meaningful. One line not to cross: when a ticket is a cancellation request, the workflow should never delay the cancellation. Cancel when asked, confirm in writing, and if you want to understand why, ask one optional question. See our notes on [click-to-cancel rules](/blog/click-to-cancel-rules/). ## A checklist to start this week - [ ] Create a billing and account pipeline, or a property that separates those tickets. - [ ] Add "Churn risk reason" and "Mentions leaving" ticket properties. - [ ] Turn on a customer support survey for the main pipeline. - [ ] Build the four reports above. - [ ] Add the negative feedback workflow. - [ ] Book a monthly review comparing signals with actual cancellations. ## Doing this with NoChurn NoChurn's HubSpot connector is read-only: it reads tickets and conversations and never writes to HubSpot. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. NoChurn combines them with your billing data in a churn score from 0 to 100 and a churn drivers view that ranks which attributes are most correlated with churn (correlation, not causation), and keeps the messages as dated, verbatim evidence for disputes on Stripe and Braintree. Pipelines, surveys, reports and workflows stay in HubSpot. See [NoChurn + HubSpot](/integrations/hubspot/). --- # Using HubSpot NPS and CSAT surveys to predict churn Source: https://www.nochurn.sh/blog/hubspot-nps-churn/ Most teams that run NPS in HubSpot look at one number: the score, going up or down. That number says something about the customer base as a whole. It says very little about which customers are about to cancel. To use surveys to predict churn, you have to work at the level of the customer and compare their answers with what they did next. This guide covers that analysis: which HubSpot properties hold the answers, how to filter and export responses, how to join them with cancellations, and how to read the result without fooling yourself. It assumes surveys are already running; for setup, see our guide on [predicting churn from HubSpot tickets](/blog/hubspot-churn-signals/). HubSpot details come from its knowledge base: [loyalty (NPS) surveys](https://knowledge.hubspot.com/customer-feedback/how-do-i-send-a-customer-loyalty-survey), [survey response properties](https://knowledge.hubspot.com/customer-feedback/survey-response-properties), [analyzing survey responses](https://knowledge.hubspot.com/customer-feedback/analyze-survey-responses), [tagging survey responses](https://knowledge.hubspot.com/customer-feedback/tag-survey-responses), the [customer feedback FAQ](https://knowledge.hubspot.com/customer-feedback/customer-feedback-faqs) and [segments](https://knowledge.hubspot.com/segments/create-active-or-static-lists) (all accessed November 2026). ## What HubSpot stores, and where The analysis depends on knowing which fields you can use. **On each response (feedback submission).** HubSpot's [survey response properties](https://knowledge.hubspot.com/customer-feedback/survey-response-properties) include the rating and the comment. For NPS the rating runs from 0 to 10; for CSAT from 0 to 2 (Unhappy, Neutral, Happy). Responses are associated with the contact and, for ticket-based surveys, with the ticket. **On the contact.** HubSpot automatically sets **Last NPS survey rating**, **Last NPS survey date** and **Last NPS survey comment** (Service Hub Professional and Enterprise). These are convenient for segments, but they only hold the latest answer. A customer who went from 9 to 3 to 8 shows as 8. **Sentiment.** HubSpot labels responses by rating. Per the [analysis guide](https://knowledge.hubspot.com/customer-feedback/analyze-survey-responses), a response counts as a detractor for NPS at 0–6, for CSAT at 0, and for CES at 1–3. NPS promoters are 9–10 and passives 7–8. For prediction, you want the history of responses, not only the last one. That means working with feedback submissions, not just the contact properties. ## Step 1: export the responses On a survey's Responses tab, HubSpot lets you set a date range, filter by company, show only responses with comments, filter by contact properties, and view detractors, passives or promoters. Exports are CSV, and if you filter before exporting, the file contains only matching responses. You can choose to export the current view's columns or all available survey response data ([analysis guide](https://knowledge.hubspot.com/customer-feedback/analyze-survey-responses)). Export all responses for at least the last 12 months, with: contact email, company, survey name, rating, comment and submission date. ## Step 2: add what happened next From your billing system, export for the same customers: subscription start, cancellation date (if any), cancellation reason (if captured), plan and MRR. Join on email, or better, on a customer ID you also store in HubSpot. Then, for each response, compute one outcome: **did this customer cancel within N days of answering?** Pick N to match your billing cycle: 90 days is a reasonable start for monthly plans; for annual plans, look at the next renewal instead. ## Step 3: compare groups Build a small table like this from your own data: | Group at time of answer | Responses | Cancelled within 90 days | Share | |---|---|---|---| | Detractors (0–6) | your count | your count | your % | | Passives (7–8) | | | | | Promoters (9–10) | | | | | Did not answer | | | | The last row matters. Customers who never answer surveys are often a large group, and their churn can be higher or lower than any of the others. If you leave them out, you will overestimate how much the survey tells you about your whole base. Then do the same for CSAT on tickets: customers with at least one Unhappy rating in a quarter versus those with none. ## Step 4: read the comments of detractors who left Numbers tell you whether a signal exists. Comments tell you what it is. Read every comment from detractors who went on to cancel, and every comment from detractors who stayed. HubSpot lets you [tag survey responses](https://knowledge.hubspot.com/customer-feedback/tag-survey-responses) and use tags in filters, views, segments and reports, so tag themes as you read: price, missing feature, reliability, support, onboarding. Often the pattern is not "detractors churn" but "detractors who mention price churn, detractors who mention a bug stay if it gets fixed". That is far more useful. ## The traps **Small samples.** HubSpot's [feedback FAQ](https://knowledge.hubspot.com/customer-feedback/customer-feedback-faqs) says you could see anywhere from a 5 to 15% response rate, depending on your industry and how often you contact customers. On a base of a few hundred customers, that is a handful of detractors per quarter. Report counts next to every percentage, and do not draw conclusions from a dozen responses. **Response bias.** People who answer surveys are not a random sample. The most engaged and the most annoyed are over-represented. **Timing.** HubSpot calculates the main NPS score based on the final date of the selected timeframe, and its trend view as a running total ([analysis guide](https://knowledge.hubspot.com/customer-feedback/analyze-survey-responses)). Neither is a per-customer measure. For prediction, always use the individual response with its date. **Correlation is not cause.** A low score before cancellation does not mean the score caused it. Both may come from the same problem, such as a failed onboarding. Use the signal to decide who to talk to, not to explain churn. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) goes into this. **Survey fatigue.** Asking too often lowers response rates and annoys customers. HubSpot supports a reminder email a set number of days after the original ([loyalty surveys](https://knowledge.hubspot.com/customer-feedback/how-do-i-send-a-customer-loyalty-survey)); one reminder is plenty. ## Step 5: act on what you found If detractors churn noticeably more in your data, turn that into a routine: 1. Create a [segment](https://knowledge.hubspot.com/segments/create-active-or-static-lists) of contacts with Last NPS survey rating of 6 or less and Last NPS survey date in the last 30 days. 2. Each week, someone reads the comments and replies personally to every detractor who left one. Not a template, not a discount: a reply to what they said. 3. For customers whose comment points to a fixable problem, open a ticket and track it to resolution. 4. Re-run the analysis every quarter. If the gap between groups disappears, either your follow-up works or the signal was noise; the counts will tell you which. If the gap is small or absent, that is a result too. Do not keep a weekly ritual around a number that does not predict anything for your customers. ## What surveys cannot tell you Many customers who cancel never answer a survey and never open a ticket. Their signals are elsewhere: falling usage, a failed payment, a removed card, a downgrade. Surveys are one input among several, and usually not the strongest. ## Doing this with NoChurn NoChurn's HubSpot connector is read-only: it reads tickets and conversations and never writes to HubSpot. Conversations are matched to your customers by email (doubtful matches suggested, never merged automatically), and you can also send survey results and other attributes to NoChurn as custom data through the API. NoChurn combines them with billing data in a churn score from 0 to 100 and a churn drivers view that ranks attributes by their correlation with churn, shown as correlation, not causation. Surveys, segments and follow-ups stay in HubSpot. See [NoChurn + HubSpot](/integrations/hubspot/). --- # Win-back emails for churned customers in HubSpot Source: https://www.nochurn.sh/blog/hubspot-win-back-sequences/ A customer who cancelled knows your product, has already paid you, and may come back if the reason they left goes away. HubSpot has every tool you need to reach them at the right time: segments, workflows with delays, marketing emails and, for personal outreach, sequences. What it does not have by default is the one fact everything depends on: that the customer cancelled, when, and why. This guide shows how to get that data into HubSpot and build a win-back program on top of it, timed by cancellation date and adapted to the reason. It relies on HubSpot's knowledge base: [segments](https://knowledge.hubspot.com/segments/create-active-or-static-lists) and [filter criteria](https://knowledge.hubspot.com/lists/determine-your-list-criteria), [delays](https://knowledge.hubspot.com/workflows/use-delays), [re-enrollment](https://knowledge.hubspot.com/workflows/add-re-enrollment-triggers-to-a-workflow), [marketing emails in automation](https://knowledge.hubspot.com/marketing-email/use-automation-with-marketing-emails), [sequences](https://knowledge.hubspot.com/sequences/create-and-edit-sequences) and [subscription types](https://knowledge.hubspot.com/marketing-email/set-up-email-subscription-types) (all accessed November 2026). For what to write in each email, see our [win-back email examples](/blog/win-back-email-examples/). ## Step 1: put churn data on the contact Create three contact properties (or company properties, for B2B accounts with several users): | Property | Type | Example values | |---|---|---| | Subscription status | Dropdown | Active, Cancelled, Paused | | Cancellation date | Date picker | The date access ended | | Cancellation reason | Dropdown | Too expensive, Missing feature, Not using it, Switched tool, Temporary, Other | These have to be filled by something: an integration with your billing system, your own app through HubSpot's API, or a regular import. Whatever the source, the cancellation reason should come from what the customer said (a cancel flow answer, a ticket), not from a guess. Time everything from "Cancellation date", not from the day HubSpot saw the status change. Imports and syncs can run late, and your timing should follow what the customer experienced. ## Step 2: build segments by reason HubSpot [segments](https://knowledge.hubspot.com/segments/create-active-or-static-lists) filter on properties, and date properties support relative operators such as "is more than … days ago" ([filter criteria](https://knowledge.hubspot.com/lists/determine-your-list-criteria)). Create one active segment per reason group: - **Price**: Subscription status is Cancelled, reason is Too expensive. - **Product**: reason is Missing feature or Switched tool. - **Timing**: reason is Not using it or Temporary. - **Unknown**: reason is Other or unknown. Exclude from all of them: contacts who have reactivated, contacts whose cancellation came with a complaint still open, and contacts who disputed a charge. Writing "come back!" to someone in the middle of a chargeback is a bad idea. ## Step 3: one workflow per reason, with delays Add one more filter to each segment: Cancellation date is more than 30 days ago. Then build a contact-based workflow per segment, enrolled on segment membership, with this shape: 1. Send email 1 (the contact enters the segment around day 30). 2. Delay 30 days. 3. If still cancelled, send email 2. 4. Delay 30 days. 5. If still cancelled, send email 3. HubSpot's [delay guide](https://knowledge.hubspot.com/workflows/use-delays) covers fixed delays, delays that skip weekends and time-of-day delays. Timing from the segment filter keeps the schedule tied to the real cancellation date, even if the data arrived late. Check each branch for "still cancelled" before sending, so a customer who came back on day 40 does not get a "we miss you" on day 60. What each email says depends on the reason: | Reason group | Email 1 (around day 30) | Email 2 (around day 60) | Email 3 (around day 90) | |---|---|---|---| | Price | What changed in plans or pricing, if anything did | A time-limited offer, if you make one | Last note, how to come back | | Product | The specific feature they asked for, only if it shipped | Other relevant improvements | Last note | | Timing | Short check-in, no offer | What's new since they left | Last note | | Unknown | Short check-in, ask what would bring them back | What's new | Last note | Be honest. If the feature they wanted has not shipped, do not hint that it has. If nothing changed on price, do not pretend. ### Re-enrollment HubSpot workflows enroll a record only the first time it meets the triggers, unless you turn on re-enrollment ([re-enrollment guide](https://knowledge.hubspot.com/workflows/add-re-enrollment-triggers-to-a-workflow)). Re-enrolled records start again from the beginning and receive every email again. For win-back, turn re-enrollment on only if a customer can cancel, return, and cancel again, and make sure the second run is appropriate. HubSpot also notes that a record still active in a workflow cannot be enrolled again until it completes it. ## Step 4: personal outreach with sequences For high-value accounts, a personal email from the person who knew them works better than a marketing email. HubSpot [sequences](https://knowledge.hubspot.com/sequences/create-and-edit-sequences) send one-to-one emails on a schedule and, by default, unenroll a contact who replies or books a meeting through a sequence link. HubSpot documents this for Sales Hub and Service Hub Professional and Enterprise. A reasonable split: marketing workflows for most churned customers, a short sequence (two emails, a few weeks apart) for the accounts you would call by name. Do not run both on the same person at the same time. ## Step 5: respect consent Win-back emails are marketing, not service messages. HubSpot's [subscription types](https://knowledge.hubspot.com/marketing-email/set-up-email-subscription-types) let contacts opt in or out of categories of marketing email; emails are not delivered to contacts who opted out of that type. Create a dedicated subscription type for win-back or product updates, so a customer who wants receipts but not marketing can say so. Check the consent rules where your customers are. A paying relationship that has ended does not automatically mean you can keep sending marketing email. ## Step 6: measure what came back For each workflow, track: - **Reactivations**: contacts whose Subscription status went from Cancelled back to Active within 30 days of an email. - **Unsubscribes** from the win-back subscription type. - **Replies**, especially to the "what would bring you back?" email. These are often the most useful output of the whole program. Compare reactivations with a small holdout group that receives nothing, if your volume allows it. Some customers return on their own, and without a holdout you will credit the emails for all of them. ## Common mistakes - **Starting too early.** An email the day after cancelling feels like the cancellation was not accepted. - **The same discount for everyone.** It trains customers to cancel for a discount and does nothing for those who left for a missing feature. - **No exit.** Three emails, then stop. Silence after the third is respectful and keeps your sender reputation intact. - **Ignoring the dispute list.** Exclude anyone with an open dispute or an unresolved complaint. ## Doing this with NoChurn NoChurn sends its own win-back emails at day 30, 60 and 90 after cancellation, chosen by the reason the customer gave in the cancel flow. Its HubSpot connector is read-only, so NoChurn does not send through HubSpot or change your workflows; if you prefer to keep win-back in HubSpot, use one or the other for the same customers, not both. Support conversations from HubSpot are matched to customers by email (doubtful matches suggested, never merged automatically) and feed the churn score and churn drivers. See [NoChurn + HubSpot](/integrations/hubspot/). --- # How to handle cancellation requests in Intercom Source: https://www.nochurn.sh/blog/intercom-cancellation-requests/ Many subscription businesses have a cancel button in the app, and still get a steady stream of "please cancel my account" messages in Intercom. Those messages are a cancel flow too, just an unstructured one. Handled well, they keep a few customers who only needed a pause or a cheaper plan, and they end cleanly for everyone else. Handled badly, they become refund requests, angry reviews or chargebacks. This guide shows how to spot cancellation requests in Intercom, answer them consistently, and record what happened. It sticks to Intercom's own help center: [creating and managing macros](https://www.intercom.com/help/en/articles/6433193-creating-and-managing-macros), [how to trigger a Workflow](https://www.intercom.com/help/en/articles/7434613-how-to-trigger-a-workflow), the [Topics Explorer](https://www.intercom.com/help/en/articles/11390087-use-the-topics-explorer-to-see-what-s-driving-volume), the [Stripe app](https://www.intercom.com/help/en/articles/1829591-stripe-app) and [Data connector templates](https://www.intercom.com/help/en/articles/9909996-use-data-connector-templates) (all accessed November 2026). ## The rule that comes first A customer who asks to cancel in a support conversation has asked to cancel. You can offer an alternative once, but the request must be carried out if they confirm, and it must not be slower or harder than signing up was. Several jurisdictions now have explicit rules on this; we summarize them in [click-to-cancel rules for SaaS](/blog/click-to-cancel-rules/). Everything below assumes that rule: the goal is a clear, fast answer, not a maze. ## What Intercom gives you natively ### Workflows can catch the conversation early Intercom Workflows start from predefined triggers. The one most teams use for inbound requests is "Customer sends their first message", which runs once per new conversation. Intercom's [trigger documentation](https://www.intercom.com/help/en/articles/7434613-how-to-trigger-a-workflow) also lists "Customer sends any message", which fires on every customer message, including replies in an open conversation. Intercom recommends the first-message trigger when you only want to act at the start of a conversation. Workflows can branch on conditions such as message content, attributes or customer type. There is no built-in "cancellation intent" trigger in the trigger list, so in practice you route on keywords ("cancel", "unsubscribe", "close my account", "stop billing") or on an attribute you set yourself. Expect false positives ("how do I cancel an invite?") and keep a human in the loop. ### Topics Explorer shows how big the problem is The [Topics Explorer](https://www.intercom.com/help/en/articles/11390087-use-the-topics-explorer-to-see-what-s-driving-volume) groups conversations into topics and subtopics with AI, without manual tagging. When it is first enabled, it builds its model from the past 90 days of conversations, and it needs at least 15 similar conversations to form a subtopic. Intercom is explicit about its limits: topics do not analyze sentiment. Use it to see whether cancellation and billing conversations are growing, not to make decisions on individual customers. ### Macros keep the answer consistent A [macro](https://www.intercom.com/help/en/articles/6433193-creating-and-managing-macros) is a saved reply with optional actions. Actions include assigning to a team or teammate, adding tags, snoozing, closing, changing priority, setting a ticket state and running a data connector. One limit matters here: a single macro cannot both reply to the customer and add an internal note, so you need two macros if you want both. Macro search matches titles only, so name them clearly (for example "Cancel – confirm", "Cancel – pause offer"). ### The Stripe app shows the subscription beside the conversation If you bill with Stripe, Intercom's [Stripe app](https://www.intercom.com/help/en/articles/1829591-stripe-app) shows the customer's Stripe details, active subscriptions and three most recent payments next to the conversation, and syncs attributes such as `stripe_subscription_status` and `stripe_subscription_period_start_at`. Only live mode data syncs. The app needs a paid Stripe account and is available on Intercom's Essential, Advanced and Expert plans. The pre-built [Stripe Data connector templates](https://www.intercom.com/help/en/articles/9909996-use-data-connector-templates) are read-only for subscriptions: they can look things up but not pause or cancel. Cancelling from Intercom needs a custom data connector that calls Stripe's write endpoints, or your teammate doing it in Stripe or in your own admin. ## A process you can set up this week ### 1. Tag every cancellation request Create a tag such as `cancel-request`. Add it with a Workflow keyword branch, and let teammates add it by hand when the Workflow misses one. Tags are what make the rest measurable. ### 2. Look up before you reply Before answering, check three things in the Stripe app panel or your admin: - the subscription status and when the current period ends; - whether the last payment failed (a "cancel" message right after a decline is sometimes a payment problem, not a decision to leave); - whether the customer is on an annual plan, which changes what "cancel" means for them. ### 3. Ask for the reason, once One short question is enough: "Before I cancel, can you tell me what's not working? It helps us improve." Do not make the answer a condition for cancelling. If you need a list of reasons that you can act on later, see [churn survey questions](/blog/cancellation-reasons-survey/). ### 4. Offer one alternative that fits the reason Match the offer to what they said: | Reason given | Reasonable single offer | |---|---| | Too expensive | A cheaper plan or a time-limited discount | | Not using it right now | A pause for one or two billing periods | | Missing a feature | Nothing, or an honest note if it is on the roadmap | | Switching to another tool | Nothing; cancel and ask for feedback | | Payment problem | A card update link, not a retention offer | We compare the options in [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). One offer, one message. If the customer says no, cancel. ### 5. Confirm in writing When you cancel, reply with a confirmation macro that states: - what was cancelled and the effective date; - whether access continues until the end of the paid period; - whether any refund applies, and how much; - that no further charges will be made. This message protects you later. If the customer disputes a charge, a dated confirmation in the conversation is exactly the kind of record a card issuer looks for. We cover that in [using Intercom conversations as chargeback evidence](/blog/intercom-chargeback-evidence/). ### 6. Close with the right tags Use a second macro (internal) to add the outcome: `cancel-done`, `cancel-paused`, `cancel-downgraded` or `cancel-retained`, plus the reason. Close the conversation. Now you can count outcomes by reason every month. ## Example macros **Cancel – first reply** > Hi, thanks for letting us know. I can cancel your subscription right away. Before I do, is there anything specific that isn't working for you? If you'd rather just cancel, reply "cancel" and I'll take care of it now. **Cancel – pause offer** (only if the reason fits) > Understood. If it's a quiet period, I can pause your subscription for up to two months instead, with no charge during the pause. If you'd still prefer to cancel, just say so and I'll do it straight away. **Cancel – confirmation** > Done: your subscription has been cancelled. You'll keep access until the end of your current billing period on [date], and you won't be charged again. If you change your mind, you can restart anytime from your account. Replace the bracketed parts by hand or with Intercom's attribute placeholders. ## Common mistakes - **Asking more than once.** Repeated offers in a support chat feel like a trap, and that is what regulators look at. - **Cancelling in Stripe but not confirming in Intercom.** The customer does not know it worked, and you have no record in the conversation. - **Treating payment failures as churn.** A customer whose card was declined may write "just cancel it" out of frustration. Send a card update link first; see [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). - **Letting reasons live only in free text.** If reasons are not tagged, you cannot tell next quarter whether price or a missing feature drove cancellations. ## Doing this with NoChurn NoChurn's Intercom connector is read-only: it never replies, tags or closes anything in Intercom, so the steps above stay with your team. What it adds is a self-serve path you can link to from your macros: a cancel flow with reasons and offers (discount, pause, plan change), with the one-click cancel always visible, hosted or headless through the API. NoChurn matches Intercom conversations to customers by email (doubtful matches are suggested to you, never merged automatically) and uses them in the churn score and churn drivers, and as dated evidence if a cancelled customer later disputes a charge. See [NoChurn + Intercom](/integrations/intercom/). --- # How to use Intercom conversations as chargeback evidence Source: https://www.nochurn.sh/blog/intercom-chargeback-evidence/ When a subscriber disputes a charge, the strongest evidence is often already sitting in your support inbox: the conversation where they asked about the renewal, used the product, or were told how to cancel. The problem is getting it out of Intercom in a form a card issuer will actually read, within the response deadline. This guide explains what Intercom lets you export, how to pick the right excerpts, and how to attach them to a dispute response on Stripe. It relies on Intercom's help center article on [exporting conversation data](https://www.intercom.com/help/en/articles/2046229-export-your-conversations-data), Intercom's developer reference for [retrieving a conversation](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/retrieveconversation) and [searching conversations](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/searchconversations), and Stripe's [dispute evidence best practices](https://docs.stripe.com/disputes/best-practices), [dispute categories](https://docs.stripe.com/disputes/categories) and [Dispute object](https://docs.stripe.com/api/disputes/object) (all accessed November 2026). ## What issuers want from support conversations Stripe's dispute evidence includes a `customer_communication` field. Stripe's [best practices page](https://docs.stripe.com/disputes/best-practices) describes it as communication relevant to the case, such as messages showing the customer received the product or service, used it, or was satisfied with it. A few rules from the same page shape how you use Intercom: - **One file per evidence type.** You can submit one piece of evidence per type, so combine all relevant messages into a single customer communication file. - **Excerpts, not threads.** Include only the relevant parts. If you attach a long thread, remove the duplicated quoted text. - **Say whether the customer contacted you.** Stripe recommends stating clearly whether the customer tried to resolve the issue with you before disputing. If they never wrote to support, that is worth saying too. - **No links, no video.** Stripe notes that banks will not review external content such as links, audio or video. Everything must be in the uploaded file. - **One submission.** Once you submit, you cannot add or change anything. Stripe also gives a limit that matters: emails and chat messages support your case but do not verify identity. In a fraud dispute, a friendly chat proves that someone used the account, not that the cardholder authorized the payment. Pair it with usage and login records. ## Which conversations help, by dispute reason Stripe groups card network reason codes into [categories](https://docs.stripe.com/disputes/categories). The ones subscription businesses see most, and the kind of Intercom message that helps for each: | Stripe category | What helps from Intercom | Pair with | |---|---|---| | Subscription canceled | Messages where the customer asked about the plan or renewal and was told how to cancel; absence of any cancellation request; continued use after the date they say they cancelled | Cancellation policy, renewal notices, usage log | | Product not received | Messages showing the customer used the service, asked how-to questions, or got their problem solved | Login and access logs | | Product unacceptable | Your replies showing you tried to fix the issue, and the customer's response | Refund policy, any partial credit offered | | Credit not processed | Messages where a refund was promised, denied, or already issued, with the policy explained | Refund policy, refund confirmation | | Fraudulent | A support conversation from the cardholder about the purchase before the dispute | IP and device data, account history | Stripe's guidance for cancellation disputes specifically mentions renewal notifications sent to the customer and acknowledgements of continued use after the claimed cancellation date. For cancellations, Stripe also suggests including any message showing the customer was told about non-refundable terms or offered an alternative. ## How to get conversations out of Intercom ### One conversation at a time According to Intercom's [export article](https://www.intercom.com/help/en/articles/2046229-export-your-conversations-data), a teammate can open a conversation in the Inbox, use the three-dot menu and export it. The transcript includes every reply with its timestamp, Fin and chatbot replies, and the names of customer and teammates. It leaves out internal notes, images, attachments and GIFs, which appear as text placeholders. That is close to what you want for evidence: dated, attributed, without internal notes. If an attachment matters (a screenshot the customer sent), add it separately. ### Many conversations, or automatically For volume, Intercom points to the API. The [search endpoint](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/searchconversations) finds conversations, and [retrieving a conversation](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/retrieveconversation) returns it with its conversation parts, ordered oldest to newest. Intercom's conversation model documentation notes two limits: parts are not returned when listing or searching, only when retrieving one conversation, and at most 500 parts are returned per conversation. Each part carries its author and a creation timestamp, which is what you need for dated quotes. ### Matching conversations to the disputed customer Intercom contacts and Stripe customers are separate records. If you use Intercom's [Stripe app](https://www.intercom.com/help/en/articles/1829591-stripe-app), it links them and syncs attributes such as `stripe_id`, but by default it only creates an Intercom user from a Stripe customer when both an email and a user ID are present in the Stripe customer's metadata. Otherwise you match by email. Be careful with that match. A customer can write from a work address and pay with a personal one, or share an inbox with a colleague. Before you put a conversation in front of an issuer, confirm it belongs to the cardholder's account. A wrong match weakens the whole response. ## Building the evidence file, step by step 1. **Read the dispute reason first.** Fetch the dispute in Stripe and note the `reason` and the response deadline (`evidence_details.due_by` on the [Dispute object](https://docs.stripe.com/api/disputes/object)). 2. **Find every conversation from that customer** in the window that matters: usually from signup or the last renewal to the dispute date. 3. **Pick the messages that answer the reason.** For a "subscription canceled" dispute, the key questions are: did the customer ever ask to cancel, and did they keep using the product after the date they claim? 4. **Quote, with dates and authors.** Use the format "2026-09-14 10:32 UTC, customer (jane@example.com): ..." Do not paraphrase what the customer said; quote it. 5. **Write a two-line summary at the top** of the file: what the conversations show, and whether the customer contacted support before disputing. 6. **Combine into one PDF** with your other customer communication (renewal reminder emails, cancellation confirmations). 7. **Keep it short.** Stripe asks for a succinct, chronological package. Three relevant excerpts beat forty pages of transcript. ## What not to do - **Do not include internal notes.** They were written for your team, can read as dismissive, and are not communication with the customer. - **Do not edit the customer's words.** Trim around them, but never change them. - **Do not reply to the customer about the dispute in a way you would not want an issuer to read.** Stripe recommends keeping a record of all communication during the dispute; assume it may be read. - **Do not refund outside the dispute.** Stripe's [How disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says you cannot issue a refund outside the dispute process while a dispute is open. - **Do not count on a withdrawal.** If the customer promises to withdraw the dispute, Stripe's [withdrawal guidance](https://docs.stripe.com/disputes/withdrawing) is to still submit evidence. ## Preventing the next one from the inbox The same conversations often show a dispute coming. A customer who writes "I never signed up for this" or "why was I charged again?" is one unanswered message away from calling their bank. Tag those conversations, answer them fast, and make cancelling or refunding easy when it is warranted. A refund the customer asked for is cheaper than a lost dispute plus its fee. ## Doing this with NoChurn NoChurn reads Intercom conversations through a read-only connector and matches them to customers by email; doubtful matches are suggested for you to confirm, never merged automatically. When a dispute opens on Stripe or Braintree, NoChurn gathers the evidence automatically, including dated verbatim excerpts from those conversations, cancel flow answers, emails sent and usage, and drafts a reply with AI. Nothing is sent to the processor until a person on your team has reviewed it. Intercom itself is unchanged: replying, tagging and closing stay there. See [NoChurn + Intercom](/integrations/intercom/). --- # How to spot churn signals in Intercom conversations Source: https://www.nochurn.sh/blog/intercom-churn-signals/ Most customers who leave a subscription say something first. They ask how to export their data, complain about a charge, rate a conversation badly, or write in three times about the same bug. In Intercom, those messages sit in the Inbox, get closed, and are rarely looked at again as a group. This guide shows how to turn Intercom conversations into churn signals you can count and act on: which signals to look for, how to capture them with tags and conversation data attributes, how to read conversation ratings, and how to get the data out. It sticks to Intercom's own documentation: [conversation ratings](https://www.intercom.com/help/en/articles/7872853-measure-customer-satisfaction-with-conversation-ratings), [CSAT reporting](https://www.intercom.com/help/en/articles/10244420-customer-satisfaction-reporting), the [conversation tags report](https://www.intercom.com/help/en/articles/3267226-conversation-tags-report), [conversation data](https://www.intercom.com/help/en/articles/6546210-using-conversation-data-in-the-inbox), [Topics Explorer](https://www.intercom.com/help/en/articles/11390087-use-the-topics-explorer-to-see-what-s-driving-volume), [data exports](https://www.intercom.com/help/en/articles/2046229-export-your-conversations-data) and the [Conversation API reference](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/conversation) (all accessed November 2026). ## The signals worth capturing Not every conversation says something about churn. These are the patterns that usually do. Treat them as hypotheses to check against your own cancellations, not as rules. | Signal | What it looks like in Intercom | How to capture it | |---|---|---| | Explicit cancellation intent | "How do I cancel", "close my account", "stop billing me" | Tag, or a conversation data attribute set by a Workflow | | Billing friction | Disputed charge, unexpected renewal, refund request | Tag `billing-complaint` | | Data exit | Questions about exporting data or deleting the workspace | Tag `data-export` | | Low satisfaction | A bad conversation rating, often with a remark | Conversation rating (native) | | Repeated contact | The same customer writing about the same issue several times | Attribute such as "Issue" plus reporting by company or user | | Missing feature | "Does it do X?" followed by "we'll look elsewhere" | Tag `feature-gap` with a list attribute naming the feature | The goal is a small, stable set. A list of forty tags that nobody applies consistently is worse than five that everyone uses. ## Tags vs conversation data attributes Intercom gives you two ways to label a conversation, and they suit different jobs. **Tags** are quick and free-form. Intercom's [conversation tags report](https://www.intercom.com/help/en/articles/3267226-conversation-tags-report) shows new conversations, tagged conversations, tagged conversations over time and the most used tags. Two caveats from that page matter for churn analysis: - Conversations are dated by their **start date**, not the date the tag was added. - Tag reporting is updated with a delay of **24 to 36 hours**, so it is not a real-time alert. **Conversation data attributes** are closer to ticket fields. Intercom's [conversation data guide](https://www.intercom.com/help/en/articles/6546210-using-conversation-data-in-the-inbox) explains that you create them under Settings > Data > Conversations, with a data type of text, number, true/false or a list of values. They can be set manually in the conversation, with macros, or automatically by Workflows. For churn signals, a list attribute such as "Churn signal" with fixed values (Cancellation request, Billing complaint, Data export, Feature gap, None) is usually more reliable than tags: teammates pick from a list instead of typing, and the values are consistent in reports. ## Routing cancellation intent with Workflows Intercom's help center on [assigning conversations](https://www.intercom.com/help/en/articles/6561699-assign-conversations-to-teammates-and-teams) notes that Workflows can automatically tag conversations, mark them as priority, set conversation attributes and route to a team. A simple setup for cancellation intent: 1. Create a list attribute "Churn signal" (Settings > Data > Conversations). 2. Build a Workflow that runs when a customer sends a message. Add a branch for messages that contain phrases such as "cancel", "unsubscribe", "close my account" or "refund". 3. In that branch, set "Churn signal" to Cancellation request and add a tag if you also want it in the tags report. 4. Assign the conversation to the team that handles billing or retention. 5. Review the branch every few weeks. Keyword rules catch "cancel my order" and "cancel the meeting" too, so expect false positives and let teammates correct the attribute. One rule that should never change: if the customer asks to cancel, the team that receives the conversation cancels. Routing is there so the request is handled fast and recorded properly, not to put more steps in front of it. See our guide on [click-to-cancel rules](/blog/click-to-cancel-rules/). If your workspace runs Fin, Intercom also documents [Topics Explorer](https://www.intercom.com/help/en/articles/11390087-use-the-topics-explorer-to-see-what-s-driving-volume), which uses AI to group conversations into topics and subtopics. Admins can create, merge, rename and delete topics, so you can shape a "Cancellation" topic by hand. Intercom lists requirements: it needs the Pro add-on, it is available only while Fin is live, and the initial model draws on inbound conversations from the last 90 days. It is separate from the older keyword-based conversation topics report. ## Reading conversation ratings Conversation ratings are Intercom's built-in CSAT. According to Intercom's [conversation ratings article](https://www.intercom.com/help/en/articles/7872853-measure-customer-satisfaction-with-conversation-ratings): - After a teammate closes a conversation, the customer sees five emoji reactions (in the Messenger) or five emoji with text labels (in email), and is asked for an optional comment, called a remark. - The rating applies to the teammate who last sent a message in the conversation. - Group conversations, with more than one user or lead, are not surveyed. The [CSAT reporting article](https://www.intercom.com/help/en/articles/10244420-customer-satisfaction-reporting) describes a Surveyed CSAT report template available to teammates with reporting access, including conversation ratings and remarks broken out by sentiment. Intercom suggests filtering by conversation rating to find negative conversations and work on those first. Custom CSAT charts, and using conversation rating attributes in custom reports, require the Advanced or Expert plan. For churn, the remark is often more useful than the score. A two-out-of-five with "third time I'm asking about this invoice" tells you more than any average. Read the negative remarks weekly and label each conversation with your "Churn signal" attribute. Two cautions: 1. **A rating describes one conversation, not the customer's whole relationship.** A happy rating on a cancellation handled quickly is a good outcome, not a sign the customer is staying. 2. **Response bias is real.** Only some customers rate. Do not compare small samples across teammates or months as if they were precise. ## Getting the data out To link support signals to who actually cancelled, you need the data outside Intercom. Intercom's [export article](https://www.intercom.com/help/en/articles/2046229-export-your-conversations-data) and related help pages describe several paths: | Path | What you get | Limits Intercom documents | |---|---|---| | Reports > Dataset export | CSV of conversation metadata: IDs, timestamps, attributes, metrics | No full message content; browser downloads capped at 10,000 rows, larger ones emailed | | Inbox export | Transcripts as text or PDF | A few hundred conversations per operation | | Conversations API | Full conversation objects, including tags, custom attributes and the rating | Rate limits and pagination apply | The [Conversation object](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/conversation) in the API carries `tags`, `custom_attributes` (your conversation data attributes) and `conversation_rating`, which holds a rating from 1 to 5 and an optional remark. That is enough to join Intercom data to your billing data by customer email or user ID. ## A weekly routine 1. **Monday:** open the Surveyed CSAT report, filter on negative ratings from the past week, read every remark. 2. Set the "Churn signal" attribute on any conversation that shows one and that the Workflow missed. 3. Export the week's conversations with a churn signal (Dataset export or API). 4. Match them to your subscription data: who cancelled, who downgraded, who failed a payment in the following weeks. 5. **Once a month:** count which signals came before cancellations most often, and check whether the reasons customers give in support match the reasons they give when cancelling. Our guide on [finding what predicts churn](/blog/predict-churn-with-customer-data/) explains how to read that without confusing correlation with cause. Keep the customer's words as they wrote them. A quote is evidence; a summary written later is an opinion. ## Doing this with NoChurn NoChurn's Intercom connector is read-only: it reads conversations and never replies, tags or changes anything in Intercom. Conversations are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. Matched conversations feed the churn score (0 to 100) and the churn drivers view, and they are kept as dated, verbatim evidence that can be attached to a chargeback response on Stripe or Braintree, which is drafted by AI and sent only after you review it. Tagging, routing, ratings and replies stay in Intercom. See [NoChurn + Intercom](/integrations/intercom/). --- # Do bad Intercom ratings predict churn? How to check Source: https://www.nochurn.sh/blog/intercom-csat-churn/ It seems obvious that a customer who rates a support conversation badly is more likely to cancel. Sometimes it is true. Sometimes the unhappy raters are your most engaged customers, the ones who care enough to complain, and the quiet ones are the ones who leave. You only find out by checking against your own billing data. This guide shows how to run that check with Intercom's conversation ratings: where the data lives, how to join it to churn, and how to read the result without fooling yourself. It sticks to Intercom's help center on [conversation ratings](https://www.intercom.com/help/en/articles/7872853-measure-customer-satisfaction-with-conversation-ratings), [Surveyed CSAT reporting](https://www.intercom.com/help/en/articles/10244420-surveyed-csat-reporting), [reporting metrics and attributes](https://www.intercom.com/help/en/articles/7022438-reporting-metrics-attributes) and the [Teammate changes conversation state](https://www.intercom.com/help/en/articles/6904514-teammate-changes-conversation-state) trigger, plus the API's [conversation model](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/conversation) (all accessed November 2026). ## How Intercom ratings work ### How the survey is sent Intercom sends its CSAT survey through Workflows. The usual setup is the "Ask for conversation rating" action right after the [Teammate changes conversation state](https://www.intercom.com/help/en/articles/6904514-teammate-changes-conversation-state) trigger, so the customer is asked when a conversation is closed. You can also add the action to other workflow paths. The default survey is a five-option emoji scale. If you want a different scale, Intercom suggests building your own with reply buttons, but those custom ratings are not included in the built-in CSAT report. ### What is stored Each rating is attached to the conversation. Intercom's API documents it as an integer from 1 to 5 with an optional remark (the customer's comment). Two details matter for analysis: - Once a customer adds a remark, the rating can no longer be changed. - You cannot create or edit ratings through the API; it is read-only for this data. ### How Intercom computes CSAT Intercom's [reporting definitions](https://www.intercom.com/help/en/articles/7022438-reporting-metrics-attributes) count the two highest ratings as positive. The CSAT score is positive ratings divided by all ratings, across teammates, Fin AI Agent and chatbots. The [Surveyed CSAT report](https://www.intercom.com/help/en/articles/10244420-surveyed-csat-reporting) template shows overall, teammate and Fin scores, CSAT over time, remarks grouped by rating, and the survey request and response rates. Building custom CSAT charts requires the Advanced or Expert plan. That score answers "how is our support doing?" It does not answer "which customers are about to leave?" For that, you need ratings per customer, joined to billing. ## Getting the data out You have two options. **Dataset export.** In Reports, the dataset export includes a "Conversation Ratings" dataset with conversation-level rating data. This is the fastest path for a one-off analysis. **API.** Retrieve conversations through the [conversations API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/conversation); each one carries its rating, remark and contacts. Intercom notes that older API versions can return a null rating for ratings visible in the app, so use a recent API version. For each rating, keep: conversation ID, contact ID and email, rating (1 to 5), remark, rated-at date, and whether a teammate or Fin handled the conversation. ## Joining ratings to churn ### 1. Build a customer table from billing From Stripe or your billing system, list every customer who was active at some point in your window, with: - start date; - cancellation date (or empty if still active); - whether the cancellation was voluntary or due to a failed payment. Keep involuntary churn separate. A customer whose card expired did not leave because of a bad support chat. Mixing the two hides the effect you are looking for; see [involuntary churn](/blog/involuntary-churn/). ### 2. Match Intercom contacts to customers Match by email, or by the Stripe ID if you use Intercom's [Stripe app](https://www.intercom.com/help/en/articles/1829591-stripe-app), which syncs `stripe_id` onto Intercom users. Review the doubtful cases by hand: shared inboxes, aliases, a colleague writing on behalf of the account owner. For B2B products, decide whether a rating from any team member counts for the account. ### 3. Pick a fixed window For each customer, take ratings from a defined period (for example the 90 days before a reference date), and check whether they cancelled in the following 90 days. Without a fixed window, long-lived customers simply accumulate more ratings, and you end up measuring tenure. ### 4. Group and compare A simple first cut: | Group | Definition | |---|---| | Rated low | At least one rating of 1 or 2 in the window | | Rated high only | Only ratings of 4 or 5 | | Rated middle only | Only 3s, or a mix without lows | | Contacted, no rating | Had conversations but did not answer the survey | | No contact | No conversation in the window | Compute the voluntary churn rate in the next period for each group. If you need a refresher on the formula, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ### 5. Look at the remarks The numbers tell you whether there is a link; remarks tell you why. Read every remark attached to a low rating for customers who later cancelled. Group them by theme: billing confusion, a bug, a missing feature, slow answers. That list is more useful than the correlation itself. ## Reading the result honestly A few traps catch almost everyone: - **Small samples.** If only a small share of conversations get rated, the "rated low" group may be a few dozen customers. Report the count next to every rate, and do not act on a difference you could get by chance. - **Response bias.** People who answer surveys differ from people who do not. The "contacted, no rating" group is often the most interesting one. - **Rating the agent vs rating the product.** A 1 can mean "your agent was rude" or "your product cannot do this". Only the second is likely to drive churn, and only the remark tells you which. - **Fin vs teammates.** Ratings on AI-handled conversations and on human-handled ones may behave differently. Compare them separately before merging. - **Correlation is not causation.** A low rating can be a symptom of a customer already on their way out. That still makes it a useful signal; it does not mean better support alone would have kept them. ## What to do if ratings do predict churn If low-rated customers churn noticeably more, act on the signal: 1. **Give low ratings an owner.** Intercom's reports can filter by rating and remark; have someone review the low-rated conversations every day and follow up within a day. 2. **Follow up on the remark, not the score.** Reply to what the customer said. 3. **Check billing at the same time.** A low rating right after a failed payment or a surprise renewal needs a billing fix, not an apology. 4. **Re-run the analysis each quarter** with the same windows, so you can see whether the gap narrows. If ratings do not predict churn in your data, that is a result too. Look at other support signals instead: conversation volume, topics, or time to first reply. We cover a wider approach in [how to find what predicts churn with your own customer data](/blog/predict-churn-with-customer-data/). ## Doing this with NoChurn NoChurn's Intercom connector is read-only. It reads conversations and ratings, matches them to billing customers by email (doubtful matches are suggested for you to confirm, never merged automatically), and uses them as inputs to the 0–100 churn score and to the churn drivers analysis, which ranks the attributes most correlated with churn (correlation, not causation). It does not change your CSAT setup or send surveys; that stays in Intercom. You can also push your own attributes by API to compare support signals with product usage. See [NoChurn + Intercom](/integrations/intercom/). --- # How to tell customers about a failed payment in Intercom Source: https://www.nochurn.sh/blog/intercom-failed-payment-messages/ When a renewal fails, the customer usually does not know. They find out when access stops, or when a dunning email lands in a promotions tab. If you already use Intercom to talk to customers inside your product, it can carry the failed payment message to the place where the customer actually is: the app. This guide shows what Intercom can do with payment failure data, how to set up an in-app message, and how to handle the support conversations that follow. It relies on Intercom's help center for the [Stripe app](https://www.intercom.com/help/en/articles/1829591-stripe-app), [event-triggered messages](https://www.intercom.com/help/en/articles/5180516-send-repeatable-messages-based-on-events-you-track-in-intercom), [banners](https://www.intercom.com/help/en/articles/4557393-how-to-create-a-banner-message) and [macros](https://www.intercom.com/help/en/articles/6433193-creating-and-managing-macros), and on the [Data Events API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/data-events) reference (all accessed November 2026). ## Intercom does not retry payments Start with what Intercom is not. It does not charge cards, retry payments or update payment methods. Those stay with your billing system: on Stripe, retries come from Smart Retries or your own schedule, and the card update happens on a Stripe-hosted page or in your app. Intercom's role is communication: telling the customer, at the right moment, with a link that fixes the problem. For the billing side, see [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). ## Getting payment failure data into Intercom ### Option 1: the Stripe app Intercom's [Stripe app](https://www.intercom.com/help/en/articles/1829591-stripe-app) imports Stripe customer data as attributes on Intercom users. Among the documented attributes: | Attribute | What it holds | |---|---| | `stripe_delinquent` | Stripe's delinquency status (true or false) | | `stripe_subscription_status` | The subscription status | | `stripe_card_expires_at` | When the saved card expires | | `stripe_card_brand` | The card brand | The app also sends events to Intercom, including `charge_failed`, `charged`, `invoice_created` and `deleted_subscription`. Constraints from the same article: only live mode data syncs (test mode is not supported), the app needs a paid Stripe account, and it is available on Intercom's Essential, Advanced and Expert plans. By default, an Intercom user is only created from a Stripe customer when the Stripe customer has both an email and a user ID in its metadata. ### Option 2: send your own event If you are not on Stripe, or want more control, send an event yourself when your billing system reports a failure. The [Data Events API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/data-events) takes a `POST` to `/events` with an `event_name`, a `created_at` Unix timestamp, a user identifier (`user_id` or `email`) and optional `metadata`. Nested JSON is not supported in metadata, and the API documentation limits the number of tracked metadata keys per event, so keep it flat and small: for example, an amount, an invoice ID and the URL of the card update page. A custom event lets you name it clearly (`payment_failed`) and carry the update link with it, which the Stripe app's events do not do for you. ## Choosing the message type ### Banners: visible until the problem is fixed A [banner](https://www.intercom.com/help/en/articles/4557393-how-to-create-a-banner-message) sits at the top of the page. If you hide the dismiss button, Intercom keeps showing it until the user no longer matches the audience rules or completes the configured action. That fits a payment failure well: target users where `stripe_delinquent` is true (or your own attribute), and the banner disappears by itself once the payment goes through and the attribute flips back. Limits from Intercom's documentation: - Banners support dynamic audiences only. - They are only delivered when the user is seen online in the Messenger. - They do not run natively in iOS or Android apps. - If several banners overlap, they show in the order they were set live, and a non-dismissible banner placed first blocks later ones. ### Event-triggered chats or posts: once per failure To send a message each time a failure happens, use an [event-triggered message](https://www.intercom.com/help/en/articles/5180516-send-repeatable-messages-based-on-events-you-track-in-intercom). Intercom documents several conditions: - It requires the Proactive Support Plus add-on. - The message must use a dynamic audience, and you can add only one event-based rule. - Events that happened before the message went live do not trigger it. - If the event arrives outside the message's schedule, the message is not sent for that event; it is not held until the schedule opens. - Event metadata cannot be used in messages inside a Series. Intercom suggests building the message standalone first, then copying it into the Series. ### Email: still needed In-app messages only reach customers who log in. A customer who has stopped using the product needs an email, and that is often the one who matters most. Keep a dunning email sequence running from your billing system or a dedicated tool. Ready-made examples are in [dunning email templates](/blog/dunning-email-templates/). ## Writing the message The in-app message should be short and specific: > **Your last payment didn't go through.** Update your payment method to keep your [plan name] plan active. [Update payment method] Rules worth following: 1. **One action.** A single button to the card update page. Do not send customers to a general settings page. 2. **No blame, no reason.** Do not show the decline reason. For some codes, such as lost or stolen cards, Stripe tells you to present the decline as generic; see [Stripe decline codes explained](/blog/stripe-decline-codes/). 3. **Say what happens next**, honestly: when you will try again, or when access will change. Do not invent a deadline you will not enforce. 4. **Show it to the right person.** In B2B products, the person who sees the banner may not be the one who pays. Target admins or billing contacts if you have that attribute. ## Handling the replies Failed payment messages create conversations: "I updated my card, why is it still failing?", "Can I pay by bank transfer?", "Just cancel it." Prepare [macros](https://www.intercom.com/help/en/articles/6433193-creating-and-managing-macros) for each. Macro actions can add tags and assign to a team, so tag these conversations `payment-failed` to measure volume. Before replying, check the Stripe app panel, which shows the customer's subscriptions and three most recent payments beside the conversation. A few common situations: | Customer says | Check | Answer | |---|---|---| | "I updated my card" | Did a new payment method attach, and was the invoice retried? | If not retried yet, explain when; or retry from your billing system | | "My bank says it's fine" | The decline code | For generic declines, suggest another card or calling the bank again | | "Just cancel" | Whether they mean it | Cancel if they confirm; a failed payment is not a reason to make cancelling harder | | "I was charged twice" | Payment history | Explain or refund promptly; this is how disputes start | ## Common mistakes - **Using the banner as the only channel.** Customers who do not log in never see it. - **Leaving the banner up after recovery.** Use an attribute that flips back automatically, not a manual list. - **Testing with Stripe test mode.** The Stripe app ignores test data, so test with a custom event on a test user instead. - **Messaging during a retry that is about to succeed.** If your billing system retries within hours for some declines, a delay before the first message can avoid needless alarm. ## Doing this with NoChurn NoChurn handles the billing side that Intercom does not: smart retries timed to the decline reason and to likely paydays, AI-written recovery emails that you review, and a hosted card update page you can link to from an Intercom banner or macro. Its Intercom connector is read-only, so it does not send Intercom messages for you; your banners and macros stay in Intercom. It reads conversations, matched to customers by email (doubtful matches are suggested, never merged automatically), and uses them in the churn score. See [NoChurn + Intercom](/integrations/intercom/). --- # How Lemon Squeezy handles failed subscription payments Source: https://www.nochurn.sh/blog/lemon-squeezy-failed-payments/ When a subscription renewal fails on Lemon Squeezy, a lot happens without you doing anything: the charge is retried, the customer gets emails, and the subscription moves through a few statuses before it ends. Knowing exactly what Lemon Squeezy does, and what it leaves to you, is the difference between a customer who quietly drops off and one who updates their card. This guide walks through that lifecycle step by step, then gives practical advice you can apply in your own app. It sticks to Lemon Squeezy's own documentation: the [Recovery and Dunning help page](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning), the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object), the [webhook event types](https://docs.lemonsqueezy.com/help/webhooks/event-types) and the [Subscriptions help page](https://docs.lemonsqueezy.com/help/products/subscriptions) (all accessed November 2026). Where the docs do not say something, we say so. ## The failed payment lifecycle on Lemon Squeezy Lemon Squeezy is a merchant of record: it charges the customer, runs the retries and sends the billing emails. Your job is mostly to react to status changes in your app. ### Step 1: the renewal fails and the subscription goes past_due According to the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object), when a renewal payment fails the subscription status becomes `past_due`. The subscription then goes through **4 payment retries over the course of 2 weeks**. If one of those retries succeeds, the status goes back to `active`. The [Recovery and Dunning page](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning) adds two details: - During the retries, the subscription still counts as active from an access point of view: the customer keeps using your product. - Each failed attempt triggers an email asking the customer to update their billing details. ### Step 2: retries run out and the subscription becomes unpaid If all retries fail, the status moves to `unpaid`. This is where Lemon Squeezy's dunning starts. Per the [Recovery and Dunning page](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning), dunning emails are sent over a set period, and each one links to a page where the customer can update their payment details and reactivate. ### Step 3: dunning ends, or the subscription stays unpaid What happens after that depends on your Recovery settings: - You can set a delay after which the subscription is automatically cancelled. Once that happens, the customer can no longer reactivate it. - You can leave the subscription `unpaid`, which lets the customer reactivate it at any time. - If you turn dunning off, the status simply stays `unpaid`, and it is up to you to decide what that means for access. When dunning completes, Lemon Squeezy sends `subscription_expired`, which its [event types page](https://docs.lemonsqueezy.com/help/webhooks/event-types) describes as firing "once dunning has been completed for past_due subscriptions". ### PayPal is different The Recovery page notes that PayPal subscriptions follow a different retry cadence, with attempts every 5 days. If a meaningful share of your customers pay with PayPal, do not assume the card timeline applies to them. ## Statuses at a glance | Status | What it means | Should the customer have access? | |---|---|---| | `active` | Paid and in good standing | Yes | | `past_due` | Renewal failed, retries in progress (4 over about 2 weeks) | Yes, per Lemon Squeezy | | `unpaid` | Retries exhausted, dunning running or dunning off | Your call; Lemon Squeezy's lifecycle docs say access should end only at `expired` | | `cancelled` | Cancelled, in its grace period until `ends_at` | Yes, until `ends_at` | | `expired` | Ended | No | The [Subscriptions help page](https://docs.lemonsqueezy.com/help/products/subscriptions) says customers should keep access in every status except `expired`. Some teams prefer to restrict features while `unpaid`; if you do, say so clearly in your app so the customer knows why. ## The webhooks you need The [event types page](https://docs.lemonsqueezy.com/help/webhooks/event-types) lists the subscription events. For failed payments, these four matter: | Event | When it fires | Payload | |---|---|---| | `subscription_payment_failed` | A renewal payment fails (not the first payment) | Subscription invoice object | | `subscription_payment_recovered` | A payment succeeds after a failure | Subscription invoice object | | `subscription_payment_success` | Any successful payment; always sent alongside `subscription_payment_recovered` | Subscription invoice object | | `subscription_updated` | Any change to the subscription, including status changes | Subscription object | | `subscription_expired` | After a cancelled subscription ends, or once dunning completes | Subscription object | Two things to note. First, `subscription_payment_failed` carries a [subscription invoice object](https://docs.lemonsqueezy.com/api/subscription-invoices/the-subscription-invoice-object), not the subscription itself, so you will usually fetch the subscription to read its status. Second, Lemon Squeezy says `subscription_updated` fires on every change after the initial payment, so for many apps it is enough to listen to it and read `status`. The docs we used do not describe a decline reason field comparable to card network decline codes on these events, so do not build logic that depends on one without checking your own payloads. ## The update payment link Every subscription object has a `urls` attribute with an `update_payment_method` link: a pre-signed URL where the customer can change their card. The [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object) says these signed URLs are valid for 24 hours, and the [managing subscriptions guide](https://docs.lemonsqueezy.com/guides/developer-guide/managing-subscriptions) makes the same point for recovery links: fetch the subscription again to get a fresh one rather than storing it. That has a practical consequence. If you send your own emails, do not paste a stored link into an email that might be opened three days later. Link to a page in your app that fetches a fresh URL and redirects. ## Configuring Recovery settings Lemon Squeezy's dunning emails are configured on the Recovery settings page of your store. The [Recovery and Dunning page](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning) says you can enable or disable dunning and edit the emails, subject lines, content and delivery schedule, with defaults provided. A sensible setup: 1. **Keep dunning on.** It costs nothing and it reaches customers who never open your app. 2. **Rewrite the default copy in your voice.** Say what the product is, what happens if the card is not updated, and keep one clear button. 3. **Decide on automatic cancellation deliberately.** Leaving subscriptions `unpaid` keeps the door open for reactivation. Auto-cancelling gives you a clean end date. Pick one and make your app's access rules match it. 4. **Test it.** Lemon Squeezy's test mode lets you [simulate webhook events](https://docs.lemonsqueezy.com/help/webhooks/simulate-webhook-events), so you can check your app's reaction to `past_due`, `unpaid` and `expired` before a real customer hits them. ## Practical advice you can apply today Lemon Squeezy's built-in behavior is a solid baseline. The gaps are mostly on your side of the integration. ### 1. Show the problem inside your app Billing emails get filtered. When a subscription is `past_due` or `unpaid`, show a banner in your app with a button to your "update card" route. This is often the moment the customer is most likely to act, because they are already using the product. ### 2. Handle statuses explicitly Map every status to an access rule in one place in your code. A common bug is treating anything other than `active` as "no access", which locks out `past_due` and `cancelled` customers who have paid for their current period. ### 3. Verify and deduplicate webhooks Lemon Squeezy signs each request with an HMAC in the `X-Signature` header ([signing requests](https://docs.lemonsqueezy.com/help/webhooks/signing-requests)) and retries non-200 responses up to three more times with exponential backoff ([webhook requests](https://docs.lemonsqueezy.com/help/webhooks/webhook-requests)). Verify the signature against the raw body and make your handler safe to run twice. ### 4. Send one human message The automatic emails cover the mechanics. A short, plain message from a real person ("Your card didn't go through, here's the link, reply if anything's wrong") often lands differently. Send it once, around the time the subscription becomes `unpaid`, not on every failed attempt. ### 5. Track recovery Count `subscription_payment_failed` events and `subscription_payment_recovered` events per month. The ratio is your own recovery rate, measured on your data. If it moves after a copy change, you know the change mattered. ## Doing this with NoChurn Lemon Squeezy keeps running the payment, the retries and its own dunning emails; NoChurn does not replace that. NoChurn reads your Lemon Squeezy webhooks, puts every failed payment in one timeline, and can add AI-written recovery emails that you review before they are sent. It also gives each customer a churn score from 0 to 100, and disputes, which Lemon Squeezy handles as the merchant of record, appear read only. NoChurn is free under $300 MRR with all features on every plan. See [NoChurn + Lemon Squeezy](/integrations/lemon-squeezy/). --- # How to pause subscriptions on Lemon Squeezy Source: https://www.nochurn.sh/blog/lemon-squeezy-pause-subscriptions/ A customer who wants a break is not the same as a customer who wants to leave. If the only button they can find is "Cancel", you lose both. Lemon Squeezy has a native pause feature, and it is more flexible than many teams realise: two pause modes, an optional automatic resume date, and full API support. This guide explains how pausing works on Lemon Squeezy, how to trigger it from the dashboard, the customer portal or the API, and how to offer it at the right moment. It sticks to Lemon Squeezy's own documentation: the [Update a Subscription API reference](https://docs.lemonsqueezy.com/api/subscriptions/update-subscription), the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object), the [managing subscriptions guide](https://docs.lemonsqueezy.com/guides/developer-guide/managing-subscriptions), the [Customer Portal page](https://docs.lemonsqueezy.com/help/online-store/customer-portal) and the [webhook event types](https://docs.lemonsqueezy.com/help/webhooks/event-types) (all accessed November 2026). ## The two pause modes Lemon Squeezy pauses a subscription by setting a `pause` object on it. The object has a `mode`, and the [Update a Subscription reference](https://docs.lemonsqueezy.com/api/subscriptions/update-subscription) documents two values: | Mode | What Lemon Squeezy says it is for | What the customer gets | |---|---|---| | `void` | When you cannot offer your service for a period (maintenance is the example given): invoices are voided so customers are not charged | No charge, and by implication no service | | `free` | Offering the subscription for free while halting payment collection | No charge, and continued service | Both modes stop payment collection. The difference is about what you promise in return, and that is a product decision, not a billing one. Lemon Squeezy does not enforce access for you: your app decides what a paused customer can do. In practice: - **`void` is the usual "pause" a customer asks for.** They are not using the product for a while, and they are not paying for it. - **`free` is a goodwill gesture.** Use it when you want to keep a customer using the product without charging them, for example while you fix an issue that affected them. ## Pausing with a resume date The `pause` object also takes an optional `resumes_at`, an ISO 8601 date-time. When it is set, the subscription continues collecting payments from that date. Without it, the pause lasts until someone unpauses it. The documentation we used does not state a maximum pause length. If you want one, enforce it in your own interface by always sending a `resumes_at`. ## Unpausing To end a pause, you set `pause` to `null` on the subscription. Per the [Update a Subscription reference](https://docs.lemonsqueezy.com/api/subscriptions/update-subscription), the subscription then changes back to `active` and payment collection resumes on its original schedule. "Original schedule" is worth thinking about. The billing anchor does not move because of the pause, so a customer who unpauses may be charged at their usual renewal date rather than on the day they come back. If that could surprise them, say so on the screen where they resume. ## Three ways to pause ### 1. From the dashboard The [managing subscriptions guide](https://docs.lemonsqueezy.com/guides/developer-guide/managing-subscriptions) describes the manual path: in your Lemon Squeezy dashboard, go to Store, then Subscriptions, select the subscription, and click "Pause Subscription". Useful for support requests. ### 2. From the customer portal Lemon Squeezy's hosted [Customer Portal](https://docs.lemonsqueezy.com/help/online-store/customer-portal) lets subscribers pause and unpause, cancel and resume, and switch products. You choose which features the portal shows in its design settings. If you rely on the portal, check that pausing is turned on and visible next to cancellation. ### 3. From the API To pause from your own app, send a `PATCH` to the subscription endpoint with a `pause` object, as shown in the [Update a Subscription reference](https://docs.lemonsqueezy.com/api/subscriptions/update-subscription). A minimal request body, in JSON:API format: ```json { "data": { "type": "subscriptions", "id": "123", "attributes": { "pause": { "mode": "void", "resumes_at": "2027-02-01T00:00:00.000000Z" } } } } ``` To unpause, send the same request with `"pause": null`. ## What changes on the subscription According to the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object): - A paused subscription has the status `paused`. - The `pause` attribute holds the mode and `resumes_at` while paused, and is `null` otherwise. The [event types page](https://docs.lemonsqueezy.com/help/webhooks/event-types) lists two dedicated events, `subscription_paused` and `subscription_unpaused`. Lemon Squeezy also sends `subscription_updated` on every change, so if you already handle that event and read `status`, pausing needs no extra webhook. ## How to offer a pause well Lemon Squeezy gives you the mechanics. Whether customers actually choose a pause depends on how you offer it. ### Offer it at the moment of cancellation The highest-intent moment is when the customer clicks "Cancel". If your app sends customers straight to the portal, they see pause as one option among several. If you build your own cancel page, you can ask why they are leaving first, then offer a pause to the customers whose reason fits: "taking a break", "seasonal", "not using it right now", "budget this month". Keep the cancel option visible on that page. A pause offer should be a genuine alternative, not a wall. Hiding cancellation creates support tickets and chargebacks, and in several places it is regulated. ### Make the pause concrete "Pause your subscription" is vague. "Pause for 1, 2 or 3 months, no charge, your data stays here" is a decision someone can make in five seconds. Map each choice to a `resumes_at` and send it with the request. ### Tell them before it ends A pause that silently resumes billing feels like a trap. Schedule a reminder a few days before `resumes_at`: "Your pause ends on March 1. You'll be charged on your usual date. Want to extend or cancel?" Lemon Squeezy's docs we used do not describe a built-in reminder for this, so send it from your own email tool. ### Pick the mode on purpose For a customer-requested break, use `void`. Reserve `free` for when you choose to keep serving a customer at no cost. Mixing them up means either charging for nothing or giving away service you meant to pause. ### Measure it Count `subscription_paused` events and what happens next for each paused customer: unpaused and renewed, cancelled during the pause, or cancelled right after resuming. That tells you whether pause offers save customers or only delay the cancellation. ## A checklist before you ship 1. Pausing is enabled in the customer portal, or your own cancel page offers it. 2. Your app maps `paused` to an access rule (no access for `void`, normal access for `free`). 3. Every pause from your interface sends a `resumes_at`. 4. A reminder goes out before the pause ends. 5. Your webhook handler updates your records on `subscription_paused`, `subscription_unpaused` or `subscription_updated`. 6. You have tested the full path in test mode with [simulated webhook events](https://docs.lemonsqueezy.com/help/webhooks/simulate-webhook-events). ## Doing this with NoChurn Pausing itself stays a Lemon Squeezy feature; NoChurn uses it rather than replacing it. NoChurn adds a cancel flow in front of the cancel button: the customer gives a reason, sees an offer that fits it (a pause, a discount or a plan change), and can always cancel in one click. The flow is hosted, or headless through the API if you want it fully in your own design. Answers feed the churn score and the win-back emails sent at day 30, 60 and 90. See [NoChurn + Lemon Squeezy](/integrations/lemon-squeezy/). --- # How to reduce churn on Lemon Squeezy Source: https://www.nochurn.sh/blog/lemon-squeezy-reduce-churn/ Lemon Squeezy already does a fair amount to keep subscriptions alive: it retries failed payments, sends recovery emails, and gives customers a portal where they can pause instead of cancelling. This guide explains what it does natively, which subscription states and webhooks to watch, and where a cancel flow and win-back fit on top. It sticks to Lemon Squeezy's own documentation: [subscriptions](https://docs.lemonsqueezy.com/help/products/subscriptions), [the subscription object](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object), [recovery and dunning](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning), [managing subscriptions with the API](https://docs.lemonsqueezy.com/guides/developer-guide/managing-subscriptions), [customer portal](https://docs.lemonsqueezy.com/help/online-store/customer-portal), [webhook event types](https://docs.lemonsqueezy.com/help/webhooks/event-types), [discounts](https://docs.lemonsqueezy.com/api/discounts) and [refunds and chargebacks](https://docs.lemonsqueezy.com/help/payments/refunds-chargebacks) (all accessed November 2026). ## Lemon Squeezy is the merchant of record Lemon Squeezy [sells to your customers as merchant of record](https://docs.lemonsqueezy.com/help/payments/merchant-of-record). It processes payments, refunds and chargebacks. Its docs say that for a dispute it typically refunds on your behalf and deducts the amount (minus its platform fee) plus a $15 dispute fee from your next payout, and that it provides information to the payment provider to make the case. Too many chargebacks can lead it to suspend a store. For churn work, this means you change subscriptions through Lemon Squeezy's API and portal, and you do not run payments yourself. ## The subscription states The [subscription object](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object) has seven statuses. Knowing which ones still grant access is the base of everything else. | Status | Meaning | Access | |---|---|---| | `on_trial` | On a trial, waiting for the first payment | Yes | | `active` | Active and valid | Yes | | `paused` | Payment collection paused, subscription still live | Optional, your choice | | `past_due` | A renewal failed and Lemon Squeezy is retrying | Yes | | `unpaid` | All retries failed; dunning rules decide what happens next | See below | | `cancelled` | Future payments cancelled, still valid until the period ends (grace period) | Yes | | `expired` | Ended, after cancellation or after dunning | No | Lemon Squeezy's guidance is to allow access for `on_trial`, `active`, `cancelled`, `past_due` and optionally `paused`. Its dunning page says that once the final retry fails, the subscription becomes `unpaid` and the customer loses access. ## What Lemon Squeezy does on failed payments Lemon Squeezy has built-in recovery, described on its [recovery and dunning page](https://docs.lemonsqueezy.com/help/online-store/recovery-dunning): - **Retries.** After a failed renewal, the subscription moves to `past_due` and Lemon Squeezy retries the payment four times over two weeks. A successful retry returns it to `active`. If all four fail, it becomes `unpaid`. - **Emails during retries.** Each failed attempt sends the customer an email asking them to update their billing information. - **Dunning after retries.** If you turn dunning on, Lemon Squeezy sends a series of dunning emails over a period you configure, and your dunning rules decide when the subscription becomes `expired`. You can edit the default emails, subject lines and schedule. If dunning is off, the status stays `unpaid`. - **Expiring card notices.** Lemon Squeezy can email customers before a saved payment method expires. - **PayPal is different.** For PayPal subscriptions, the [PayPal page](https://docs.lemonsqueezy.com/help/orders/paypal-subscriptions) says retries happen every 5 days, up to twice per billing cycle, and the subscription is suspended after two failed billing cycles. The same card update link is sent with each retry and dunning email. Lemon Squeezy notes that these update URLs expire after 24 hours, so if you send your own messages, fetch a fresh URL from the API each time rather than storing one. This is a solid native baseline. The parts you control are the dunning schedule and email copy; the retry timing itself is set by Lemon Squeezy. ## Pause and cancel through the API The [subscription management guide](https://docs.lemonsqueezy.com/guides/developer-guide/managing-subscriptions) covers both. **Pause.** Send `PATCH /v1/subscriptions/:id` with a `pause` object. Two modes exist: - `void`: for periods when you cannot provide the service; - `free`: the customer keeps using the product for free during the pause. Both stop payment collection. An optional `resumes_at` date unpauses automatically. Setting `pause` to null resumes collection on the original schedule. **Cancel.** `DELETE /v1/subscriptions/:id` cancels an active subscription. It moves to `cancelled` and stays valid until the next renewal date, shown in `ends_at`, then expires. During that grace period you can resume it by updating the subscription with `cancelled` set to false. ## The customer portal Lemon Squeezy's hosted [customer portal](https://docs.lemonsqueezy.com/help/online-store/customer-portal) lets customers switch between subscription products, pause and unpause, cancel and resume, and update billing details. You choose which features appear in the portal settings. Each subscription object also carries a `customer_portal` URL, a pre-signed link valid for 24 hours, which you can open from your app. If you let customers cancel straight from the portal, they skip any retention step you build. Decide on purpose: either send "Cancel" in your app to your own flow first, or rely on the portal's pause option as your only offer. ## Discounts Lemon Squeezy discounts have three durations ([discount object](https://docs.lemonsqueezy.com/api/discounts)): `once`, `repeating` for a set number of months, or `forever`. For yearly plans the repeating count is still in months, so two yearly payments means 24. The discount documentation describes codes redeemed at checkout; it does not describe applying a discount to a subscription that already exists. Check with Lemon Squeezy before promising a "50% off your next 3 months" offer to a current subscriber. Pause and a move to a cheaper product through the portal are the offers its docs clearly support. ## Webhooks to listen to From the [event types](https://docs.lemonsqueezy.com/help/webhooks/event-types) page: | Event | Use it for | |---|---| | `subscription_updated` | Catch-all for the latest subscription data; Lemon Squeezy recommends it | | `subscription_payment_failed` | A renewal failed; retries start | | `subscription_cancelled` | Cancelled by the customer or you; grace period begins | | `subscription_expired` | Access should end | | `subscription_paused` / `subscription_unpaused` | Pause started or ended | You can simulate events such as `subscription_cancelled` and `subscription_expired` in test mode. ## Adding a cancel flow 1. **Route "Cancel" in your app to your flow.** Show a short list of reasons plus "Other". 2. **Offer one thing that fits the reason.** "Not using it now": a pause in `void` mode with `resumes_at` set. "Too expensive": a cheaper product. "Missing a feature": a reply from a person. 3. **Keep "Cancel now" visible on every step.** One click should finish the cancellation without accepting an offer. 4. **Apply the outcome with the API.** Pause with `PATCH` and a `pause` object; cancel with `DELETE`, which keeps access until `ends_at`. 5. **Confirm the end date** from the subscription returned by the API. 6. **Offer "keep my subscription"** during the grace period, which sets `cancelled` to false. ## Win-back Once a subscription has `expired`, it is over. Keep the reason you collected, and contact the customer later with something that answers it. Use the `subscription_expired` event as the start of the timer, and send them to a new checkout. ## Doing this with NoChurn NoChurn reads your Lemon Squeezy subscriptions and webhooks. It adds a cancel flow with reasons, offers (such as a pause or a plan change) and a one-click cancel that is always visible, hosted or headless through the API, plus win-back emails at day 30, 60 and 90 based on the cancel reason and a churn score from 0 to 100. Lemon Squeezy stays the merchant of record: payments, payment recovery, refunds and disputes stay with it. Failed payments show up in NoChurn's customer timeline and churn score, and disputes appear read only. NoChurn is free under $300 MRR. See [NoChurn + Lemon Squeezy](/integrations/lemon-squeezy/). --- # Tracking churn with Lemon Squeezy webhooks Source: https://www.nochurn.sh/blog/lemon-squeezy-webhooks-churn-tracking/ If you sell subscriptions through Lemon Squeezy, every churn signal you need passes through its webhooks: cancellations, expiries, failed renewals, recoveries, pauses. The hard part is not receiving them. It is deciding which event means what, and recording them so that your churn numbers still add up six months later. This guide maps Lemon Squeezy's subscription events to churn concepts, shows how to store them, and lists the delivery details that break naive handlers. It sticks to Lemon Squeezy's own documentation: the [webhook event types](https://docs.lemonsqueezy.com/help/webhooks/event-types), the [webhook requests page](https://docs.lemonsqueezy.com/help/webhooks/webhook-requests), [signing requests](https://docs.lemonsqueezy.com/help/webhooks/signing-requests), the [sync with webhooks guide](https://docs.lemonsqueezy.com/guides/developer-guide/webhooks) and the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object) (all accessed November 2026). ## The subscription events Lemon Squeezy's [event types page](https://docs.lemonsqueezy.com/help/webhooks/event-types) lists these subscription events: | Event | What Lemon Squeezy says triggers it | Churn meaning | |---|---|---| | `subscription_created` | A new subscription | New (or returning) customer | | `subscription_updated` | Any change after the initial payment | Use to sync status | | `subscription_cancelled` | Cancelled by the customer or store owner; enters a grace period until the next billing date | Churn scheduled, not yet happened | | `subscription_resumed` | Resumed after being cancelled | Scheduled churn reversed | | `subscription_expired` | Ended after being cancelled, or once dunning completed for `past_due` subscriptions | Churn happened | | `subscription_paused` | Payment collection paused | Not churn; track separately | | `subscription_unpaused` | Payment collection resumed | End of pause | | `subscription_payment_success` | A successful payment | Revenue | | `subscription_payment_failed` | A renewal payment failed | Involuntary churn risk | | `subscription_payment_recovered` | A successful payment after a failed one | Risk resolved | | `subscription_payment_refunded` | A payment refunded | Revenue adjustment | Two of these deserve a closer look. ### Cancelled is not churned `subscription_cancelled` fires when the customer clicks cancel, but the subscription keeps running until `ends_at`. During that grace period it can be resumed, which sends `subscription_resumed`. If you count churn on `subscription_cancelled`, every resumed subscription becomes a false churn, and your churn date is off by up to a full billing period. Count churn on `subscription_expired`. Keep `subscription_cancelled` as a separate, leading metric: "cancellations scheduled this month". ### One event, two kinds of churn `subscription_expired` fires for two very different reasons: a customer who cancelled and reached `ends_at` (voluntary churn), and a subscription that went through dunning after failed payments without recovering (involuntary churn). The event name does not tell you which. To separate them, look at what came before. If your log has a `subscription_cancelled` for that subscription and no `subscription_resumed` after it, it is voluntary. If it has `subscription_payment_failed` events and no recovery, it is involuntary. You can also read the subscription's state when you receive the event: the [Subscription object reference](https://docs.lemonsqueezy.com/api/subscriptions/the-subscription-object) shows a `cancelled` boolean alongside `status`. Voluntary and involuntary churn need different fixes, so this split is the most useful thing your log can give you. ## What the requests look like Per the [webhook requests page](https://docs.lemonsqueezy.com/help/webhooks/webhook-requests): - Each request is a `POST` with a JSON:API body: the resource related to the event (a subscription for most subscription events, a subscription invoice for the payment events). - The `X-Event-Name` header carries the event name. - The `X-Signature` header carries the signature. - Your endpoint must return `200`. Any other status is retried up to three more times with exponential backoff (the docs give 5, 25 and 125 seconds as an example), after which the request is considered failed. The webhooks settings page in your dashboard logs recent deliveries with their payloads and lets you resend them. That is your safety net if your endpoint was down. ### Verify the signature [Signing requests](https://docs.lemonsqueezy.com/help/webhooks/signing-requests) explains the scheme: you set a signing secret when you create the webhook (6 to 40 characters), and Lemon Squeezy computes an HMAC-SHA256 hex digest of the request body with it. Recompute the digest on the **raw** body, not on re-serialized JSON, and compare with a timing-safe function. Reject anything that does not match. ### Payment events carry invoices The `subscription_payment_*` events carry a [subscription invoice object](https://docs.lemonsqueezy.com/api/subscription-invoices/the-subscription-invoice-object), not the subscription. It references the subscription, so store that ID and, if you need the status, fetch the subscription. ## Building a churn log step by step The goal is an append-only table of what happened to each subscription, from which every churn metric can be recomputed. 1. **Create one endpoint for all subscription events.** Subscribe it to the events in the table above. Lemon Squeezy's [sync guide](https://docs.lemonsqueezy.com/guides/developer-guide/webhooks) notes that `subscription_updated` covers every change, so you can subscribe to it alone if you only want state. For churn tracking, the specific events are easier to reason about, so take both. 2. **Verify, then store the raw payload.** Write the event name, the subscription ID, the customer ID, the timestamp and the raw JSON before doing anything else. 3. **Deduplicate.** Retries and manual resends mean the same event can arrive twice. The docs we used do not describe a unique event ID in the request, so build your own key from the event name, the resource ID and the resource's `updated_at`, and ignore repeats. 4. **Respond fast.** Return `200` as soon as the event is stored, and process it in a background job. A slow handler that times out triggers retries. 5. **Derive, do not overwrite.** Keep the log immutable. Compute "current status" and churn counts from it, so a bug in your logic can be fixed by replaying the log. 6. **Reconcile occasionally.** Once a week, list subscriptions through the API and compare their statuses to what your log says. Any mismatch means a missed event. ## The metrics you can compute With that log, these are straightforward: - **Customer churn rate for a month:** subscriptions that expired during the month, divided by subscriptions active at the start of the month. - **Voluntary vs involuntary share:** expiries split by the rule above. - **Cancellations scheduled:** `subscription_cancelled` events in the month, a leading indicator for next month's churn. - **Grace-period saves:** cancelled subscriptions followed by `subscription_resumed`. - **Payment recovery rate:** subscriptions with a `subscription_payment_recovered` divided by subscriptions with a `subscription_payment_failed` in the same period. - **Paused share:** subscriptions currently `paused`. Report them separately; they are neither active payers nor churned. Define each metric once, in writing, and keep the definition stable. A churn rate is only useful compared to itself over time. ## Testing before you trust it Lemon Squeezy's test mode can [simulate webhook events](https://docs.lemonsqueezy.com/help/webhooks/simulate-webhook-events) for subscriptions. Run each lifecycle through it: create, cancel, resume, cancel again and let it expire; a failed payment that recovers; one that does not. Check that your log and your metrics match what you expect at every step. ## Doing this with NoChurn Lemon Squeezy stays the source of truth for subscriptions and payments; NoChurn does not change them. NoChurn subscribes to your Lemon Squeezy webhooks, stores and deduplicates the events, and separates voluntary from involuntary churn for you. On top of that it adds a churn score from 0 to 100 per customer, custom data you send by API, and the cancel flow answers that explain why people leave. Disputes, which Lemon Squeezy handles as the merchant of record, are shown read only. See [NoChurn + Lemon Squeezy](/integrations/lemon-squeezy/). --- # How to win back canceled customers on Lemon Squeezy Source: https://www.nochurn.sh/blog/lemon-squeezy-win-back/ On Lemon Squeezy, a cancellation is not the end of the relationship. For a while it is not even the end of the subscription. Lemon Squeezy keeps cancelled subscriptions alive until the end of the paid period, and during that window one API call brings them back. After it, you can still invite customers to return with a discount. This guide covers both windows: what Lemon Squeezy lets you do while a cancelled subscription is still in its grace period, and how to win customers back once it has expired. It sticks to Lemon Squeezy's own documentation: the [Subscriptions help page](https://docs.lemonsqueezy.com/help/products/subscriptions), the [Cancel a Subscription](https://docs.lemonsqueezy.com/api/subscriptions/cancel-subscription) and [Update a Subscription](https://docs.lemonsqueezy.com/api/subscriptions/update-subscription) API references, the [webhook event types](https://docs.lemonsqueezy.com/help/webhooks/event-types), the [Create a Discount reference](https://docs.lemonsqueezy.com/api/discounts/create-discount) and the [email Subscribers page](https://docs.lemonsqueezy.com/help/email/subscribers) (all accessed November 2026). ## What happens when a customer cancels A cancellation on Lemon Squeezy can come from the customer (usually through the [Customer Portal](https://docs.lemonsqueezy.com/help/online-store/customer-portal)), from you in the dashboard, or from your app through the API with a `DELETE` on the subscription ([Cancel a Subscription](https://docs.lemonsqueezy.com/api/subscriptions/cancel-subscription)). Either way, the result is the same: 1. The subscription's `status` becomes `cancelled` and `cancelled` is `true`. 2. It enters a **grace period**. The `ends_at` attribute holds the date it will expire, which is the next renewal date. 3. The customer keeps access until `ends_at`, because they paid for that period. The [Subscriptions help page](https://docs.lemonsqueezy.com/help/products/subscriptions) says customers should keep access in every status except `expired`. 4. At `ends_at`, the status becomes `expired` and the subscription can no longer be resumed. Lemon Squeezy sends `subscription_cancelled` when the cancellation happens, and `subscription_expired` when the subscription actually ends. The [event types page](https://docs.lemonsqueezy.com/help/webhooks/event-types) is explicit that a cancelled subscription can be resumed during the grace period, and that `subscription_resumed` fires when that happens. That gives you two distinct win-back windows. | Window | Status | How to bring them back | Event to start from | |---|---|---|---| | Grace period | `cancelled`, before `ends_at` | Resume the same subscription | `subscription_cancelled` | | After expiry | `expired` | New checkout, optionally with a discount | `subscription_expired` | ## Window 1: the grace period This is the easiest save you will ever make. The customer still has access, their card is still on file, and nothing needs to be re-entered. ### Resuming by API The [Update a Subscription reference](https://docs.lemonsqueezy.com/api/subscriptions/update-subscription) says a subscription can be resumed before its `ends_at` date by sending a `PATCH` with `cancelled` set to `false`. The status goes back to active and billing continues on the existing schedule. ```json { "data": { "type": "subscriptions", "id": "123", "attributes": { "cancelled": false } } } ``` Customers can also resume from the Customer Portal themselves, if you leave that option on. ### What to do in this window 1. **Show it in the app.** A cancelled customer who logs in should see "Your plan ends on March 1" and a "Keep my plan" button that calls the resume endpoint. No email is faster. 2. **Send one reminder before `ends_at`.** A few days before the end date, a short email: what they lose, the date, and the same "Keep my plan" link pointing to your app. 3. **Do not discount yet.** The customer already decided once; a discount here can train customers to cancel for a coupon. Save offers for the cancel moment itself, or for after expiry. ## Window 2: after expiry Once a subscription is `expired`, it is over. Lemon Squeezy's docs we used describe no way to reactivate an expired subscription, so bringing the customer back means a new checkout. That is where discounts come in. ### Create a discount for returning customers Lemon Squeezy's [Create a Discount reference](https://docs.lemonsqueezy.com/api/discounts/create-discount) documents three `duration` values for subscription discounts: - `once`: applies to the first payment only (the default). - `repeating`: applies for a number of months set by `duration_in_months` (defaults to 1). For yearly plans, the docs say to multiply years by 12. - `forever`: applies to every payment. For win-back, `repeating` is usually the right choice: "50% off your first 3 months back" has a clear end and lets the customer re-evaluate at full price. The docs also advise against repeating discounts on daily or weekly subscriptions. Give the code a name that makes sense in an email, and limit it to the products you are inviting people back to. Then link to your checkout with the code already applied, so the customer does not have to type it. ### Who can you email? Lemon Squeezy has its own email marketing feature. Per the [Subscribers page](https://docs.lemonsqueezy.com/help/email/subscribers), subscribers can be added manually, through a signup form, or automatically when a customer buys a product. Its [anti-spam policy](https://www.lemonsqueezy.com/anti-spam-policy) requires permission before sending marketing emails, forbids pre-checked opt-in boxes, and requires a one-click unsubscribe link in every newsletter. Whichever tool you use, check your consent basis before sending a win-back campaign. A former customer who bought from you is not automatically someone who agreed to marketing, and the rules differ by country. A plain, relevant message to people who opted in is always the safe default. ## A win-back sequence that respects the customer The content of a win-back email matters more than the discount. A sequence keyed to the reason the customer gave works better than a generic "We miss you". ### Collect the reason first Lemon Squeezy's portal handles the cancellation, but the docs we used do not describe a built-in cancellation reason survey. If you want reasons, ask in your own app before sending customers to cancel, or with a one-question email right after `subscription_cancelled`. Store the answer with the customer. ### Match the message to the reason | Reason | Win-back angle | |---|---| | Too expensive | A time-limited discount, or a cheaper plan | | Missing a feature | Tell them when it ships, no discount needed | | Not using it enough | A short reminder of what changed, maybe a smaller plan | | Switched to another tool | One honest message about what you do differently, then stop | | Temporary need | A friendly check-in at the time they said they would be back | ### Space it out Three touches is plenty: roughly a month after expiry, two months, and three months. Stop at the first reply or the first unsubscribe. If a customer comes back through a new checkout, Lemon Squeezy sends `subscription_created`; use it to stop the sequence. ### Measure it on your data Track how many expired customers start a new subscription within 90 days, by cancel reason and by whether they received an offer. That is the only win-back rate that matters for your product. ## Common mistakes - **Revoking access at cancellation.** The customer paid for the period. Lemon Squeezy's lifecycle keeps access until `expired`; your app should too. - **Treating `subscription_cancelled` as churn.** It is a scheduled end, not an end. Count churn on `subscription_expired`. - **Leading with the biggest discount.** Start with relevance, add an offer only where the reason calls for one. - **Emailing people who did not opt in.** It hurts deliverability and may break the law where they live. ## Doing this with NoChurn Resuming subscriptions and running checkouts stay with Lemon Squeezy. NoChurn reads your Lemon Squeezy webhooks, records the cancel reason from its cancel flow (where customers can always cancel in one click), and sends win-back emails at day 30, 60 and 90 based on that reason. Each customer also gets a churn score from 0 to 100, so you can see who is worth a personal message. NoChurn is free under $300 MRR. See [NoChurn + Lemon Squeezy](/integrations/lemon-squeezy/). --- # How to add a cancel flow to Maxio Source: https://www.nochurn.sh/blog/maxio-cancel-flow/ A cancel flow sits between the "Cancel" button and the cancellation: it asks why, makes one offer that fits the reason, and cancels cleanly if the customer still wants to go. Maxio Advanced Billing (formerly Chargify) already has several of the pieces: delayed cancellation, churn reason codes, holds and scheduled product changes. This guide explains how they work and how to put them together into a flow. It sticks to Maxio's own documentation: [cancelling subscriptions](https://docs.maxio.com/hc/en-us/articles/24252133729165-Cancelling-Subscriptions), [schedule a subscription cancellation](https://docs.maxio.com/billing/subscriptions/management/state-management/schedule-a-subscription-cancellation), [manage subscriptions in the Billing Portal](https://docs.maxio.com/hc/en-us/articles/24252490287501-Subscription-Management), [configuring Billing Portal features](https://docs.maxio.com/hc/en-us/articles/24252420731405-Configuring-Billing-Portal-Features), [churn reason codes](https://docs.maxio.com/hc/en-us/articles/24286647554701-Churn-Reason-Codes), [on hold and resume scenarios](https://docs.maxio.com/billing/subscriptions/management/subscription-states/understand-on-hold-and-resume-scenarios), [apply coupons to subscriptions](https://docs.maxio.com/billing/catalog/coupons/apply-coupons-to-subscriptions), the [update subscription](https://developers.maxio.com/http/advanced-billing-api/api-endpoints/subscriptions/update-subscription) and [initiate delayed cancellation](https://developers.maxio.com/http/advanced-billing-api/api-endpoints/subscription-status/initiate-delayed-cancellation) API references, and [webhook payload examples](https://docs.maxio.com/hc/en-us/articles/24266167968909-Payload-Examples) (all accessed November 2026). Some of Maxio's API examples still use older Chargify URLs; check the endpoints for your site. ## How cancellation works in Maxio Maxio offers three timings ([cancelling subscriptions](https://docs.maxio.com/hc/en-us/articles/24252133729165-Cancelling-Subscriptions)): | Timing | What happens | |---|---| | Immediately | The subscription is canceled now | | At the end of the period | It keeps running through the paid period in a **Pending Cancellation** state, then cancels | | On a scheduled date | It cancels on a future date you or the customer pick (needs the scheduling feature) | In every case, Maxio does not refund or prorate automatically. For a customer who chose to leave, end of period is the fair default: they keep what they paid for. A pending cancellation can be removed: Maxio's guide to [building your own Billing Portal](https://docs.maxio.com/getting-started/quick-start-guides/subscription-management/build-your-own-billing-portal-with-the-advanced-billing-api) lists a separate endpoint for that. Through the API, a delayed cancellation accepts a reason code and the `cancel_at_end_of_period` flag; scheduling a date requires the Schedule Subscription Cancellation feature to be enabled on your site. Some subscriptions cannot be scheduled to cancel. Per Maxio, **prepaid** subscriptions always cancel immediately, and subscriptions in states such as Past Due, Expired or Paused cannot be scheduled ([schedule a cancellation](https://docs.maxio.com/billing/subscriptions/management/state-management/schedule-a-subscription-cancellation)). Your flow has to handle those cases. ### Churn reason codes Maxio has built-in [churn reason codes](https://docs.maxio.com/hc/en-us/articles/24286647554701-Churn-Reason-Codes). You create, edit, sort and delete them in your site settings, and they appear when someone cancels from the subscription summary. Once your site has codes configured, a reason must be selected before a cancellation is confirmed. When codes are in use, Maxio's churn analytics show the reason for each churn event. Use them even if you build your own flow: send the reason code with the cancellation, so Maxio's reports and yours agree. ## The Billing Portal Maxio's hosted Billing Portal lets customers cancel from Plan Details, choosing between immediate and end-of-period cancellation ([Billing Portal subscriptions](https://docs.maxio.com/hc/en-us/articles/24252490287501-Subscription-Management)). You control it with separate toggles in the [Billing Portal features](https://docs.maxio.com/hc/en-us/articles/24252420731405-Configuring-Billing-Portal-Features): - **Allow Immediate Cancellations** - **Allow Delayed Cancellations (at end of period)** - **Allow Scheduling Cancellations**, so customers can pick a future date - **Display Churn Reason Codes**, so customers pick a reason when they cancel The portal asks for confirmation, and Maxio notes there is no undo after that step. What the portal does not do is make an offer: it records a reason and cancels. If you want a retention step, put it in your app before the customer reaches the portal, or turn off portal cancellation and handle it yourself. If you keep portal cancellation on, enabling only delayed cancellation is a sensible choice. ## The offers Maxio supports ### Hold (pause) Maxio calls a pause a **hold** ([on hold and resume scenarios](https://docs.maxio.com/billing/subscriptions/management/subscription-states/understand-on-hold-and-resume-scenarios)). While on hold, renewals do not happen. A hold can carry a resume date, and the subscription then resumes on its own (the subscription object has an `automatically_resume_at` field). Only an Active subscription can be put on hold. One detail matters for cancel flows: a subscription that was set to cancel at the end of the period does not cancel while on hold; it cancels after it resumes. Maxio's guide lists hold and resume endpoints, but its own pages show them in two path forms (with and without `/subscriptions/:id`), so check the current API reference before you build on them. ### Coupon Maxio coupons can be added to an existing subscription ([apply coupons](https://docs.maxio.com/billing/catalog/coupons/apply-coupons-to-subscriptions)). Two rules from the docs: - The coupon's duration is counted from the subscription's **next renewal**, not from signup. - A coupon only applies to plans in the **same product family**. The pages we found describe adding a coupon in the admin interface; check Maxio's API reference for the call you will use from your app. ### Product change For "too expensive", a cheaper plan is often better than a discount. Maxio supports a **delayed product change** ([update subscription](https://developers.maxio.com/http/advanced-billing-api/api-endpoints/subscriptions/update-subscription)): set `product_handle` to the new product and `product_change_delayed` to true, and the change happens at the next renewal with no proration. Sending an empty next product cancels a scheduled change. Coupons on the subscription carry over only if they are restricted to the new plan or unrestricted. ## Building the flow 1. **Send "Cancel" in your app to your flow.** Decide what the Billing Portal allows, so customers do not reach two different cancellation experiences. 2. **Check what is possible for this subscription.** Prepaid subscriptions cancel immediately; Past Due and Paused ones cannot be scheduled. A hold needs an Active subscription. 3. **Ask why**, using the same list as your Maxio churn reason codes. 4. **Show one offer that fits.** "Too expensive": a delayed product change or a coupon. "Not using it right now": a hold with a resume date. "Missing a feature": a reply from a person. 5. **Keep "Cancel now" visible on every step.** One click finishes the cancellation, without accepting any offer. 6. **Apply the result.** Delayed cancellation with the reason code and `cancel_at_end_of_period`; or the hold, coupon or product change. 7. **Confirm the date** from the subscription Maxio returns, and offer to undo a pending cancellation until it takes effect. ## Webhooks to listen to From Maxio's [payload examples](https://docs.maxio.com/hc/en-us/articles/24266167968909-Payload-Examples) and [webhook events](https://docs.maxio.com/hc/en-us/articles/39414912245261-Webhooks-Events): - **`subscription_state_change`** carries `state` and `previous_state`: use it to see a subscription go to canceled, on hold or back to active. - **`pending_cancellation_change`** has a sample payload with `cancel_at_end_of_period` and `delayed_cancel_at`. Maxio's pages we found do not say exactly when it fires, so test it in your site. Maxio says webhooks are asynchronous and advises checking that `previous_state` matches what you have before updating your records, and fetching the subscription from the API when in doubt. ## Doing this with NoChurn NoChurn connects to Maxio with an API key, imports customers and subscriptions and follows Maxio's webhooks. It adds a cancel flow with reasons, offers that become a coupon or a product change on the Maxio subscription, and a one-click cancel that is always visible, hosted or headless through the API. It also sends win-back emails at day 30, 60 and 90 based on the cancel reason and computes a churn score from 0 to 100. Invoicing, taxes, your products and the charge stay in Maxio and your gateway. NoChurn is free under $300 MRR. See [NoChurn + Maxio](/integrations/maxio/). --- # How to measure churn in Maxio Source: https://www.nochurn.sh/blog/maxio-churn-metrics/ Maxio has several reports that show churn, and they do not all measure the same thing. One counts customers, another counts revenue, and the churn rate in the momentum reports includes downgrades as well as cancellations. Before you put a churn number in a board deck, it helps to know which report it came from and how that report defines it. This guide maps Maxio's churn reports and definitions, then gives a practical way to read them. It sticks to Maxio's own documentation: [choose the right report for your metric](https://docs.maxio.com/insights/report-management/reporting-in-general/choose-the-right-report-for-your-metric), [understanding Maxio report types](https://docs.maxio.com/insights/report-management/reporting-in-general/understanding-maxio-report-types), [get started with the Advanced Subscription Momentum Report](https://docs.maxio.com/insights/analytics-reports/advanced-subscription-momentum-report/advanced-subscription-momentum-report-overview), [troubleshoot unexpected Advanced Subscription Momentum Report results](https://docs.maxio.com/insights/analytics-reports/advanced-subscription-momentum-report/troubleshoot-unexpected-advanced-subscription-momentum-report-results), the [Maxio Core glossary](https://docs.maxio.com/getting-started/maxio-platform-basics/important-concepts/glossary-of-key-maxio-core-terms), [configure reporting](https://docs.maxio.com/getting-started/quick-start-guides/financereporting/configure-reporting) and [churn reason codes](https://docs.maxio.com/hc/en-us/articles/24286647554701-Churn-Reason-Codes) (all accessed November 2026). Maxio has two billing products, Advanced Billing (formerly Chargify) and Maxio Core (formerly SaaSOptics); some definitions below come from Core's glossary, and we say so. ## Two kinds of churn Maxio's [report guide](https://docs.maxio.com/insights/report-management/reporting-in-general/choose-the-right-report-for-your-metric) separates two ways of counting: - **Logo churn**: how many customers you lost. - **Revenue churn**: how much MRR or ARR you lost. They answer different questions. Logo churn tells you whether customers stay; revenue churn tells you whether money stays. A company losing many small customers and keeping its large ones can have high logo churn and low revenue churn. Maxio's glossary also notes that churn is usually split into a gross and a net rate; in common usage, net churn offsets lost revenue with expansion revenue and gross churn does not. For the general formulas, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ## Where churn shows up in Maxio | Report | What it shows | Good for | |---|---|---| | **MRR report** | MRR, filterable by movement: New Business, Expansion, Contraction, Churn, Reactivation | Revenue churn in dollars, month by month | | **Churn Analytics** (Insights) | Churn trends; Maxio suggests reading it with the MRR report's churn movements | Spotting changes in the trend; churn by reason | | **Subscription Momentum Report** | Momentum, retention and churn calculations, customer counts, customer lifetime value | A broad overview in one place | | **Advanced Subscription Momentum Report** | Renewal growth, churn velocity, cohort momentum, revenue transition, with rows you can expand to see the customers behind each figure | Churn rate questions; Maxio recommends it for those | Maxio's [reporting setup guide](https://docs.maxio.com/getting-started/quick-start-guides/financereporting/configure-reporting) also describes Business Intelligence dashboards that you enable separately (Business Intelligence › Enable Maxio Advanced Billing BI). They are not on by default. ## How Maxio calculates churn rate Maxio's [troubleshooting page for the Advanced Subscription Momentum Report](https://docs.maxio.com/insights/analytics-reports/advanced-subscription-momentum-report/troubleshoot-unexpected-advanced-subscription-momentum-report-results) gives the formula: - **Churn rate** = (Contraction + Lost) / Opening - **Renewal rate** = 1 − churn rate - When Opening is 0, churn rate returns 0% (and renewal rate 100%) rather than an undefined value. Two things follow from this. **Contraction counts as churn.** A customer who downgrades from $500 to $300 adds $200 to the numerator, just as a lost customer does. This is a gross revenue churn rate, not a count of cancellations. If someone asks "what share of customers cancelled?", this number is not the answer. **Expansion is not subtracted.** The formula does not net off upgrades, so it is a gross figure. If you need net revenue churn, compute it from the movements yourself. The report's Customer Count section measures Opening, New, Expansion, Contraction, Lost and Ending customer counts. That is where to get logo churn: Lost customers divided by Opening customers for the period. ### What the movement names mean Maxio's [Core glossary](https://docs.maxio.com/getting-started/maxio-platform-basics/important-concepts/glossary-of-key-maxio-core-terms) defines: - **New**: customers with transactions starting in this period and none before it. - **Expansion**: the net increase for customers whose total amount (MRR, ARR) grew compared with the previous period. - **Contraction**: the net decrease for customers whose total amount shrank. The pages we found do not define the Reactivation movement in the MRR report. If returning customers matter for your numbers, check how Maxio classifies them on your site before comparing periods. ## Why churn happened: reason codes Numbers say how much; [churn reason codes](https://docs.maxio.com/hc/en-us/articles/24286647554701-Churn-Reason-Codes) say why. You define the codes in your site settings; once configured, a reason must be selected to confirm a cancellation, and the Billing Portal can show them to customers. Maxio's churn analytics then show the reason code for each churn event. Without codes, your churn analysis stops at the size of the problem. Keep the list short and stable. Changing codes every quarter makes trends impossible to read. Something like "Too expensive", "Missing feature", "Not using it", "Switched tool", "Business closed", "Other" covers most cases. ## A monthly churn review in Maxio 1. **Pick the period and stick to it.** Monthly for monthly plans; look at annual renewals separately. 2. **Logo churn** from the Customer Count section: Lost ÷ Opening. 3. **Gross revenue churn** from the Advanced Subscription Momentum Report: (Contraction + Lost) ÷ Opening. Write down that it includes downgrades. 4. **Net revenue churn**: take the same movements and subtract Expansion, then divide by Opening. 5. **Split voluntary and involuntary.** Subscriptions canceled at the end of dunning are a payment problem, not a product one. If your reports do not separate them, use the state history (past due, then canceled) to tag them. 6. **Break down by reason code** in Churn Analytics. 7. **Expand the rows.** The Advanced Subscription Momentum Report lets you see the customers behind each number. Read a few of them; it keeps the numbers honest. 8. **Check for data issues** with Maxio's troubleshooting page when a figure looks wrong, for example an Opening of zero producing a 0% churn rate. ## Annual plans need their own view If you sell both monthly and annual plans, a monthly churn rate mixes two very different populations: monthly customers can leave any month, annual customers only at renewal. A month with many annual renewals can look like a spike that is really a calendar effect. Report annual renewals separately, as a renewal rate for the contracts that came up in the period, and keep the monthly churn rate for monthly plans. ## What the reports cannot tell you Maxio's reports describe what happened in billing. They do not tell you which active customers are about to leave, and they do not connect churn to signals outside billing, such as product usage, support tickets or signup source. For that, you need to join billing data with your own. ## Doing this with NoChurn NoChurn reads your Maxio customers, subscriptions and events, and adds a churn score from 0 to 100 for each customer, computed at signup and at every change from the payment method, signup source and custom data you send by API. Its churn drivers analysis ranks the attributes most correlated with churn (correlation, not causation), and its cancel flow records reasons in the customer's own words. Your billing reports and revenue figures stay in Maxio. NoChurn is free under $300 MRR. See [NoChurn + Maxio](/integrations/maxio/). --- # How to reduce involuntary churn in Maxio Source: https://www.nochurn.sh/blog/maxio-dunning/ Involuntary churn is the part of churn nobody chose: a renewal fails, nobody fixes the payment method, and the subscription ends. Maxio Advanced Billing (formerly Chargify) gives you most of the tools to prevent it natively: a configurable dunning schedule, per-step retries and emails, a final action, a Billing Portal where customers update their card, and webhooks for every step. This guide explains how those pieces behave and how to set them up well. All Maxio behaviour described here comes from Maxio's own documentation: [Understanding how dunning works](https://docs.maxio.com/billing/subscriptions/dunning/overview/understanding-how-dunning-works), [Configure credit card dunning](https://docs.maxio.com/billing/subscriptions/dunning/set-up-schedules/configure-credit-card-dunning), [Configure ACH dunning](https://docs.maxio.com/billing/subscriptions/dunning/set-up-schedules/configure-ach-dunning), [Configure direct debit dunning](https://docs.maxio.com/billing/subscriptions/dunning/set-up-schedules/configure-direct-debit-dunning), [Update subscription payment method](https://docs.maxio.com/billing/subscriptions/management/subscription-actions/update-subscription-payment-method), [Dunning email parameters](https://docs.maxio.com/billing/subscriptions/dunning/dunning-email-parameters-reference) and [Webhook events](https://docs.maxio.com/hc/en-us/articles/39414912245261-Webhooks-Events) (all accessed November 2026). ## What happens when a renewal fails in Maxio When a subscription's period ends, Maxio attempts to charge the payment method on file. If the processor declines, the subscription moves to **Past Due** and Maxio starts following your dunning schedule. From there, three outcomes are possible: 1. A retry succeeds, or the customer updates their payment method and pays, and the subscription returns to **Active**. 2. The schedule runs out and the **final action** applies: the subscription is either **Canceled** (it stops accruing charges) or marked **Unpaid** (it keeps accruing charges). 3. You intervene manually, for example by recording a payment. An Unpaid subscription can return to Active: Maxio's docs describe using Retry/Reactivate to collect payment, or Reset to $0 to waive the balance. A few cases behave differently, per the [dunning overview](https://docs.maxio.com/billing/subscriptions/dunning/overview/understanding-how-dunning-works): - **Prepaid subscriptions** are not marked past due. They stay active while the balance lasts, then are suspended. - **Term subscriptions** whose term ends during dunning expire rather than staying past due, and are not canceled later if dunning runs out. - **Manual remittance** (invoice-billed) subscriptions get reminder emails, but dunning does not retry open invoices. - **High-risk or fraud declines** disable the payment profile instead of continuing retries. ## The dunning schedule Dunning lives under **Config, then Retries & Dunning**. Maxio organises it into email settings, the retry and dunning schedule, and the final step. Dunning emails are configured here, separately from your other site emails. ### Limits and rules by payment method | Payment method | Rule from Maxio's docs | |---|---| | Credit card | Up to 365 days and/or 30 steps per schedule | | ACH | 2 retry attempts plus 1 final action, following ACH network rules | | Direct debit | At least 5 days between retries; the final action cannot retry | | Manual remittance | Reminder emails only, no retries | You can set site-wide strategies per payment method, and product or product family strategies alongside them, so an annual enterprise plan does not have to share a schedule with a monthly self-serve plan. ### Steps: retry, email, or both Each step in the schedule has a day number and two switches: - **Retry Payment**: attempt the charge on that day. You can switch it off to send an email without retrying, except on the Day 1 step, which always retries. - **Send Email**: preset templates start with emails switched off, so you need to turn on each email you want and edit its subject and body. ### How Maxio tracks the current step Maxio calculates a subscription's current step from how long it has been past due and your current schedule, rather than storing the step. The practical consequence, stated in the docs: editing the schedule can change which step a past due subscription appears to be on. Make schedule changes deliberately, and expect subscriptions already in dunning to follow the new schedule. Also note: if a subscription reaches its regular renewal date while in dunning and there is no dunning step that day, the renewal still runs. If it fails, the subscription stays in dunning and continues with the next step. ## Getting the customer to update their payment method Most recovered revenue from hard declines and expired cards comes from the customer entering new details. Maxio offers several ways to get them there, according to its docs on [updating the payment method](https://docs.maxio.com/billing/subscriptions/management/subscription-actions/update-subscription-payment-method) and the [dunning email parameters](https://docs.maxio.com/billing/subscriptions/dunning/dunning-email-parameters-reference): - **In dunning emails:** an `update_url` variable gives the URL the customer can use to update their payment method. If you use the Billing Portal, templates can link to the portal's management page instead. - **From the subscription page:** the Payment Details tab has an action to email the customer a link to their self-service page, and you can also copy the self-service page URL to send it yourself. - **In the Billing Portal:** customers log in, select the subscription, choose to update the payment method, pick a saved method or add a new one, and save. The portal also has a direct URL pattern for the update-payment-method page of a given subscription. Two limits worth knowing: - While a payment is still pending (for example an unsettled direct debit), the payment method cannot be changed, including from the self-service page. - Dunning emails are only sent while a subscription is past due; they are not processed for expired or canceled subscriptions. Anything you want to send after the final action needs another channel. ## Webhooks to wire into your app Maxio's [webhook events reference](https://docs.maxio.com/hc/en-us/articles/39414912245261-Webhooks-Events) lists the events you need to mirror dunning state in your product: | Event | What it tells you | What to do | |---|---|---| | `payment_failure` | A payment attempt failed, including retries | Show an in-app banner, log the attempt | | `payment_success` | A payment succeeded, including retries | Clear the banner | | `dunning_step_reached` | The subscription reached a dunning step (payload includes current and next step) | Time your own reminders or in-app notices | | `subscription_state_change` | The subscription's state changed | Re-read the state, then grant or remove access | Maxio notes that a payment that brings a past due account current generates `payment_success` and `subscription_state_change`, but not `renewal_success`. If your app only listens to renewal events, it will miss recoveries. Maxio attempts each webhook delivery up to six times ([webhooks guide](https://docs.maxio.com/hc/en-us/articles/24286723085197-Webhooks)), so make your handlers idempotent. ## A setup plan 1. **Match the schedule to the billing period.** For monthly plans, finish dunning before the next renewal so you are not stacking unpaid periods. Annual plans can afford a longer window. 2. **Front-load retries and emails.** Retry on day 1, then every few days in the first two weeks, when the customer still remembers using the product. 3. **Turn on the emails.** They start disabled. Write a short first email with the `update_url` link, two or three reminders, and a final notice that names the date access ends. 4. **Separate strategies by product** when audiences differ. Enterprise customers often need a longer window and a human touch, not more automated emails. 5. **Choose the final action on purpose.** Cancel stops charges accruing; Unpaid keeps them accruing, which makes sense only if you plan to collect the balance. 6. **Respect ACH and direct debit rules.** Do not design a card-style schedule for bank payments; Maxio enforces the limits anyway. 7. **Mirror state with webhooks,** keyed on `subscription_state_change`, and show a banner inside your product while the subscription is past due. 8. **Review canceled-for-nonpayment subscriptions monthly** and look for patterns: one product, one gateway, one card type. ## Doing this with NoChurn Maxio's dunning stays in place: retries, invoicing, taxes and the charge itself remain in Maxio and your gateway. NoChurn connects with a Maxio API key, imports customers and subscriptions, follows Maxio webhooks and adds AI-written recovery emails that you review before they go out, with a link to update the payment profile. On top of dunning, it adds cancel flows with reasons, offers (a coupon or a product change on the Maxio subscription) and a one-click cancel that is always visible, win-back emails at day 30, 60 and 90 based on the cancel reason, and a churn score from 0 to 100. Disputes come from the gateway behind Maxio; with Stripe or Braintree, NoChurn gathers evidence and drafts a reply for you to review. See [NoChurn + Maxio](/integrations/maxio/). --- # How to handle expiring cards in Maxio Source: https://www.nochurn.sh/blog/maxio-expiring-cards/ An expiring card is the most predictable failed payment there is: you know the month it will stop working before it happens. Maxio Advanced Billing (formerly Chargify) gives you three tools for it: automatic card expiration emails, an `expiring_card` webhook, and account updater support on some gateways. This guide explains what each one does, where they leave gaps, and how to combine them so renewals do not fail for a reason you could see coming. It sticks to Maxio's own documentation: [configure email settings](https://docs.maxio.com/configuration/advanced-billing/settings/configure-email-settings), [email templates](https://docs.maxio.com/hc/en-us/articles/24266086168461-Email-Templates), [webhook events](https://docs.maxio.com/hc/en-us/articles/39414912245261-Webhooks-Events), [payload examples](https://docs.maxio.com/hc/en-us/articles/24266167968909-Payload-Examples), [compare gateway features](https://docs.maxio.com/hc/en-us/articles/24176142616333-Gateway-Features), [managing payment methods](https://docs.maxio.com/hc/en-us/articles/24251599929613-Managing-Payment-Methods), [update a customer's payment information](https://docs.maxio.com/payments/maxio-payments/payment-processing/payment-methods-integrations/update-a-customers-payment-information) and the [Advanced Billing glossary](https://docs.maxio.com/getting-started/maxio-platform-basics/advanced-billing-overview-and-resources/glossary-of-key-advanced-billing-terms) (all accessed November 2026). Where Maxio's pages disagree, we say so. For what happens once a renewal has already failed, see [how to reduce involuntary churn in Maxio](/blog/maxio-dunning/). ## Step 1: let the account updater do what it can Card networks run account updater services: when a bank reissues a card, the new number or expiry date can reach the merchant without the customer doing anything. In Maxio, support [depends on your gateway](https://docs.maxio.com/hc/en-us/articles/24176142616333-Gateway-Features): | Gateway | Account updater in Advanced Billing | |---|---| | Stripe, BlueSnap, Cybersource, Forte (Beta), Maxio Payments | Fully supported: Maxio receives the updates and keeps stored card data current | | Other gateways | The gateway's updater generally still works through its token, so charges can succeed, but the new card details may not appear in Advanced Billing | Some gateways need setup. For BlueSnap, Maxio's setup guide asks you to configure BlueSnap webhooks and tick "Send Account Updater". For Forte, the updater must be enabled in the Forte account first. On Stripe, Maxio's docs tie the automatic updater to the Stripe Connect integration. Two limits from Maxio's docs: - **Not every issuer takes part.** An updater only works when the card issuer participates, so some cards will expire with no update. - **An updater can disable a profile.** When an updater cannot find an account, it may remove the record, leaving the subscriber's payment profile disabled. Maxio's [payment methods page](https://docs.maxio.com/hc/en-us/articles/24251599929613-Managing-Payment-Methods) says that, at the time of writing, this had only happened to Authorize.Net merchants using the updater. The second point matters for the first: if your gateway updates the card silently and Maxio does not show it, Maxio may still believe the card is about to expire and email the customer about it. Know which case you are in before you write the email. ## Step 2: card expiration emails Maxio can send **Card Expiration Emails** to customers whose card on file is about to expire ([email templates](https://docs.maxio.com/hc/en-us/articles/24266086168461-Email-Templates)). The template can include the number of days until expiration and an update link, `{{update_url}}`, which is the self-service URL for the subscription, so the customer enters the new card themselves and you never handle card data. ### When they are sent: two versions in Maxio's docs Maxio's pages give two schedules: - The current [email settings page](https://docs.maxio.com/configuration/advanced-billing/settings/configure-email-settings) says the emails go out three times **during the month the card expires**: on the 1st, on the 15th, and one week before the end of the month (so the third date moves with the month's length). - The [glossary](https://docs.maxio.com/getting-started/maxio-platform-basics/advanced-billing-overview-and-resources/glossary-of-key-advanced-billing-terms) and the email templates page mention the 1st, 15th and **23rd**, and the glossary refers to the month **before** the card expires. The email settings page is the more specific and appears to be the newer one, but check a real send on your site before you build anything that depends on the exact dates. ### Make the email useful The default template is a starting point. A good expiring card email: 1. Says which card (brand and last four digits) and which subscription. 2. Gives the date the next renewal will be charged, if it falls after the expiry. 3. Has one button to the update link, working on a phone, with no password to remember. 4. Comes from your brand and a real reply address. ## Step 3: the expiring_card webhook Maxio also sends an [`expiring_card` webhook](https://docs.maxio.com/hc/en-us/articles/39414912245261-Webhooks-Events). Per its webhook events page, it is periodic: sent on the 1st, on the 15th and 7 days before the end of the month, and it identifies all cards expiring **in the current month**. The [payload](https://docs.maxio.com/hc/en-us/articles/24266167968909-Payload-Examples) carries the subscription object, with the customer, product and card details. Note what that means: the webhook arrives in the month of expiry, not weeks before. For a monthly plan billed early in the month, that is fine. For a customer whose renewal is on the 2nd and whose card expires at the end of that month, it is also fine. But for an annual plan renewing next spring, an "expiring this month" alert today is not the problem; the card that will be on file at renewal is. Use the webhook as a trigger, and decide what to do with your own logic: - **Renewal before expiry**: no action needed now; the next renewal will succeed. - **Renewal after expiry, monthly plan**: ask for a new card now. - **Annual plan**: look at the card's expiry date against the renewal date yourself, ahead of time, rather than waiting for the webhook. ## Step 4: other ways to get a new card When the email does not work, Maxio offers manual and bulk options ([update a customer's payment information](https://docs.maxio.com/payments/maxio-payments/payment-processing/payment-methods-integrations/update-a-customers-payment-information)): - **From the subscription.** On the Payment Details tab, "Email Customer to Request Payment Update" sends the customer a link to their self-service page. Maxio recommends this over entering new card details for the customer. - **In bulk.** A prewritten "Request Payment Method Update" bulk email sends a secure update link to a group of subscribers. - **In the Billing Portal.** Customers add a card under Payment, or use Update Payment Method on a specific subscription. - **Maxio Core.** If you use Maxio Core rather than Advanced Billing, the docs describe copying a link from the customer's e-Bill billing profile page and sending it. Add a message inside your own product too: a banner for the account owner when their card expires this month reaches people who ignore email. ## A checklist - [ ] You know whether your gateway's account updater is fully supported in Advanced Billing. - [ ] Gateway-side updater settings are enabled where needed. - [ ] Card Expiration Emails are on, with your branding and a working update link. - [ ] You checked on a real send which schedule Maxio uses on your site. - [ ] `expiring_card` is handled, with logic for monthly vs annual plans. - [ ] Annual plans are checked for expiry against the renewal date well in advance. - [ ] An in-app banner shows when the card on file is about to expire. - [ ] Dunning is set up for the cards you could not catch in time. ## Doing this with NoChurn NoChurn reads Maxio subscriptions and each payment profile's type and expiry date, and uses them in the customer's 0–100 churn score. When a renewal does fail, NoChurn sends recovery emails written by AI and reviewed by you, alongside your Maxio dunning, with a link to update the payment profile. Card data, the charge and the account updater stay with Maxio and your gateway. NoChurn is free under $300 MRR, with every feature on every plan. See [NoChurn + Maxio](/integrations/maxio/). --- # How to win back churned customers on Maxio Source: https://www.nochurn.sh/blog/maxio-win-back/ A customer who cancelled already knows your product, has been through onboarding and, in Maxio, still has an account and payment history. Bringing them back is usually cheaper than finding someone new, and Maxio Advanced Billing has a feature built for it: reactivation, with options for coupons, trials and balances. This guide explains how reactivation works, how to choose who to contact and with what, and how to measure the result. It sticks to Maxio's own documentation: [understand reactivation and resume scenarios](https://docs.maxio.com/billing/subscriptions/management/state-management/understand-reactivation-and-resume-scenarios), the [reactivate subscription](https://developers.maxio.com/http/advanced-billing-api/api-endpoints/subscription-status/reactivate-subscription) and [reactivate subscription request](https://developers.maxio.com/http/advanced-billing-api/models/structures/reactivate-subscription-request) API references, [churn reason codes](https://docs.maxio.com/hc/en-us/articles/24286647554701-Churn-Reason-Codes), [apply coupons to subscriptions](https://docs.maxio.com/billing/catalog/coupons/apply-coupons-to-subscriptions), [choose the right report for your metric](https://docs.maxio.com/insights/report-management/reporting-in-general/choose-the-right-report-for-your-metric) and [webhook payload examples](https://docs.maxio.com/hc/en-us/articles/24266167968909-Payload-Examples) (all accessed November 2026). Maxio also sells Maxio Core (formerly SaaSOptics); this guide is about Advanced Billing. ## Reactivation, not a new subscription In Maxio Advanced Billing, a canceled subscription can be **reactivated**: the same subscription comes back to life, with its customer, history and payment profile. You do it from the subscription in the admin interface or with `PUT /subscriptions/:id/reactivate.json` ([reactivate subscription](https://developers.maxio.com/http/advanced-billing-api/api-endpoints/subscription-status/reactivate-subscription)). For a win-back campaign this is the main tool, since the customer does not have to start over. ### Resume vs new billing period Maxio separates two outcomes ([reactivation and resume scenarios](https://docs.maxio.com/billing/subscriptions/management/state-management/understand-reactivation-and-resume-scenarios)): - **Resume the existing period.** Possible only if you reactivate within the billing period in which the subscription was canceled. Whether the customer is charged depends on whether the subscription had a balance when it was canceled, for example after failed dunning. - **Start a new billing period.** The usual case for win-back, since you contact people after their period has ended. The customer is charged for the new period. The API's `resume` field controls this: when true, Maxio tries to resume and falls back to a new period if it cannot; when false or omitted, it always starts a new period. Note that Maxio also uses "resume" for taking a subscription off **hold**, which is a different action. ### The options that matter for win-back The [reactivate request](https://developers.maxio.com/http/advanced-billing-api/models/structures/reactivate-subscription-request) accepts: | Field | What it does | Win-back use | |---|---|---| | `coupon_code` | Applies a coupon during reactivation | The discount in your offer | | `include_trial` | If true, includes the product's trial if one is available; if false, ignores it | A free restart period, if your product has a trial | | `preserve_balance` | If true, keeps the existing balance instead of clearing it before adding reactivation charges | Decide whether an old unpaid balance follows the customer | | `resume` | Resume the old period or start a new one | See above | The balance question needs a decision before you launch. A customer who left after failed payments may have an outstanding balance. Maxio's docs describe a case where a $100 plan is reactivated at $0 by adding a balance adjustment of -$100 and choosing "Do not reset the existing balance"; if the adjustment is smaller than the plan price, the customer is charged the difference right away. Agree with your finance team on what returning customers owe before you email them. ### Coupons Coupons in Maxio only apply to plans in the **same product family** ([apply coupons](https://docs.maxio.com/billing/catalog/coupons/apply-coupons-to-subscriptions)). If you plan to bring someone back on a different plan, check that the coupon belongs to that plan's family. ## Who to contact, and with what ### Use churn reason codes Maxio's [churn reason codes](https://docs.maxio.com/hc/en-us/articles/24286647554701-Churn-Reason-Codes) are defined in your site settings, required on cancellation once configured, and can be shown to customers in the Billing Portal. When codes are in use, Maxio's churn analytics show the reason for each churn event. That is the field to segment your win-back on. ### Separate voluntary and involuntary churn A subscription canceled at the end of dunning is not the same as one the customer cancelled. Look at the state history: Maxio's `subscription_state_change` webhook carries `state` and `previous_state`, so a move from past due to canceled tells you payment was the problem ([payload examples](https://docs.maxio.com/hc/en-us/articles/24266167968909-Payload-Examples)). Those customers need a simple restart with a new card, not a discount. ### Match the offer to the reason | Reason | Win-back message | |---|---| | Price | A coupon on reactivation, or a cheaper product | | Missing feature | Tell them when it ships; no discount needed | | Not using it | What changed since they left, or a smaller plan | | Moved to another tool | One honest message about the difference | | Payment failed | A restart link with a card update; no offer | ## A win-back sequence, step by step 1. **Record the reason** at cancellation with a churn reason code, plus any free-text answer you collect. 2. **Listen to `subscription_state_change`** and start the sequence when a subscription becomes canceled. Note the previous state. 3. **Wait before the first message.** The day after someone cancels is rarely the right time; space messages over weeks. 4. **Write each message for the reason.** Keep each one short with one link. 5. **Reactivate the same subscription** when the customer accepts, with `coupon_code` if there is an offer, and a clear choice on `preserve_balance` and `include_trial`. 6. **Stop the sequence** as soon as the subscription is active again, and for anyone who unsubscribes. ## What to avoid - **Discounting everyone.** A customer who left because a feature was missing does not need 30% off; they need the feature. Discounts sent to everyone teach customers to cancel to get a better price. - **Messaging people who asked you to stop.** Respect unsubscribes and any request not to be contacted. - **Surprise charges on return.** If the reactivation will charge an old balance, say so before the customer clicks. - **A new account for a returning customer.** Reactivate the existing subscription where you can, so history and reporting stay in one place. ## Measure it Maxio's [report guide](https://docs.maxio.com/insights/report-management/reporting-in-general/choose-the-right-report-for-your-metric) lists an MRR report that can be filtered by movement type, including **Reactivation** and Churn, and a Churn Analytics report under Insights. Use the Reactivation movement to see revenue that came back, and compare it with what your campaign sent. Also check whether reactivated customers stay: a win-back that lasts one month and ends in another cancellation is not much of a win. We cover the reports in more detail in [how to measure churn in Maxio](/blog/maxio-churn-metrics/). ## Doing this with NoChurn NoChurn follows Maxio's webhooks and sends win-back emails at day 30, 60 and 90 after a customer leaves, written from the reason they gave, with a link to come back. Before that, its cancel flow offers a coupon or a product change on the Maxio subscription, with a one-click cancel always visible, hosted or headless through the API, and a 0–100 churn score flags customers at risk. Reactivation, invoicing and the charge stay in Maxio and your gateway. NoChurn is free under $300 MRR, with every feature on every plan. See [NoChurn + Maxio](/integrations/maxio/). --- # How to add a cancel flow to Mollie subscriptions Source: https://www.nochurn.sh/blog/mollie-cancel-flow/ Mollie runs the recurring charges, but the place where a customer decides to leave is your own app. The [Subscriptions API](https://docs.mollie.com/reference/create-subscription) gives you the tools to cancel a subscription, change its amount or interval, or move its start date. What it does not give you is a cancel screen. That part is yours to build, and it is where a good cancel flow pays off. This guide shows what Mollie's API lets you do when a customer wants to cancel, and how to turn that into a short, honest cancel flow. It sticks to Mollie's documentation: [Cancel subscription](https://docs.mollie.com/reference/cancel-subscription), [Update subscription](https://docs.mollie.com/reference/update-subscription), [Get subscription](https://docs.mollie.com/reference/get-subscription), [Revoke mandate](https://docs.mollie.com/reference/revoke-mandate) and the [Recurring payments guide](https://docs.mollie.com/docs/recurring-payments) (all accessed November 2026). We also checked field descriptions against Mollie's official [Node.js API client](https://github.com/mollie/mollie-api-node). ## What Mollie gives you A Mollie subscription belongs to a customer and charges a fixed amount at an interval, on a mandate. The fields that matter for a cancel flow: | Field | Meaning | |---|---| | `status` | `pending`, `active`, `canceled`, `suspended` or `completed`. It depends on whether the customer's mandate is pending, valid or invalid. | | `amount` | The constant amount charged on each payment. | | `interval` | Time between charges, such as `1 month` or `14 days`. | | `nextPaymentDate` | The next scheduled charge; absent when the subscription has ended. | | `times`, `timesRemaining` | For subscriptions with a fixed number of charges. | | `canceledAt` | When it was cancelled. | | `metadata` | Your own data, forwarded to each payment the subscription creates. | And the calls: - **Cancel**: `DELETE /v2/customers/:customerId/subscriptions/:id`. Mollie's reference says a subscription can be cancelled at any time this way. - **Update**: `PATCH` on the same resource. The updatable fields are `amount`, `description`, `interval`, `startDate`, `times`, `mandateId`, `metadata` and `webhookUrl`. A cancelled subscription cannot be updated. - **Revoke mandate**: `DELETE` on the customer's mandate. You can no longer charge that account or card with it, and all connected subscriptions are cancelled. Note what is not in the list: Mollie's Subscriptions API has no pause endpoint. Any "pause" offer has to be built from the calls above. ## Cancel the subscription, not the mandate When a customer cancels, cancel the **subscription**. Revoking the **mandate** also stops every other subscription on it and means the customer has to go through checkout again if they ever come back. Revoke a mandate only when the customer asks you to stop all charges on that account, or when you have a reason to distrust it. Also decide what "cancel" means for access. Mollie stops future charges when you cancel; it does not know what the customer has already paid for. Most subscription businesses keep access until the end of the paid period. Store that date yourself, from the last paid payment and the interval. ## Designing the flow A cancel flow has three jobs: find out why the customer is leaving, offer something that fits that reason, and cancel cleanly if they still want to go. Keep it to a few screens. ### 1. Ask for the reason One question, one tap. A short list works better than a free-text field: - Too expensive - Not using it enough - Missing a feature - Switching to another product - Technical problems - Temporary need, will come back - Other (with an optional text box) Store the answer in your database and, if useful, in the subscription's `metadata`, so it travels with the customer's record. ### 2. Make one offer that matches Each offer must map to something Mollie can actually do: | Reason | Offer | How on Mollie | |---|---|---| | Too expensive | A lower price for a few months | `PATCH` the `amount`; schedule a second update to restore it | | Not using it enough | A cheaper plan or a longer interval | `PATCH` the `amount` and, if needed, the `interval` | | Temporary need | Skip a period | Move the next charge with `startDate`, or cancel and create a new subscription later (test this first, see below) | | Missing feature, switching, technical | No discount; ask for detail, route to a person | Nothing to change on Mollie | Mollie applies a changed `amount` to all future charges. There is no built-in "discount for 3 months", so a temporary discount means remembering to update the amount back, or creating the subscription with `times` and a follow-up one. Tell the customer exactly what they will pay and from when. For a "skip a period" offer, Mollie's documentation lists `startDate` among the fields you can update, but it does not describe in detail how this moves the next charge on an active subscription. Try it in test mode and check `nextPaymentDate` before offering it to customers. The alternative, cancelling now and creating a new subscription on the same mandate later, is predictable but depends on the mandate still being valid at that point. ### 3. Cancel, always one click away The cancel button must be visible on every step, not hidden behind the offer. A customer who says no to the offer should be cancelled with one more click, with a confirmation that states: - the subscription is cancelled, - the date access ends, - that no further payments will be taken. Consumer rules in several countries push in this direction (see [click-to-cancel rules](/blog/click-to-cancel-rules/)), and so does simple self-interest on Mollie: a customer who cannot find how to cancel a SEPA Direct Debit subscription can ask their bank to reverse the debit. Mollie's [help center](https://help.mollie.com/hc/en-us/articles/115000796469-What-is-a-SEPA-Direct-Debit-chargeback) says you cannot dispute a SEPA reversal requested within 8 weeks. A reversal costs you more than a clean cancellation. ## Wiring it to the API 1. **Load the subscription** with Get subscription when the customer opens the flow, so you show the right amount, interval and next charge date. 2. **On "accept offer"**, call Update subscription with the new values, then fetch it again and show the result. Record the offer and the reason. 3. **On "cancel"**, call Cancel subscription. Use an idempotency key so a double click does not cause problems, and show the confirmation from your stored end date. 4. **Reconcile.** Mollie can also end a subscription on its own, for example after failed payments. Check subscription status regularly (or on each payment webhook) so your app and Mollie agree. 5. **Keep a log** of each step: reason shown, offer shown, offer accepted or refused, cancellation time. You will want it for support questions and for any bank reversal later. ## What to measure - Share of customers who start the flow and accept an offer. - Share of accepted offers still paying three months later. - Reasons by plan, by signup source and by tenure. - Reversals after cancellation, which should be close to zero if the flow is clear. Be careful with the first number. An offer that delays a cancellation by one month is not a save. ## Doing this with NoChurn Mollie keeps the subscription, the mandate and the charges. NoChurn adds the cancel flow itself: reasons, an offer that fits the reason, and a one-click cancel that is always visible, either hosted by NoChurn or built in your own interface with the headless API. For Mollie, accepted offers change the subscription amount and a cancellation ends the subscription, through Mollie's API. Reasons feed win-back emails at day 30, 60 and 90 and the churn score. See [NoChurn + Mollie](/integrations/mollie/). --- # Chargebacks on Mollie: what happens and what to do Source: https://www.nochurn.sh/blog/mollie-chargebacks/ A chargeback on Mollie can mean two quite different things. For SEPA Direct Debit, it is a reversal the customer has a right to, which you cannot argue with in the first 8 weeks. For cards and some other methods, it is a dispute you may be able to answer with evidence. The right response depends on which one you are looking at, and on a subscription business it also affects every future charge. This guide explains what Mollie documents about each case, how to read chargebacks in the API, and what to do with the customer and the subscription afterwards. It sticks to Mollie's documentation: the [Chargebacks API](https://docs.mollie.com/reference/chargebacks-api) and [Get chargeback](https://docs.mollie.com/reference/get-chargeback) references, and the help center articles [What is a SEPA Direct Debit chargeback?](https://help.mollie.com/hc/en-us/articles/115000796469-What-is-a-SEPA-Direct-Debit-chargeback), [What is an Unauthorised Direct Debit Report?](https://help.mollie.com/hc/en-us/articles/115000806165-What-is-an-Unauthorised-Direct-Debit-Report), [How do I resolve a card chargeback?](https://help.mollie.com/hc/en-us/articles/213317329-How-do-I-resolve-a-card-chargeback), [How do I respond to a dispute?](https://help.mollie.com/hc/en-us/articles/35793503532050-How-do-I-respond-to-a-dispute) and [What happens to a mandate after a reversal?](https://help.mollie.com/hc/en-us/articles/115004339309-What-happens-to-a-mandate-after-a-reversal-) (all accessed November 2026). Field descriptions were also checked against Mollie's official [Node.js API client](https://github.com/mollie/mollie-api-node). ## SEPA Direct Debit: a right, not a dispute SEPA gives customers strong refund rights, and Mollie's help center describes two windows: | When | What the customer can do | Can you dispute? | |---|---|---| | Up to 8 weeks after the debit | Ask their bank to reverse the payment | No. Mollie says that once a chargeback is requested, you cannot dispute it. | | 8 weeks to 13 months | File an Unauthorised Direct Debit Report | The bank checks whether the mandate was valid. If the debit was unauthorised, the customer gets the money back and you pay the cost of the report, which Mollie's article puts at €65 excluding VAT. | Two consequences for subscriptions: 1. **The mandate is gone.** Mollie's help center says it revokes the mandate after a reversal. Further charges on it will not work, and Mollie's [recurring payments guide](https://docs.mollie.com/docs/recurring-payments) lists "return of funds requested by end customer" (`MD06`) among the reasons that lead to the subscription being cancelled after repeated occurrences. 2. **Keep proof of the mandate.** For the 13-month window, what matters is whether the customer authorised the debit. Keep the first payment, the date, the IBAN holder name and anything they accepted at signup. ## Cards: a dispute with a deadline Card chargebacks go through the card schemes, and you can sometimes contest them. Mollie's help center describes two ways of responding, and they are not the same: - The older article, [How do I resolve a card chargeback?](https://help.mollie.com/hc/en-us/articles/213317329-How-do-I-resolve-a-card-chargeback), says Mollie forwards the chargeback to you by email, gives you several days to object with documentation (for example the invoice, proof of delivery, your terms and your communication with the customer), and that objections go to Mollie by email. It says the bank's decision can take up to 45 days, and that if the objection is rejected the payment is reversed and a chargeback fee is deducted. - The newer article, [How do I respond to a dispute?](https://help.mollie.com/hc/en-us/articles/35793503532050-How-do-I-respond-to-a-dispute), describes a Dispute Portal in the Mollie dashboard, marked as beta. Each dispute shows a response due date; until then you can defend or accept it, and if the date passes the dispute is recorded as lost. Which one applies to your account depends on whether you have the Dispute Portal. Check your dashboard before you rely on email. In both cases, the deadline is short and set by Mollie and the scheme, so the evidence needs to be ready before the chargeback arrives. Mollie's [dispute fees article](https://help.mollie.com/hc/en-us/articles/35795203499154-What-fees-do-I-pay-for-disputes) explains when a fee is charged; the amounts depend on the method and your contract. Other methods have their own rules. Mollie documents separate dispute processes for methods such as Klarna and Wero in its help center. ## Reading chargebacks in the API The [Chargebacks API](https://docs.mollie.com/reference/chargebacks-api) has two ways in: - `GET /v2/chargebacks` lists chargebacks across all your payments, newest first. - `GET /v2/payments/:paymentId/chargebacks` and `.../chargebacks/:id` list or fetch those of one payment. A chargeback object carries: | Field | Meaning | |---|---| | `amount` | The amount charged back | | `settlementAmount` | What will be deducted from your balance, in your settlement currency (negative); amounts Mollie does not settle, such as PayPal chargebacks, are not reflected | | `createdAt` | When the chargeback was issued | | `reason.code`, `reason.description` | The bank's reason; only for SEPA Direct Debit chargebacks | | `reversedAt` | When the chargeback was reversed, if it was | | `paymentId` | The payment it belongs to | | `settlementId` | The settlement it was deducted in, once settled | A chargeback changes the payment, so your payment webhook is the place to notice it: fetch the payment, check whether it has chargebacks, and fetch them. Because webhooks can be missed, also run a daily job on `GET /v2/chargebacks` and compare it with what you have stored. `reversedAt` matters too: a chargeback can be undone, and your records should follow. ## What to do, step by step 1. **Record it on the customer.** Amount, reason code, date and the subscription it belongs to. 2. **Stop the next charge from failing.** For a SEPA reversal, the mandate is revoked, so the subscription will not collect again. Decide now whether to end access, pause it, or ask for payment by another method. 3. **Contact the customer, without accusing them.** Many reversals come from customers who did not recognise the debit or could not find how to cancel. Ask, and give them a clear way to cancel or to pay again. 4. **For card disputes, answer before the deadline.** Send what proves the customer subscribed and used the service: signup date and terms accepted, renewal reminders sent, usage after the charge, and any support conversation. Do not send more than is relevant. 5. **Look for patterns.** Several reversals around renewal dates point to a reminder or description problem. Several on new accounts may point to fraud. ### Prevent the next one - **Use a description customers recognise.** Mollie includes the subscription description in each payment's description. - **Remind before renewals**, especially annual ones. - **Make cancelling easy.** A customer who can cancel in two clicks has no reason to go to their bank. - **Refund when it is the right call.** If a customer asks for a refund you would grant anyway, a refund is cleaner than a reversal. ## Doing this with NoChurn Mollie handles chargebacks and decides with the banks; NoChurn does not submit evidence to Mollie. NoChurn reads your Mollie chargebacks and shows them read only on the customer's timeline, where they also count in the churn score from 0 to 100. What NoChurn adds on Mollie is upstream of a chargeback: a cancel flow with a one-click cancel always visible, recovery emails with a link to pay again, and win-back emails at day 30, 60 and 90. See [NoChurn + Mollie](/integrations/mollie/). --- # How to handle failed recurring payments with Mollie Source: https://www.nochurn.sh/blog/mollie-failed-recurring-payments/ Mollie makes recurring payments simple to start: one first payment creates a mandate, and subscriptions or on-demand charges run on that mandate. What happens when one of those charges fails is less obvious. Does Mollie retry? When does it cancel the subscription? What does your webhook actually receive? And how do you get a customer back onto a working payment method? This guide answers those questions from Mollie's own documentation: [Recurring payments](https://docs.mollie.com/docs/recurring-payments), [Webhooks](https://docs.mollie.com/reference/webhooks), [Next-gen webhooks](https://docs.mollie.com/reference/webhooks-new), [Status reasons](https://docs.mollie.com/reference/status-reasons), the [Chargebacks API](https://docs.mollie.com/reference/chargebacks-api), [Update subscription](https://docs.mollie.com/reference/update-subscription) and Mollie's help center articles on [failed SEPA Direct Debit payments](https://help.mollie.com/hc/en-us/articles/115000309865-Why-did-my-SEPA-direct-debit-payment-fail) and [mandates after a reversal](https://help.mollie.com/hc/en-us/articles/115004339309-What-happens-to-a-mandate-after-a-reversal-) (all accessed November 2026). ## How Mollie recurring payments work Mollie's model has three pieces, described in the [recurring payments guide](https://docs.mollie.com/docs/recurring-payments): 1. **A first payment.** You create a payment for a customer with `sequenceType` set to `first`. The customer completes it through the normal checkout. 2. **A mandate.** Once the first payment succeeds, Mollie stores a mandate for that customer and payment method. A mandate does not cap the amount or the number of charges. 3. **Recurring charges.** Either you create payments yourself with `sequenceType` set to `recurring` (this requires a mandate with status `valid`), or you create a **subscription** and Mollie charges on its interval. For subscriptions, the customer needs a mandate in status `pending` or `valid`. The customer only goes through checkout once. That is the strength of the model, and also why recovery is different from card-on-file platforms: when a mandate stops working, there is no "update card" form on the mandate itself. The customer has to make a new first payment. ## What happens when a subscription payment fails Mollie does retry. According to the [recurring payments guide](https://docs.mollie.com/docs/recurring-payments): - If a subscription payment fails, Mollie may attempt it again **up to 5 times, once a day**, depending on the failure reason. - The retry behaviour may differ per payment method and failure reason. - If a retry succeeds, the next charge date is updated based on the latest successful payment and your interval. - Once all retries are exhausted, **the subscription is cancelled**. Some failure reasons skip that pattern. The same page lists reasons that cancel the subscription immediately and others that cancel it after repeated occurrences: | Behaviour | Example SEPA reasons listed by Mollie | |---|---| | Cancel immediately | Invalid IBAN (AC01), closed account (AC04), deceased debtor (MD07) | | Cancel after the same issue occurs repeatedly | No mandate (MD01), return requested by the customer (MD06), refusal by the debtor (MS02), reason not specified | If the subscription has a fixed mandate set (its `mandateId` field), cancelling it for these reasons also revokes the mandate. One caution: an older Mollie [help article](https://help.mollie.com/hc/en-us/articles/115000309865-Why-did-my-SEPA-direct-debit-payment-fail) gives a different threshold for SEPA subscriptions (cancellation after 2 failures, not applicable to insufficient funds). The developer documentation is the more recent reference, but test the behaviour for your own payment methods rather than assuming a number. For insufficient funds (AM04), Mollie's help center suggests trying the direct debit again or contacting the customer. Two practical consequences: - **You need to know when Mollie cancelled a subscription,** because your app has to react. Cancelled subscriptions cannot be updated through the API, so recovery means creating a new subscription. - **Retries alone will not fix a closed account or a revoked mandate.** Those customers need to pay again through checkout. ## Webhooks that carry only an ID Mollie's classic webhooks are intentionally minimal. As the [webhooks reference](https://docs.mollie.com/reference/webhooks) explains, Mollie calls your `webhookUrl` with a POST parameter `id`, the ID of the object that changed (for a payment, `id=tr_...`), and nothing else. Your handler must fetch the object from the API and read its current status. Things to build around this: 1. **Always fetch.** Do not infer what happened from the fact that a call arrived. Read the payment, check its status, and for subscription payments check the subscription ID and the subscription's own status. 2. **Return HTTP 200 quickly.** Mollie treats anything else, or a response slower than 15 seconds, as a failure and retries with increasing intervals, up to 10 attempts over about 26 hours. You cannot trigger a webhook call again manually from Mollie. 3. **Make processing idempotent.** The same payment can be reported more than once, and the status you read may have moved on since the call was sent. 4. **Reconcile on a schedule.** Since you cannot replay calls, a periodic job that lists recent payments and subscriptions catches anything a failed endpoint missed. Mollie also offers [next-gen webhooks](https://docs.mollie.com/reference/webhooks-new), which are signed with an `X-Mollie-Signature` header computed with your webhook secret. If you use them, verify the signature before acting. Either way, treat your own API read as the source of truth. ## Chargebacks Customers can reverse payments, and Mollie exposes them through the [Chargebacks API](https://docs.mollie.com/reference/chargebacks-api): - `GET /v2/chargebacks` lists chargebacks across all your payments, newest first, paginated. - The payment-level endpoints list or fetch the chargebacks for one payment. For SEPA Direct Debit, a customer can reverse a payment within 8 weeks, and according to Mollie's [help center](https://help.mollie.com/hc/en-us/articles/115004339309-What-happens-to-a-mandate-after-a-reversal-), Mollie revokes the mandate after a reversal. Any further charges need a new mandate, so a chargeback on a recurring payment is also a payment method problem, not just a lost amount. For card disputes, Mollie's [card chargeback article](https://help.mollie.com/hc/en-us/articles/213317329-How-do-I-resolve-a-card-chargeback) explains that, depending on the case, you may be able to respond with documentation within a limited number of days. When a chargeback arrives on a subscription, decide explicitly: pause access, contact the customer, or end the subscription. Do not let the next scheduled charge discover that the mandate is gone. ## Asking the customer to pay again When retries have run out, the mandate is revoked or the account is closed, recovery means getting the customer back through checkout. The flow that follows Mollie's documented model: 1. **Detect the failure** from your webhook handler after fetching the payment, and note the failure reason from the [status reasons](https://docs.mollie.com/reference/status-reasons) reference where available. 2. **Email the customer the same day.** Explain that the payment did not go through, without quoting bank codes, and include one link. 3. **Point the link at a new first payment.** Create a payment for the same customer with `sequenceType` `first` for the outstanding amount. Paying it settles what is owed and creates a new mandate in one step. Mollie's [payment links](https://docs.mollie.com/reference/create-payment-link) are another way to collect the amount, but check whether the method you use creates a mandate for future charges. 4. **Restart the subscription** on the new mandate once the payment is paid. If Mollie had already cancelled the old subscription, create a new one with a start date that fits the period the customer just paid for. 5. **Send reminders** if the link is not used: after a few days, then a final notice with the date access ends. 6. **Offer another payment method** in the reminder. A customer whose bank account was closed may prefer a card, and the first payment lets them choose. ## A checklist - Your webhook handler fetches every object and returns 200 fast. - You store the subscription status and react when Mollie cancels it. - Hard reasons (closed account, invalid IBAN, revoked mandate) go straight to a "pay again" email, without waiting. - Insufficient funds get time: Mollie's own retries, plus a reminder. - Chargebacks are checked and mark the mandate as unusable in your app. - A scheduled job reconciles payments and subscriptions in case webhook calls were missed. ## Doing this with NoChurn Payment processing, mandates, Mollie's retries and the card and bank details all stay with Mollie. NoChurn connects to your Mollie account, imports customers, mandates and subscriptions, and, because Mollie webhooks only carry an ID, reads the payment again before acting. It adds AI-written recovery emails that you review before they go out, with a link to pay again and set up a new payment method. Chargebacks are shown read only on the customer's timeline and count in the churn score from 0 to 100. NoChurn also adds cancel flows with reasons, offers and a one-click cancel that is always visible, and win-back emails at day 30, 60 and 90 based on the cancel reason. See [NoChurn + Mollie](/integrations/mollie/). --- # Why SEPA Direct Debit payments fail on Mollie Source: https://www.nochurn.sh/blog/mollie-sepa-direct-debit-failures/ A SEPA Direct Debit on Mollie does not fail the way a card does. There is no instant decline: the bank answers later, with a short code from the SEPA rulebook such as `AM04` or `MD06`. That code is the most useful thing you get. It tells you whether trying again can work, whether the customer has to act, and whether they have in fact asked for their money back. This guide goes through the reason codes you will see on Mollie, where to find them in the API, how Mollie's subscriptions react to each one, and what to do next. It sticks to Mollie's documentation: the [Get payment reference](https://docs.mollie.com/reference/get-payment) (SEPA Direct Debit details), the [Recurring payments guide](https://docs.mollie.com/docs/recurring-payments), the [SEPA Direct Debit guide](https://docs.mollie.com/docs/sepa-direct-debit) and Mollie's help center articles [Why did my SEPA direct debit payment fail?](https://help.mollie.com/hc/en-us/articles/115000309865-Why-did-my-SEPA-direct-debit-payment-fail) and [What is a SEPA Direct Debit chargeback?](https://help.mollie.com/hc/en-us/articles/115000796469-What-is-a-SEPA-Direct-Debit-chargeback) (all accessed November 2026). Where we used Mollie's official API client to confirm a field, we say so. For a broader view of retries, webhooks and asking the customer to pay again, see [how to handle failed recurring payments with Mollie](/blog/mollie-failed-recurring-payments/). ## Where the reason lives A failed SEPA Direct Debit payment has the status `failed`. The reason is in the payment's `details` object. Mollie's [Get payment reference](https://docs.mollie.com/reference/get-payment) documents these SEPA Direct Debit fields, and Mollie's official [Node.js client](https://github.com/mollie/mollie-api-node) carries the same descriptions: | Field | What it holds | |---|---| | `details.bankReasonCode` | Only when the payment failed: the official reason code. Mollie points to the European Payments Council for the full description of each code. | | `details.bankReason` | Only when the payment failed: a text description of the reason. | | `details.dueDate` | The estimated date the amount is debited from the customer's account. | | `details.signatureDate` | The date the customer signed the mandate, when verified. | | `details.consumerName`, `consumerAccount`, `consumerBic` | The account holder, IBAN and BIC. | Mollie's classic webhooks only send the payment ID. Your handler fetches the payment, sees `failed`, and reads `bankReasonCode`. Store the code with the payment: you will need it to decide what to do, and later to see which failures you recover. A reversal (a customer asking their bank for their money back) is different. It shows up as a **chargeback** on a payment that had succeeded, with its own `reason.code` and `reason.description`, which Mollie fills only for SEPA Direct Debit chargebacks. We cover that in [chargebacks on Mollie](/blog/mollie-chargebacks/). ## The codes, and what each one means for you Mollie's [help center](https://help.mollie.com/hc/en-us/articles/115000309865-Why-did-my-SEPA-direct-debit-payment-fail) and [recurring payments guide](https://docs.mollie.com/docs/recurring-payments) list the codes that matter most. "Subscription behaviour" is what the recurring payments guide says Mollie does with a subscription when a charge fails for that reason. | Code | Meaning | Subscription behaviour | What to do | |---|---|---|---| | `AM04` | Insufficient funds (banks sometimes send `MS03` for this) | May be retried | Give it time; send a reminder; suggest another method if it keeps failing | | `MS03` | Reason not specified | Cancelled after repeated failures | Treat like insufficient funds at first; contact the customer if it repeats | | `AC01` | Incorrect account number (invalid IBAN) | Cancelled immediately | Ask for new payment details | | `AC04` | Account closed | Cancelled immediately | Ask for new payment details | | `MD07` | Debtor deceased | Cancelled immediately | Stop collecting; handle with care | | `MD01` | No mandate | Cancelled after repeated failures | Check the mandate; ask the customer to set one up again | | `MS02` | Refusal by the debtor | Cancelled after repeated failures | Contact the customer: they may want to stop | | `MD06` | Return requested by the customer | Cancelled after repeated occurrences (Mollie's guide says after 3 times) | A reversal: see below | Three groups come out of this table: 1. **Money problems** (`AM04`, sometimes `MS03`). The account is fine; the money was not there that day. These are the payments you can recover by waiting and reminding. 2. **Account problems** (`AC01`, `AC04`, `MD07`). Retrying the same IBAN cannot work. Mollie cancels the subscription straight away, so you need a new payment method and a new subscription. 3. **Customer decisions** (`MS02`, `MD06`, often `MD01`). The customer, or their bank on their behalf, refused or reclaimed the debit. Retrying without talking to them is the fastest way to a second reversal. ### Two sources, two thresholds Mollie's documentation is not fully consistent on retries. The [recurring payments guide](https://docs.mollie.com/docs/recurring-payments) says a failed subscription payment may be retried up to 5 times, once a day, depending on the payment method and failure reason, and that the subscription is cancelled once retries are exhausted. An older [help center article](https://help.mollie.com/hc/en-us/articles/115000309865-Why-did-my-SEPA-direct-debit-payment-fail) describes SEPA subscriptions being cancelled after 2 failures, not counting insufficient funds. We read the developer guide as the more recent reference, but test with your own account rather than relying on either number, and watch the subscription's status after each failure. ## Why reversals deserve their own handling `MD06` is a customer asking for their money back. Mollie's [help center](https://help.mollie.com/hc/en-us/articles/115000796469-What-is-a-SEPA-Direct-Debit-chargeback) says the customer has up to 8 weeks to do this, and that once they request it, you cannot dispute it. Between 8 weeks and 13 months, a customer can still file an [Unauthorised Direct Debit Report](https://help.mollie.com/hc/en-us/articles/115000806165-What-is-an-Unauthorised-Direct-Debit-Report); the bank then checks whether the mandate was valid. So a reversal is rarely a payment problem. Common causes are a forgotten subscription, a charge the customer did not recognise, or a customer who tried to cancel and could not find how. Each one calls for a message, not a retry. ## A playbook by code ### Insufficient funds (`AM04`) 1. Let Mollie's own retries run if the subscription is still active. 2. Send one short email on the first failure: the amount, the plan, and the fact that the bank refused the debit because of the balance. Do not shame the customer. 3. Include a link to pay now by another method. A Mollie payment with `sequenceType` `first` collects the amount and sets up a new mandate in one step. 4. If the subscription ends up cancelled, create a new one once the customer has paid. ### Closed or invalid account (`AC01`, `AC04`) 1. Email the same day. The subscription is already cancelled, so waiting does not help. 2. Ask the customer to pay through a new first payment. They can choose a card or another account. 3. Create a new subscription on the new mandate, starting after the period they just paid for. ### Refusal or reversal (`MS02`, `MD06`, `MD01`) 1. Pause any further attempts in your own system. 2. Ask the customer what happened, in plain words, with a clear way to cancel if that is what they want. Customers who can cancel easily have less reason to reverse a debit. 3. Only collect again once they agree, through a new first payment. ### Deceased (`MD07`) Stop all collection, end access according to your terms, and route any contact to a person. No automated dunning. ## Prevent the next failure - **Store the IBAN holder and mandate date** from `details`, so support can answer "what is this debit?" quickly. - **Use a clear description.** The subscription description appears in the payment description, so make it recognisable on a bank statement. - **Remind before annual renewals.** A large unexpected debit is the classic cause of both `AM04` and `MD06`. - **Make cancelling easy.** A visible cancel option in your app is cheaper than a reversal. ## Doing this with NoChurn Collecting the debit, Mollie's retries and the bank details stay with Mollie. NoChurn connects to your Mollie account, imports customers, mandates and subscriptions, and reads each payment again after a webhook, so it sees the reason code. It sends AI-written recovery emails that you review, with a link to pay again and set up a new payment method, and shows reversals read only on the customer timeline and in the churn score. Cancel flows with a one-click cancel always visible and win-back emails at day 30, 60 and 90 are included on every plan. See [NoChurn + Mollie](/integrations/mollie/). --- # How to win back canceled subscribers on Mollie Source: https://www.nochurn.sh/blog/mollie-win-back/ When a customer cancels a Mollie subscription, the subscription is over for good: Mollie does not let you update a cancelled subscription. Winning that customer back means creating a new one. Whether they have to go through checkout again depends on one thing you can check in the API: whether they still have a valid mandate. This guide covers what Mollie leaves behind after a cancellation, the two ways to restart a subscription, how to time and word win-back messages, and how to track whether they work. It sticks to Mollie's documentation: [Get subscription](https://docs.mollie.com/reference/get-subscription), [Create subscription](https://docs.mollie.com/reference/create-subscription), [Update subscription](https://docs.mollie.com/reference/update-subscription), [List mandates](https://docs.mollie.com/reference/list-mandates), [Revoke mandate](https://docs.mollie.com/reference/revoke-mandate), [Create payment link](https://docs.mollie.com/reference/create-payment-link) and the [Recurring payments guide](https://docs.mollie.com/docs/recurring-payments) (all accessed November 2026). Field descriptions were also checked against Mollie's official [Node.js API client](https://github.com/mollie/mollie-api-node). ## What a cancellation leaves behind | Object | After cancellation | |---|---| | Subscription | `status` is `canceled`, `canceledAt` is set, there is no `nextPaymentDate`, and it cannot be updated | | Mandate | A separate object with its own status. Check it rather than assume | | Customer | Unchanged, with their payment history | The mandate is what decides how easy a return is. Mollie mandates have three statuses: `valid`, `pending` and `invalid`. Mollie's documentation describes revoking a mandate as cancelling its subscriptions, not the other way round, but some events do revoke the mandate: - Revoking it through the API cancels all subscriptions connected to it. - Mollie's help center says a mandate is [revoked after a SEPA reversal](https://help.mollie.com/hc/en-us/articles/115004339309-What-happens-to-a-mandate-after-a-reversal-). - Mollie's recurring payments guide says that when a subscription with a fixed mandate is cancelled for certain failure reasons, the mandate is revoked as well. So before any win-back message, list the customer's mandates and look at their status. That tells you which of the two paths below applies. ## Two ways back ### Path 1: the customer still has a valid mandate Mollie lets you create a subscription for a customer with a `pending` or `valid` mandate, without a new checkout. Technically, a returning customer could be restarted with one API call. That does not mean you should do it silently. The customer cancelled. Charging their account again needs their clear agreement, given at the moment they come back, for the amount and interval they are agreeing to. A practical flow: 1. The win-back email links to a page in your app that shows the plan, the price and the first charge date. 2. The customer confirms with one button. 3. Your server creates the subscription with that amount, interval and `startDate`, on their existing mandate (set `mandateId` if you want to tie it to that one), and records the confirmation. 4. Show and email a confirmation, including how to cancel again. If the mandate is a SEPA Direct Debit mandate and the customer has not been charged for a long time, also make sure they recognise the description that will appear on their bank statement. An unrecognised debit is a common reason for a reversal. ### Path 2: no valid mandate When the mandate is revoked or invalid, the customer has to pay through checkout again. Mollie's [payment links](https://docs.mollie.com/reference/create-payment-link) are a good fit: - Set `sequenceType` to `first`. Mollie's reference says a mandate is then established right after the customer pays. With the default, `oneoff`, no mandate is created. - Set `customerId` to the existing Mollie customer, so the mandate is attached to them. - Set an `expiresAt` date if the offer is time-limited. Without one, the link does not expire. - Leave `reusable` at its default (`false`) so the link is used once. When the link is paid, fetch its payment to get the new mandate, then create the subscription with a `startDate` after the period the first payment covered. The first payment can be the first period itself, at the win-back price if you offer one. ## What to offer, and when The cancel reason is the best guide to both the message and the timing. A schedule that works for many subscription businesses: | Day after cancellation | Message | |---|---| | 30 | What changed since they left, matched to their reason. No discount yet. | | 60 | A specific offer if their reason was price; otherwise a feature or fix that addresses the reason. | | 90 | A last, short note with a direct way back. Then stop. | Matching the reason matters more than the discount: - **Too expensive**: a lower price for a few months. On Mollie, a changed `amount` applies to all future charges, so either create the subscription at the offer price and update it later (tell the customer the date and the full price), or limit the offer with `times` and create a follow-up subscription. - **Not using it**: a cheaper plan or a longer interval, such as `3 months`. - **Missing feature or technical problem**: only write if it is fixed or shipped. Say what changed. - **Switched to a competitor**: one honest message about what you do differently, then stop. Do not write to customers who asked you not to, and keep win-back emails apart from transactional messages in your consent records. ## Before you hit send A short check for each former customer, every time: 1. **Is the mandate still `valid`?** List the customer's mandates just before sending, because a reversal or revocation may have happened since they cancelled. The answer decides which link goes in the email. 2. **Did they leave on good terms?** Skip anyone whose last payment was reversed or who is in a dispute with you until that is resolved. 3. **Did they opt out?** Check your consent records, not just your email tool. 4. **Is the offer still true?** If the email promises a price, make sure the subscription you will create, or the payment link amount, matches it exactly. 5. **Does the link work for them?** Open it in test mode with a test customer: payment link, mandate, new subscription, confirmation email. ## Track it properly - **Store the cancellation** with its date, reason and the last mandate status. - **Tag the returning subscription** in its `metadata`, for example with the campaign and the original cancellation date. Mollie forwards subscription metadata to each payment it creates, so you can report on revenue by campaign. - **Measure months retained, not just restarts.** A customer who comes back for one discounted month and leaves again was not won back. - **Watch reversals.** A win-back that leads to SEPA reversals means the consent step was not clear enough. ## Doing this with NoChurn Mollie keeps the mandates, the payments and the new subscription. NoChurn adds the win-back side: emails at day 30, 60 and 90 written from the cancel reason the customer gave in the cancel flow, with a link to come back. Reasons come from NoChurn's cancel flow, which has a one-click cancel always visible, and returns are tracked against the churn score from 0 to 100. See [NoChurn + Mollie](/integrations/mollie/). --- # Net revenue retention (NRR) vs gross revenue retention: formulas and pitfalls Source: https://www.nochurn.sh/blog/net-revenue-retention/ Net revenue retention (NRR) and gross revenue retention (GRR) both ask the same question: of the recurring revenue you had at the start, how much do you still have? They differ on one thing. NRR counts expansion from existing customers; GRR does not. That one difference makes NRR the number companies like to show and GRR the number that tells you whether the bucket leaks. This guide gives both formulas, the monthly and the 12-month versions, examples on hypothetical numbers, and the mistakes that quietly inflate either one. ## The formulas Start from the recurring revenue of the customers you had at the start of the period. Call it starting MRR (or ARR, the logic is the same). ```text GRR = (starting MRR − churned MRR − contraction MRR) ÷ starting MRR NRR = (starting MRR − churned MRR − contraction MRR + expansion MRR) ÷ starting MRR ``` Where: - **Churned MRR** is revenue from customers who left, voluntarily or because a payment could not be collected. - **Contraction MRR** is revenue lost to downgrades, fewer seats or lower usage among customers who stayed. - **Expansion MRR** is revenue gained from upgrades, more seats, add-ons or price increases among customers who were there at the start. Two properties follow directly: - GRR can never exceed 100%. If yours does, expansion leaked into it. - NRR can exceed 100%, and does whenever expansion outweighs churn plus contraction. New customers never appear in either formula. Neither do customers who left before the period and came back during it (reactivations); treat them as a separate line, as Stripe's MRR roll-forward does with its "reactivation" category ([Stripe analytics docs](https://docs.stripe.com/billing/subscriptions/view-metrics), accessed November 2026). ## Monthly example (hypothetical numbers) A fictional company starts June with $80,000 MRR from its existing customers. During June, among those customers: - Cancellations and failed payments remove $3,200. - Downgrades remove $1,000. - Upgrades and seat additions add $2,400. ```text GRR = (80,000 − 3,200 − 1,000) ÷ 80,000 = 94.75% NRR = (80,000 − 3,200 − 1,000 + 2,400) ÷ 80,000 = 97.75% ``` Same month, three points apart. The gap is the expansion. ## The 12-month cohort version Many companies report NRR and GRR over 12 months rather than monthly. The cleanest definition takes a fixed group of customers and compares their revenue a year apart: ```text 12-month NRR = current ARR of customers who were customers 12 months ago ÷ ARR of those same customers 12 months ago 12-month GRR = same, but each customer's current ARR is capped at their ARR 12 months ago ``` The cap is how expansion is removed customer by customer: a customer who grew from $1,000 to $1,500 counts as $1,000; a customer who shrank to $600 counts as $600; a customer who left counts as $0. ### Example (hypothetical numbers) Five customers had $10,000 ARR in total a year ago: | Customer | ARR a year ago | ARR today | Capped for GRR | |---|---|---|---| | A | $4,000 | $5,500 | $4,000 | | B | $2,000 | $2,000 | $2,000 | | C | $2,000 | $1,200 | $1,200 | | D | $1,000 | $0 (churned) | $0 | | E | $1,000 | $1,800 | $1,000 | | Total | $10,000 | $10,500 | $8,200 | ```text 12-month NRR = 10,500 ÷ 10,000 = 105% 12-month GRR = 8,200 ÷ 10,000 = 82% ``` An NRR above 100% sits on top of a GRR of 82%: nearly a fifth of last year's revenue base left or shrank, and growth from two customers covered it. ### Do not multiply monthly figures Compounding monthly NRR (for example 0.98 to the power of 12) gives a rough number at best. Expansion and churn are not evenly spread across months, and a customer who churns in month 3 cannot expand in month 9. If you report a 12-month figure, compute it from the cohort. ## When to look at which | Question | Use | |---|---| | Is the base leaking? | GRR | | Does the existing base grow on its own? | NRR | | Are cancel flows and payment recovery working? | GRR (they act on churn and contraction) | | Is upsell or seat growth working? | NRR minus GRR (the expansion share) | A business with high NRR and low GRR depends on a few customers growing fast. If that growth stops, the churn underneath shows up all at once. A business with high GRR and NRR close to it keeps its customers but does not grow them. Both are worth knowing. ## Pitfalls that inflate NRR or GRR ### 1. New customers in the numerator The most common error. If a customer signed up during the period, their revenue belongs to growth, not retention. Filter on the customer's start date, not on whether they appear in this month's MRR. ### 2. Reactivations counted as expansion A customer who left in January and returned in May was churned in January. Counting their return as expansion turns a loss into a gain. Keep reactivation as its own line. ### 3. Price increases presented as product pull A list price increase applied to existing customers shows up as expansion and lifts NRR. That is real revenue, but it is not the same signal as customers buying more. Note it next to the number in months with a price change. ### 4. Discounts ending A three-month 50% discount that expires looks like expansion when the price returns to normal. Decide whether MRR is before or after discounts; Stripe's analytics let you choose to exclude recurring and one-time discounts. Be consistent. ### 5. Currency movements If you bill in several currencies and report in one, exchange rates move revenue without anyone buying or leaving. Stripe's roll-forward has a separate FX adjustment line for this reason. Exclude FX from NRR or hold rates constant. ### 6. Past-due revenue counted as retained A subscription in past-due status still counts in MRR in many systems, including Stripe's active subscriber count. If dunning is slow to end subscriptions, GRR looks better than collected revenue. Decide when a failed payment becomes churn and apply it. ### 7. Usage-based volatility For usage-based pricing, one quiet month can look like contraction and one busy month like expansion. Use a trailing average of usage, or report NRR on the committed portion only, and say which. ### 8. Small bases With 30 customers, one large account moves NRR by several points. Show the customer count next to the percentage. ## How to improve each one GRR moves with churn and contraction, so it responds to the retention work: recovering failed payments, matching cancel offers to the reason (a downgrade instead of a cancellation still reduces GRR, but less), and catching risk before renewal. NRR adds expansion, which is product and pricing work: seat growth, add-ons, usage. Improving GRR is usually faster, because a share of churn, the failed payments in particular, never involved a decision to leave. See [involuntary churn](/blog/involuntary-churn/) and [downgrade offers](/blog/downgrade-offers/). ## Doing this with NoChurn NoChurn works on the churn and contraction side of GRR. It recovers failed payments with smart retries timed to the decline reason and payday (on Stripe), AI-written recovery emails you can review and a hosted card update page. It runs cancel flows with an offer per reason, including a plan change instead of a cancellation, with one-click cancel always visible. It sends win-back emails at day 30, 60 and 90 by cancel reason, and scores each customer's churn risk from 0 to 100 at signup and on every change. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # Activation and early churn: fixing the first 30 days Source: https://www.nochurn.sh/blog/onboarding-activation-churn/ New customers usually churn faster than customers who have been around for a while. You can see it in almost any [cohort table](/blog/cohort-retention-analysis/): the steepest drop is in the first month or two, then the curve flattens. That early drop is less about price or competitors and more about whether the customer ever got the product working for them. This guide covers how to define "activated" from your own data, how to measure early churn, where to look for the stall, and what to change. All numbers are hypothetical. ## Step 1: define early churn Pick a window and stick to it: ```text early churn (30 days) = new paying customers who churned within 30 days of their first payment ÷ new paying customers in the cohort ``` Count from the first payment, not the signup, so trial drop-off stays in its own metric ([trial-to-paid conversion](/blog/trial-to-paid-conversion/)). For monthly plans, a 30-day window catches the first renewal; you may prefer 45 or 60 days so the first renewal's retries have finished. Split it like any churn: voluntary (cancelled) vs involuntary (first renewal failed). A first renewal that fails is often a card that was never meant to be charged again, a prepaid card, or a payment that needs authentication; the fix is different from onboarding. See [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ## Step 2: find your activation milestone An activation milestone is an action, done within a fixed early window, that separates customers who stay from customers who leave. "Created first project," "invited a teammate," "sent first campaign," "connected the data source." Do not pick it by opinion. Test candidates against history. ### Method 1. List 5 to 10 candidate actions that plausibly show the customer got value. 2. For each new customer in past cohorts, record whether they did each action **within the first N days** (for example 7 or 14). The fixed window matters: customers who churned on day 10 never had a chance to do something on day 20, which would make every action look predictive. 3. Compare retention at day 90 between customers who did and did not do each action. ### Example (hypothetical numbers) | Action within 14 days | Did it | Retained at day 90 | Did not | Retained at day 90 | |---|---|---|---|---| | Created first project | 700 | 78% | 300 | 52% | | Invited a teammate | 350 | 86% | 650 | 62% | | Connected an integration | 280 | 88% | 720 | 64% | | Opened the help center | 400 | 69% | 600 | 71% | "Opened the help center" does not separate anything. "Invited a teammate" and "connected an integration" separate the most, but fewer customers do them. A good milestone combines a large gap with an action that a reasonable share of customers can reach. Sometimes it is a pair: "created a project **and** invited a teammate within 14 days." ### Correlation, not cause Customers who invite teammates may stay because collaboration makes the product stick, or because teams that were already committed invite each other. The table cannot tell which. Treat the milestone as a hypothesis: if pushing more customers to reach it raises retention in a test, it is causal enough to act on. ## Step 3: measure the funnel to activation Once you have a milestone, track three numbers per weekly or monthly cohort: ```text activation rate = new customers who reached the milestone within N days ÷ new customers time to value = median days from first payment to the milestone, among those who reached it early churn = as defined in step 1 ``` Then break the path into steps and look for the biggest drop. Example funnel for a fictional analytics tool: | Step | Customers reaching it | Drop from previous step | |---|---|---| | Paid | 1,000 | | | Logged in after payment | 930 | 7% | | Connected a data source | 610 | 34% | | Built first report | 520 | 15% | | Shared a report (milestone) | 380 | 27% | The biggest drop is at "connected a data source." That is where to look first, not at the welcome email. ## Step 4: find out why they stall Numbers show where; people tell you why. For the step with the largest drop: - **Watch it.** Go through the step yourself on a fresh account, with a real data source, on a slow connection. - **Ask.** Email customers who stalled at that step with one question: "What stopped you from connecting your data?" Short replies are fine. - **Read support tickets** from customers in their first 30 days. Group them by step. - **Read cancellation reasons** from early churners. "Too hard to set up" and "not using it enough" from a 3-week-old customer usually mean they never activated. See [cancellation reasons survey](/blog/cancellation-reasons-survey/). ## Step 5: fix the first 30 days Typical fixes, roughly in order of effort: ### Remove steps Every field, setting and choice before the milestone costs customers. Defaults, templates and sample data let a customer see the product working before they configure it fully. ### Make the next step obvious One clear next step on screen, not a checklist of twelve. A short checklist (three to five items, ending at the milestone) works if each item is a real step toward value. ### Send help at the moment of the stall Event-triggered emails beat a fixed drip. "You created a project but haven't connected data yet; here's how, in 2 minutes" sent on day 2 to customers who stopped there is more useful than "Welcome, day 3" sent to everyone. ### Offer a human for high-value accounts For larger accounts, a 20-minute setup call at the stall point may be cheaper than any automation. ### Check the first renewal Before the first renewal, check that the payment method is valid and not expiring, and send a short note on what the customer has achieved so far. If the customer has not activated, a helpful message or a pause offer is more honest than charging them again silently. ## Step 6: test and measure Change one thing at a time, and compare cohorts before and after, or run a split test if volume allows. Measure: | Metric | Expected effect of a good fix | |---|---| | Activation rate | Up | | Time to value | Down | | Early churn (30 days) | Down | | Retention at day 90 | Up, and it should hold, not just delay churn | Wait for the day-90 number before declaring victory. A fix that only gets customers to click through the milestone without getting value will raise activation and leave retention unchanged. That is the sign the milestone was a correlate, not the cause. ## Checklist - [ ] Early churn defined from first payment, split voluntary and involuntary. - [ ] Activation milestone chosen from historical data with a fixed window. - [ ] Activation rate and time to value tracked per cohort. - [ ] Funnel to the milestone built; biggest drop identified. - [ ] Customers who stalled asked why. - [ ] One fix shipped and measured at day 90. - [ ] First renewal checked (card valid, customer activated). ## Doing this with NoChurn NoChurn scores each customer's churn risk from 0 to 100 at signup and on every change, so a new customer who looks risky is visible from day one. Send your own events by API, such as your activation milestone, and NoChurn shows which attributes go together with churn (correlation, not causation). If the first renewal fails, it runs recovery: on Stripe, smart retries timed to the decline reason and payday, AI-written emails you can review and a hosted card update page. Customers who decide to leave see a cancel flow with one offer per reason (such as a pause) and a one-click cancel always visible, then win-back emails at day 30, 60 and 90. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # How to add a cancel flow to Paddle Billing Source: https://www.nochurn.sh/blog/paddle-cancel-flow/ A cancel flow is the short step between "I want to cancel" and the cancellation itself: ask why, offer something that fits the reason, and cancel cleanly if the customer still wants to go. This guide explains how cancellation works in Paddle Billing, what Paddle already offers natively, and how to build your own retention step on top of its API. It sticks to Paddle's developer documentation: [cancel a subscription](https://developer.paddle.com/build/subscriptions/cancel-subscriptions/), [pause a subscription](https://developer.paddle.com/build/subscriptions/pause-subscriptions/), [resume a subscription](https://developer.paddle.com/api-reference/subscriptions/resume-subscription/), [update a subscription](https://developer.paddle.com/api-reference/subscriptions/update-subscription/), [discounts](https://developer.paddle.com/build/products/offer-discounts-promotions-coupons/), [provisioning and webhooks](https://developer.paddle.com/build/subscriptions/provision-access-webhooks/), the [customer portal](https://developer.paddle.com/concepts/sell/customer-portal/) and [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys/) (all accessed November 2026). This is about Paddle Billing, not Paddle Classic, whose API is different. ## Paddle is the merchant of record One thing to keep in mind throughout: Paddle is the [merchant of record](https://developer.paddle.com/get-started/how-paddle-works/) for your sales. It sells to your customer, handles tax, and, [per Paddle](https://www.paddle.com/paddle-101), handles billing support and chargebacks. That means the payment relationship is between the customer and Paddle. Your cancel flow should change subscriptions only through Paddle's API or Paddle's own tools, never by trying to stop payments some other way. ## How cancellation works in Paddle Billing Paddle gives you three places where a subscription can be cancelled. ### 1. The cancel API You cancel with `POST /subscriptions/{subscription_id}/cancel`. The `effective_from` field decides when: | `effective_from` | What happens | |---|---| | `next_billing_period` (default, also what an empty body does) | Paddle adds a `scheduled_change` with action cancel. The subscription stays active until its next billing date, and `next_billed_at` becomes null | | `immediately` | The status changes to `canceled` right away and `subscription.canceled` fires | Paddle documents a few limits on the [cancel page](https://developer.paddle.com/build/subscriptions/cancel-subscriptions/): - You cannot cancel or pause within 30 minutes of the next billing date. - A scheduled cancellation can be removed by updating the subscription with `scheduled_change` set to null. This is how you "undo" a cancellation before it takes effect. - A cancelled subscription cannot be reinstated. A returning customer needs a new subscription, which matters for win-back. - A paused subscription can only be cancelled with `effective_from: immediately`. ### 2. The customer portal Paddle's [customer portal](https://developer.paddle.com/concepts/sell/customer-portal/) lets customers cancel and update payment details. Paddle's docs say pausing is not supported in the portal, so a pause offer has to come from your app or from Paddle's Cancellation Flows. ### 3. Paddle's own Cancellation Flows Paddle has a native feature for exactly this, part of Paddle Retain. You configure it under Retain › Cancellation Flows ([setup guide](https://developer.paddle.com/build/retain/configure-cancellation-flows-surveys/)). It asks for a cancellation reason and can offer a pause, a plan switch, contact with support, or a time-limited discount. Per Paddle's [January 2026 changelog](https://developer.paddle.com/changelog/2026/cancellation-flows-customer-portal/), once a flow is set up it runs automatically when customers cancel in the customer portal or through cancellation links in Paddle's subscription emails. In your own app you start it with [`Paddle.Retain.initCancellationFlow()`](https://developer.paddle.com/paddle-js/methods/paddle-retain-initcancellationflow/), which returns a status such as `retained`, `aborted` or `chose_to_cancel`. A [September 2026 changelog](https://developer.paddle.com/changelog/2026/cancellation-flows-sandbox/) adds sandbox testing through the customer portal, while flows started with `initCancellationFlow()` still run only on live accounts. To be clear: if all you need is a reason survey and a standard offer inside Paddle, this native feature may be enough, and Paddle lists it at no extra cost for Paddle Billing customers. The rest of this guide is for when you want your own flow, your own design, or offers that depend on data Paddle does not have. ## The retention offers Paddle's API supports ### Pause `POST /subscriptions/{subscription_id}/pause` pauses a subscription ([guide](https://developer.paddle.com/build/subscriptions/pause-subscriptions/)). It takes `effective_from` (`next_billing_period` or `immediately`) and an optional `resume_at` date. A pause at the next billing period creates a scheduled change; the status becomes `paused` when it takes effect. To bring a customer back early, `POST /subscriptions/{subscription_id}/resume` works only on paused subscriptions. The `on_resume` field decides billing: by default Paddle starts a new billing period and charges immediately; `continue_existing_billing_period` keeps the old period instead. Paddle also [cancels past-due renewal transactions](https://developer.paddle.com/changelog/2024/past-due-renewal-translations-canceled-pause/) when a subscription is paused, to avoid charging twice for overlapping periods. ### Discount Create the discount once with `POST /discounts`. For a retention offer such as "50% off for 3 months", set `recur` to true and `maximum_recurring_intervals` to the number of billing periods. Then apply it to the subscription with `PATCH /subscriptions/{subscription_id}`, passing a `discount` object with the discount's ID and an `effective_from` of `next_billing_period` or `immediately` ([update a subscription](https://developer.paddle.com/api-reference/subscriptions/update-subscription/)). Sending `discount: null` removes it. Paddle notes that renewals and mid-cycle changes do not count as new redemptions. ### Plan change A downgrade is also a subscription update: replace the items with the cheaper price. When you change items or the billing date, Paddle requires `proration_billing_mode`. Use the [preview endpoint](https://developer.paddle.com/api-reference/subscriptions/preview-subscription-update/) to show the customer what they will pay before confirming. ## Building your own cancel flow on Paddle 1. **Put the cancel entry point in your app.** Link "Cancel subscription" to your flow, not straight to the API call. Keep the customer portal available as well; it is Paddle's own path and customers may use it. 2. **Ask one question: why.** Use a short list of reasons plus "Other" with a free-text field. Store the answer with the subscription ID. 3. **Show one offer that matches the reason.** "Too expensive" fits a discount or a cheaper plan. "Not using it right now" fits a pause with a `resume_at` date. "Missing a feature" or "Too complex" fits a conversation with support. Do not stack offers. 4. **Keep "Cancel now" visible on every step.** The customer should be able to finish the cancellation at any point without accepting an offer. This is a matter of trust, and in several places, of law. 5. **Call Paddle for the outcome.** Discount: `PATCH` the subscription with the discount. Pause: `POST .../pause`. Plan change: `PATCH` the items after a preview. Cancel: `POST .../cancel` with `effective_from: next_billing_period`, so the customer keeps what they paid for. 6. **Confirm what happens next.** Tell the customer the date access ends or the date the pause ends. Read it from the subscription returned by Paddle rather than computing it yourself. 7. **Let them change their mind.** Until the scheduled cancellation takes effect, a "Keep my subscription" button can clear `scheduled_change`. ## Webhooks to listen to Paddle's [provisioning guide](https://developer.paddle.com/build/subscriptions/provision-access-webhooks/) recommends `subscription.created` and `subscription.updated` as the core events, because `subscription.updated` covers renewals, plan changes, pauses, resumes and cancellations. A few dedicated events are useful as clear signals: | Event | When it fires | |---|---| | `subscription.updated` | Any change, including a cancellation being scheduled | | `subscription.canceled` | The status becomes `canceled`: immediately, or on the billing date for a scheduled cancellation | | `subscription.past_due` | The subscription becomes past due after a failed renewal | Pauses and resumes also come through `subscription.updated`, with the status moving to or from `paused`; check Paddle's [webhooks reference](https://developer.paddle.com/webhooks/overview) for the dedicated events available in your API version. Two details from Paddle's docs: for a scheduled cancellation, keep access until the scheduled change's effective date; and deduplicate on `event_id` and compare `occurred_at`, because events can arrive out of order. The `subscription.canceled` payload does not include `management_urls`. ## After the cancellation: win-back Because Paddle cannot reinstate a cancelled subscription, a win-back offer must lead to a new checkout. Keep the cancellation reason you collected, wait a reasonable time, and send an offer that answers that reason: a new feature for "missing features", a lower price for "too expensive". Send the customer to a checkout with the discount already applied. ## Doing this with NoChurn NoChurn reads your Paddle subscriptions and events and adds a cancel flow with reasons, offers (discount, pause, plan change) and a one-click cancel that stays visible at every step, either hosted or headless through the API. Accepted offers and cancellations are applied in Paddle, and Paddle stays the merchant of record: it keeps checkout, payments, payment recovery, tax and the customer portal. Disputes are handled by Paddle and shown in NoChurn read only. NoChurn also sends win-back emails at day 30, 60 and 90 based on the cancel reason, and is free under $300 MRR. See [NoChurn + Paddle](/integrations/paddle/). --- # Chargebacks on Paddle: what a merchant of record handles for you Source: https://www.nochurn.sh/blog/paddle-chargebacks-merchant-of-record/ If you sell through Paddle, you do not deal with chargebacks the way a Stripe or Braintree merchant does. Paddle is the merchant of record, so the bank's dispute is raised against Paddle, and Paddle runs the process. That removes a lot of work. It does not remove the cost, and it does not remove the things only you can do to prevent disputes in the first place. This guide explains what Paddle handles, what reaches your balance, how to see it in your data, and what is still in your hands. It sticks to Paddle's own pages: the help article [understanding chargebacks with Paddle](https://www.paddle.com/help/manage/risk-prevention/understanding-chargebacks-with-paddle), the [seller handbook](https://www.paddle.com/seller-guides/seller-handbook), the developer guide on [transaction adjustments](https://developer.paddle.com/build/transactions/create-transaction-adjustments) and the [adjustment reports](https://developer.paddle.com/build/finance/reports/adjustments) page (all accessed November 2026). Where Paddle's pages disagree, we point it out. ## Who the dispute is against Paddle's [help article](https://www.paddle.com/help/manage/risk-prevention/understanding-chargebacks-with-paddle) is clear: because Paddle is the merchant of record for transactions processed through its platform, the dispute is raised against Paddle rather than against you, the seller. In practice that means: - You do not receive the dispute from the bank or a payment processor. - You do not submit the evidence or the response yourself. - Paddle contests the chargeback on your behalf. ## How Paddle contests disputes Paddle's help article describes a Dispute Defense System that contests chargebacks automatically by gathering evidence. The evidence it lists can include communication with the buyer, subscription payment history and proof of authorization for the purchase. The same article notes one limit: if a buyer disputes a second time at the pre-arbitration stage, Paddle does not contest it, and it is treated as a standard chargeback. ## Where the money goes The flow, as Paddle's help article describes it: 1. When a chargeback occurs, the funds are withdrawn from Paddle and the payment provider applies a fee. 2. Paddle deducts the transaction amount and the chargeback fee from your balance. 3. If Paddle wins, the transaction amount comes back to you. On the fee, Paddle's own pages differ. The help article lists a fee per card chargeback and a higher one for PayPal, and gives different wording on whether the fee is returned when a dispute is won. The [seller handbook](https://www.paddle.com/seller-guides/seller-handbook) lists other amounts and says the fee is set out in your Paddle agreement. Treat your agreement as the answer, and check the fee on a real adjustment rather than relying on a number from a blog, including this one. ## Chargeback alerts: the early warning Paddle sometimes receives an alert before a chargeback is finalized. According to the [help article](https://www.paddle.com/help/manage/risk-prevention/understanding-chargebacks-with-paddle), these alerts typically give a short window of around 48 hours to act. In that case Paddle refunds the disputed amount before it becomes a chargeback. A fee still applies to cover the alert, but the dispute does not count toward your chargeback rate. For subscription businesses, this is worth understanding. A refund you did not choose shows up on your account, and the customer may still have an active subscription. If you do not act on it, the next renewal can produce the same outcome. ## Seeing chargebacks in your data Paddle records chargebacks as adjustments on transactions. The [transaction adjustments guide](https://developer.paddle.com/build/transactions/create-transaction-adjustments) explains that Paddle creates these automatically: | Adjustment action | When Paddle creates it | |---|---| | `chargeback_warning` | Paddle received an early warning; the disputed amount is refunded | | `chargeback` | A chargeback without early warning; the disputed amount is refunded | | `chargeback_reverse` | Paddle contested successfully; the held amount is returned | The [adjustment reports](https://developer.paddle.com/build/finance/reports/adjustments) page adds a `chargeback_fee` column, present when the action is `chargeback` or `chargeback_warning`. Practical steps: 1. Pull the adjustments report on a schedule, or subscribe to adjustment notifications (check Paddle's webhook reference for the current event names). 2. When you see `chargeback` or `chargeback_warning`, find the customer and the subscription. 3. Decide what happens to the subscription. In most cases a disputed customer should not be charged again until you have spoken to them. 4. Record `chargeback_reverse` when it arrives, so your reporting shows wins. ## What a merchant of record does not do for you Paddle runs the dispute. It cannot make your customers less likely to dispute in the first place. Most subscription disputes come from a few causes you control. ### Make charges recognizable Customers dispute charges they do not recognize. Use a product name customers know, send a receipt for every renewal, and remind before annual renewals. See [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/). ### Make cancelling easy A customer who cannot find the cancel button calls their bank instead. Paddle's [customer portal](https://developer.paddle.com/concepts/customer-portal) lets customers cancel, and Paddle's Cancellation Flows show a cancel link on every screen in regions with one-click cancellation rules. Do not hide it behind a support email. Our guide to [click to cancel rules](/blog/click-to-cancel-rules/) covers the details. ### Refund before the bank does If a customer emails asking for their money back and you are going to agree anyway, refund quickly through Paddle. A refund you choose is cheaper than a chargeback, and it keeps the customer relationship intact. ### Answer support fast Many disputes start as unanswered support tickets. A clear reply, with the option to cancel or get a refund, ends most of them. ### Keep your own record Even though Paddle gathers evidence, keep a clean record per customer: when they signed up, what they used, what emails you sent, whether they tried to cancel. If Paddle asks you for information, you will have it ready. ### Watch the subscription after a dispute A chargeback or an alert refund does not cancel the customer's subscription by itself in the flows described above. Check the subscription status every time you see a `chargeback` or `chargeback_warning` adjustment. If it is still active, decide whether to cancel it or to contact the customer first. Charging a card again after its owner disputed the last payment is the fastest way to a second dispute, and Paddle does not contest second disputes at pre-arbitration. ### Fraud versus friendly disputes Not every dispute is fraud. Some are customers who forgot they subscribed, could not find how to cancel, or expected a refund they never asked for. The prevention steps above mostly address those. Real fraud (stolen cards used at signup) looks different: new accounts, little or no usage, several signups close together. If you see that pattern, raise it with Paddle support and stop the affected subscriptions. ## Watching the trend Track chargebacks per month alongside cancellations and refunds: - Count of `chargeback`, `chargeback_warning` and `chargeback_reverse` adjustments. - Total fees from the `chargeback_fee` column. - Share of disputed customers who had contacted support or tried to cancel first. That last number tells you whether disputes are a fraud problem or a customer experience problem. The fixes are very different. ## Doing this with NoChurn On Paddle, disputes are handled by Paddle as merchant of record, so NoChurn shows them read only: you see each chargeback next to the customer's subscription, cancel flow answers, emails and support conversations, but there is nothing to submit. Where NoChurn helps is prevention: a cancel flow with one-click cancel always visible, a churn score from 0 to 100, and help desk connectors (read only) that put support history next to billing. See [NoChurn + Paddle](/integrations/paddle/). --- # How failed payments work on Paddle Billing, and what you can add Source: https://www.nochurn.sh/blog/paddle-failed-payments/ When a renewal fails on Paddle Billing, a lot happens without you: Paddle is the merchant of record, it retries the payment, and it can email the customer. That is a real advantage over building dunning yourself. It also means you need to know exactly what Paddle does, so you do not duplicate it or leave gaps. This guide explains how Paddle Billing handles a failed subscription payment, what Paddle Retain adds, how customers update their payment details, and the parts you can improve yourself. It sticks to Paddle's own documentation: the [default dunning changelog](https://developer.paddle.com/changelog/2025/default-dunning-payment-recovery), [configure Payment Recovery and dunning](https://developer.paddle.com/build/lifecycle/subscription-renewal-dunning), [Payment Recovery](https://developer.paddle.com/concepts/retain/payment-recovery-dunning/), [update payment details](https://developer.paddle.com/build/subscriptions/update-payment-details/) and the Paddle help article on [Retain retry cadence](https://www.paddle.com/help/profitwell-metrics/retain/how-it-works/retain-payment-recovery-how-it-works-retry-cadence) (all accessed November 2026). ## What happens when a renewal fails For a subscription collected automatically, Paddle's [dunning guide](https://developer.paddle.com/build/lifecycle/subscription-renewal-dunning) describes the sequence: 1. The payment for the renewal transaction fails. 2. The subscription status changes to `past_due`. 3. Paddle sends `transaction.payment_failed` for the attempt, then [`transaction.past_due`](https://developer.paddle.com/webhooks/transactions/transaction-past-due/) and `subscription.past_due` as the transaction and subscription become overdue. 4. Paddle retries the payment. 5. If a retry succeeds, the subscription goes back to `active` and is no longer overdue. ### Default retries, with or without Retain Paddle's [2025 changelog](https://developer.paddle.com/changelog/2025/default-dunning-payment-recovery) made automatic payment failure retries available to all Paddle Billing users. Failed payments on automatically collected subscriptions are retried up to seven times over 30 days, even if you have not turned on Paddle Retain. Two limits are worth knowing: - **Live accounts only.** Paddle says automatic retries only run on live accounts. No retries occur in sandbox, so you cannot test the full retry schedule there. - **Automatic collection only.** For manually collected subscriptions (paid by invoice), Paddle Retain does not take any action when they are past due. Paddle [moved those subscriptions to `past_due`](https://developer.paddle.com/changelog/2024/manually-collected-subscriptions-past-due/) in 2024, but chasing them is up to you. ### What happens at the end of the window According to Paddle's help article on [retry cadence](https://www.paddle.com/help/profitwell-metrics/retain/how-it-works/retain-payment-recovery-how-it-works-retry-cadence), you set what happens to a subscription when the recovery window ends: cancel it, pause it, or leave it past due. The default is cancellation after 30 days, and the window can be adjusted from the Paddle dashboard. Choose deliberately. Cancelling is clean for reporting. Pausing keeps the subscription so the customer can come back without a new checkout. Leaving it past due keeps the door open but can leave customers with access they are not paying for, unless your app checks the status. ## What Paddle Retain adds [Payment Recovery](https://developer.paddle.com/concepts/retain/payment-recovery-dunning/) is part of Paddle Retain. On top of the default retries, Paddle's docs describe: | Feature | What Paddle says it does | |---|---| | Tactical Retries | Retries failed payments at times chosen from payment method type, customer location and other details | | Recovery emails | Up to four payment recovery emails | | Other channels | Payment reminders in-app and by SMS | | End of dunning | Can pause or cancel subscriptions automatically when all attempts are exhausted | By default, dunning in Retain runs over a 30-day period. Check in your Paddle dashboard whether Payment Recovery is turned on for your account before assuming any of this applies. If you use Retain, let it own retries and emails. Running a second retry schedule against the same card adds attempts without adding information, and two dunning sequences in one inbox look like spam. ## Letting customers update their payment details Most hard declines only recover when the customer gives you a new card. Paddle's [update payment details](https://developer.paddle.com/build/subscriptions/update-payment-details/) guide lists the options: 1. **Customer portal.** Paddle's portal is on by default and lets customers update their payment method without any screens of your own. 2. **Customer portal session.** You can create an authenticated deep link straight to the payment method update page for a specific subscription, so the customer does not have to sign in. 3. **Subscription management URL.** Paddle returns an `update_subscription_payment_method` link for each subscription that you can show in your app. 4. **Update payment method transaction.** Call `GET /subscriptions/:id/update-payment-method-transaction`. Where the subscription is `past_due`, it returns the most recent past-due transaction. Open its `checkout.url`, or pass the transaction ID to Paddle.js. This only works when `collection_mode` is `automatic`. One setup step catches people: the default payment link must be set in your Paddle account and approved before customers can update payment details. Paddle also uses it in its dunning emails. When a past-due subscription is paid after an update, Paddle sends `subscription.activated` and the status becomes `active` again. ## A practical setup Whether or not you use Retain, these steps close the usual gaps. 1. **Set the default payment link** and confirm it is approved. Without it, update links do not work. 2. **Choose the end-of-window outcome** (cancel, pause or past due) based on how your app handles access. 3. **Gate access on status.** Handle `subscription.past_due`, `subscription.activated` and `subscription.canceled` in your app. Decide how much access a past-due customer keeps, and say so. 4. **Show the problem in your app.** A banner for past-due customers with the subscription management link reaches people who never open dunning emails. 5. **Do not double-email.** If Paddle or Retain sends recovery emails, your own messages should be in-app, or clearly different (for example from the account owner, for large B2B accounts). 6. **Chase manual invoices yourself.** Retain does not act on manually collected subscriptions. Build a reminder sequence for those. 7. **Log every failure.** Store each `transaction.payment_failed` with the subscription, amount and outcome. After a few months you will know which customers recover by retry and which only by a new card. ## What you can add on top Paddle covers the core well: retries, a hosted update page, emails and a status model. What is left is mostly context. - **Know which customers are at risk.** A failure on a long-tenured, active account is different from a failure on an account nobody has logged into for two months. - **Tie failures to what you know about the customer.** Plan, usage, support history and payment method type all change what a good recovery message says. - **Measure.** Count recovered versus lost per month and per cause. See [involuntary churn](/blog/involuntary-churn/) for definitions and [dunning email templates](/blog/dunning-email-templates/) if you write your own in-app copy. ## Doing this with NoChurn For Paddle, payment collection, retries and Paddle's own emails stay with Paddle as merchant of record. NoChurn reads your Paddle subscriptions and transactions, gives each customer a churn score from 0 to 100 using your custom data sent by API, and adds a cancel flow and win-back emails at day 30, 60 and 90. Where Paddle's settings leave room, it can send AI-written recovery messages that you review before they go out. See [NoChurn + Paddle](/integrations/paddle/). --- # How to pause subscriptions on Paddle Billing Source: https://www.nochurn.sh/blog/paddle-pause-subscriptions/ Some customers do not want to leave; they want a break. A seasonal business, a project on hold, a tight quarter. If cancel is the only option, they take it, and getting them back later costs a new checkout and often a discount. A pause keeps the subscription, the customer record and the payment method, and gives them an easy way back. Paddle Billing supports pausing natively, through the API and through Paddle Retain's cancellation flows. This guide explains how it works, what happens on resume, and how to offer it well. It sticks to Paddle's documentation: [pause a subscription](https://developer.paddle.com/build/subscriptions/pause-subscriptions), the [pause subscription API reference](https://developer.paddle.com/api-reference/subscriptions/pause-subscription), [subscription pause or resume](https://developer.paddle.com/build/lifecycle/subscription-pause-resume), the [`subscription.paused` webhook](https://developer.paddle.com/webhooks/subscriptions/subscription-paused/), the changelog entries on [resume billing options](https://developer.paddle.com/changelog/2024/resume-subscription-billing-period-options) and [pausing past-due subscriptions](https://developer.paddle.com/changelog/2024/past-due-renewal-translations-canceled-pause/), and [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys) (all accessed November 2026). ## How a pause works on Paddle You pause a subscription with the [pause subscription operation](https://developer.paddle.com/api-reference/subscriptions/pause-subscription). The main options: | Field | What it does | |---|---| | `effective_from` | `next_billing_period` or `immediately`. For active subscriptions the default is `next_billing_period`. | | `resume_at` | Optional date and time (RFC 3339) when the subscription should resume on its own | | `on_resume` | How billing works when the subscription resumes (see below) | ### At the next billing period (the default) Pausing at the next billing period is the gentle option. Paddle's [pause guide](https://developer.paddle.com/build/subscriptions/pause-subscriptions) explains that it creates a scheduled change on the subscription saying it should pause on the next billing date. Until then, the subscription stays active and the customer keeps what they paid for. You will see the scheduled change through `subscription.updated`, and `subscription.paused` once the pause takes effect, as described in [subscription pause or resume](https://developer.paddle.com/build/lifecycle/subscription-pause-resume). ### Immediately With `immediately`, the subscription pauses now. Use it when the customer explicitly asks to stop right away, or when your own logic needs it (for example, after a failed payment). ## Resuming A paused subscription can resume in two ways: automatically at `resume_at` if you set it, or when you call the resume operation. What the customer pays on resume is controlled by `on_resume`, added in Paddle's [2024 changelog](https://developer.paddle.com/changelog/2024/resume-subscription-billing-period-options): - **`start_new_billing_period`** (default): a new billing period starts and Paddle charges right away. - **`continue_billing_period`**: the subscription keeps its existing billing period. Paddle returns an error if you combine this with a resume date after the end of that period. For most retention pauses, the default is easier to explain to customers: "your plan restarts on [date] and you'll be charged then". Use `continue_billing_period` for short pauses inside a period that the customer has already paid for. ## Past-due subscriptions Pausing interacts with failed payments in ways worth knowing: - Paddle's docs say that while a subscription is `past_due`, you can still pause or cancel it, even though most other updates are blocked. - Paddle's [2024 changelog](https://developer.paddle.com/changelog/2024/past-due-renewal-translations-canceled-pause/) says that when you pause a subscription, past-due renewal transactions are canceled automatically, to avoid charging for overlapping billing periods. When the paused subscription resumes, a new billing cycle starts. - Paddle returns an [error](https://developer.paddle.com/errors/subscriptions/subscription_continuing_existing_billing_period_not_allowed_subscription_past_due/) if you try to continue the existing billing period for a past-due subscription. Use `start_new_billing_period` instead. That makes a pause a reasonable end state for failed payments too. Paddle's help article on [retry cadence](https://www.paddle.com/help/profitwell-metrics/retain/how-it-works/retain-payment-recovery-how-it-works-retry-cadence) says you can choose to pause, cancel or leave a subscription past due when the recovery window ends. ## Pausing and cancelling One detail in Paddle's [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys) docs: if a customer cancels an active subscription, it is scheduled to cancel at the next billing period, but a paused subscription is canceled immediately. Tell customers this in your pause confirmation, so "pause, then cancel later" does not surprise them. ## Offering a pause with Paddle Retain Paddle Retain's Cancellation Flows run a short survey when a customer tries to cancel, then make an offer to stay. Paddle's docs list pausing as one of the salvage options, scheduled for the next billing period, along with plan switches and a temporary discount when the customer declines the first offer. Cancel, pause and downgrade choices flow through to Paddle Billing. Since January 2026, Paddle's [changelog](https://developer.paddle.com/changelog/2026/cancellation-flows-customer-portal) says Cancellation Flows also appear when customers cancel in the Paddle customer portal, and from cancellation links in Paddle's subscription emails. Without a configured flow, customers see a simple confirmation dialog. A [later changelog entry](https://developer.paddle.com/changelog/2026/cancellation-flows-sandbox) adds that flows can be built and tested in sandbox through the customer portal. For regions with one-click cancellation rules, Paddle's [2024 changelog](https://developer.paddle.com/changelog/2024/cancellation-flows-cancel-compliance) says a cancel link appears on every screen of the flow. Paddle detects those regions automatically. ## How to offer a pause well 1. **Match the offer to the reason.** A pause answers temporary reasons: seasonality, a paused project, travel, a budget cycle. It does not answer "too expensive" or "missing features". See [pause vs discount retention offers](/blog/pause-vs-discount-retention-offers/). 2. **Offer fixed lengths.** One, two or three months, with `resume_at` set. Open-ended pauses tend to become silent cancellations. 3. **Say what happens on resume.** The date, the amount, and whether a new billing period starts. 4. **Remind before resuming.** Send an email a few days before `resume_at` with a link to extend or cancel. A surprise charge after a pause is a classic source of refund requests. 5. **Keep cancel one click away.** The pause is an offer, never a gate. See [click to cancel rules](/blog/click-to-cancel-rules/). ## Wiring it into your app - On `subscription.updated` with a scheduled pause, show the pause date in the account page. - On `subscription.paused`, switch the account to a paused state and decide what data stays visible. - On resume, restore access and log it. - In reports, count paused customers separately. A pause is not churn, but a pause that ends in cancellation should keep its original reason. ### Test checklist - [ ] A pause at the next billing period keeps access until that date. - [ ] An immediate pause stops access right away. - [ ] `resume_at` resumes the subscription and charges as expected for your `on_resume` choice. - [ ] Pausing a past-due subscription cancels the overdue renewal. - [ ] Cancelling a paused subscription ends it immediately, and your app handles that. ## Doing this with NoChurn NoChurn's cancel flow asks for a reason and offers a pause, a discount or a plan change based on it, with one-click cancel always visible. It runs hosted or headless through the API, so it fits apps where you do not use the Paddle portal. The subscription itself stays in Paddle, which remains the merchant of record. Cancel reasons then drive win-back emails at day 30, 60 and 90 and feed the churn score. See [NoChurn + Paddle](/integrations/paddle/). --- # How to win back canceled customers on Paddle Source: https://www.nochurn.sh/blog/paddle-win-back/ Customers who cancelled once already know your product, have been through your checkout and have told you, at least roughly, why they left. With the right message at the right time, some of them come back. On Paddle Billing, bringing them back has one technical rule that shapes everything else: a canceled subscription cannot be reinstated. This guide explains what Paddle allows, how to build a clean path for returning customers, how to use discounts without training people to cancel, and how to time the messages. It sticks to Paddle's documentation: [cancel a subscription](https://developer.paddle.com/build/subscriptions/cancel-subscriptions), [subscription cancellation](https://developer.paddle.com/build/lifecycle/subscription-cancellation), [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys), the [discounts API reference](https://developer.paddle.com/api-reference/discounts/overview), the help article on [reactivations](https://paddle.com/help/profitwell-metrics/measure/subscription-retention/reactivations) and [testing Retain](https://developer.paddle.com/paddlejs/test-retain) (all accessed November 2026). ## What Paddle allows after a cancellation Paddle's [cancel guide](https://developer.paddle.com/build/subscriptions/cancel-subscriptions) is direct: canceled subscriptions cannot be reinstated. If a customer who cancelled wants to return, you create a new subscription for them. Two details matter for timing: - **Active subscriptions cancel at the end of the period by default.** Until then, the cancellation is a scheduled change, and the customer still has access. Paddle's [cancellation lifecycle page](https://developer.paddle.com/build/lifecycle/subscription-cancellation) notes that `canceled_at` stays empty until the cancellation is processed. - **Paused subscriptions cancel immediately.** Paddle's [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys) docs say so explicitly. The window between a scheduled cancellation and its effective date is your easiest save. Removing a scheduled change keeps the subscription alive without any new checkout. A reminder a few days before the end date, with one click to stay, costs almost nothing. ## The returning-customer transaction Paddle's [cancel guide](https://developer.paddle.com/build/subscriptions/cancel-subscriptions) walks through bringing a customer back: 1. List the customer's subscriptions and find the canceled one. 2. Copy its items: price IDs and quantities, plus the related customer, address and business details. 3. Create a transaction with a `POST` to `/transactions` using those items. 4. Send the customer to checkout, either with the transaction's `checkout.url` or by opening Paddle.js with the transaction ID. When the customer pays, Paddle creates a new subscription. The [lifecycle page](https://developer.paddle.com/build/lifecycle/subscription-cancellation) suggests building this into your app: when a customer with a canceled subscription logs in, create the transaction from their previous subscription and show a "Restart your plan" button. That turns every login by a former customer into a one-click return, with no form to fill in. ### Keep the same customer Use the same Paddle customer for the new transaction. Paddle's help article on [reactivations](https://paddle.com/help/profitwell-metrics/measure/subscription-retention/reactivations) says a customer counts as reactivated in its metrics only if they keep the same customer ID. A new customer record turns a win-back into a "new customer" in your reports, and inflates both acquisition and churn. ### Retain Reactivations Paddle Retain also has a feature called Reactivations. Paddle's [Retain testing page](https://developer.paddle.com/paddlejs/test-retain) notes that Reactivations are not available for every billing platform Retain supports, and that you can simulate them on a page where Retain is installed. Check in your dashboard whether it applies to your account before you plan around it. ## Know why they left Win-back works when the message answers the reason. Collect it at the moment of cancellation. If you use Paddle Retain, [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys) run a short survey when a customer tries to cancel, then make an offer to stay, such as a pause, a plan switch or a temporary discount. Paddle's [2026 changelog](https://developer.paddle.com/changelog/2026/cancellation-flows-customer-portal) says these flows also appear in the Paddle customer portal. If you build your own cancel flow, store the reason and any free text on your side, linked to the customer and subscription. Record which offer was shown and refused. Someone who turned down a 20% discount while cancelling is unlikely to accept the same 20% a month later. ## Plan the sequence | When | Who | Message | |---|---|---| | Before the effective date | Scheduled cancellations | End date reminder, one click to keep the plan | | Day 30 | Voluntary cancellations | What changed, tied to their reason | | Day 60 | No return yet | A specific offer, where the reason was price | | Day 90 | No return yet | A short last note and an easy unsubscribe | By reason: 1. **Price**: a cheaper plan or a limited discount on return. 2. **Missing features**: wait until you ship what they asked for, then tell them. 3. **Not using it**: offer help, a guide or a short call, not money. 4. **Switched to another tool**: ask what it does better. Use the answer even if they never return. 5. **Bad experience**: apologize specifically and say what you fixed. More examples are in our [win-back email examples](/blog/win-back-email-examples/). ## Using Paddle discounts for win-back Paddle [discounts](https://developer.paddle.com/api-reference/discounts/overview) can be added to the returning-customer transaction. A few fields matter: - **`recur`**: whether the discount applies over several billing periods. The default is false, so a discount applies once unless you set it. - **`maximum_recurring_intervals`**: how many periods a recurring discount lasts. Paddle's reference wording around this field has varied, so test the behavior in sandbox before you promise "3 months off" in an email. - On a subscription, the discount object shows when it stops applying: the last billing period for a capped discount, or empty if it recurs forever. Practical rules: 1. **Prefer short discounts.** A first-period or three-period discount is enough to make a return feel worthwhile. 2. **Avoid permanent win-back discounts.** They teach customers that cancelling gets a better price. 3. **Use a dedicated code or a discount applied to the transaction.** Keep win-back discounts separate from acquisition discounts so you can measure them. 4. **Set an expiry.** "This offer ends on [date]" is honest and helps people decide. ## Payment details The payment method a customer used months ago may have expired. Because the returning-customer flow goes through checkout, the customer confirms or enters payment details there. That is a feature, not friction: it avoids a failed first renewal. ## Measure the results Track, per cancellation month: - Customers who returned within 90 days, on which plan, and with which discount. - Return rate by cancellation reason. - How long returning customers stay the second time. Count returns only when they are on the same customer ID, matching Paddle's own definition of a reactivation. For the base metrics, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ## Doing this with NoChurn NoChurn reads cancellations from Paddle, collects reasons through its cancel flow (hosted or headless, one-click cancel always visible), and sends win-back emails at day 30, 60 and 90 based on the reason. The returning customer pays through Paddle checkout, and Paddle stays the merchant of record. You can add your own customer data by API, and the churn score from 0 to 100 shows which former customers are worth a personal note. See [NoChurn + Paddle](/integrations/paddle/). --- # How to use Polar discounts as retention offers Source: https://www.nochurn.sh/blog/polar-discounts-retention-offers/ A customer about to cancel because of price is one of the few cases where a discount really is the right answer. Polar does not ship a retention offer screen of its own in the docs we reviewed, but it has the pieces to build one: discounts with durations, an API to attach a discount to an active subscription, and cancellation reasons on the subscription. This guide shows how those pieces fit together, when a discount is the right offer, and the mistakes that turn retention discounts into a permanent price cut. It sticks to Polar's documentation: [discounts](https://polar.sh/docs/features/discounts), the [create discount API reference](https://polar.sh/docs/api-reference/discounts/create), [manage subscriptions](https://polar.sh/docs/features/subscriptions/manage), the [update subscription API reference](https://polar.sh/docs/api-reference/subscriptions/update) and the [webhook events](https://polar.sh/docs/integrate/webhooks/events) page (all accessed November 2026). ## What a Polar discount can be Polar's [discounts](https://polar.sh/docs/features/discounts) have two types and three durations. ### Types - **Percentage**: in the API, expressed in basis points. 1,000 basis points is a 10% discount. - **Fixed**: a fixed amount off. ### Durations (for subscriptions) | Duration | What it does | |---|---| | `once` | Applies one time | | `repeating` | Applies for a set number of months; `duration_in_months` is required | | `forever` | Applies indefinitely | One-time purchases always apply a discount once, whatever the duration. ### Restrictions From the dashboard or the API, a discount can have: - A **code**, if customers should enter it themselves. - **Starts at** and **ends at** dates. - **Maximum redemptions**. - **Products** it applies to. Leaving this empty applies the discount to every product, including products you create later. Polar notes that once a discount has been redeemed, its type, duration and amount cannot be changed. Get them right before you use a discount in a live offer. ## Applying a discount to an active subscription This is the key step for retention. Polar's [manage subscriptions](https://polar.sh/docs/features/subscriptions/manage) guide shows a `PATCH` to `/v1/subscriptions/:id` with a `discount_id` in the body. - The discount is attached to the active subscription. - The change applies on the **next billing cycle**. Polar does not re-bill the current period. - Passing `null` as the `discount_id` removes the current discount. Because the change takes effect at the next cycle, say so in the offer: "Your next renewal will be 30% lower" is accurate. "We have refunded 30%" is not. ## Knowing why the customer is leaving A discount only helps when the reason is price. Polar stores the reason on the subscription: - `customer_cancellation_reason`, with values such as `too_expensive`, `missing_features` and `other`. - `customer_cancellation_comment`, the customer's free text. When a customer cancels from the Customer Portal or you cancel through the dashboard or API, Polar's [webhook events](https://polar.sh/docs/integrate/webhooks/events) page says it sends `subscription.updated` and `subscription.canceled` immediately. The subscription keeps its `active` status with `cancel_at_period_end` set to true, and only moves to `canceled` when the period ends. Until then, the customer can undo the cancellation, which sends `subscription.uncanceled`. That gives you two moments to make an offer: 1. **Before the cancellation**, in your own app, when the customer clicks "Cancel" and you ask why. 2. **After a scheduled cancellation**, while the subscription is still active, with an email offering the discount and a link to undo the cancellation. ## Building the offer step A simple retention step, in your own app, before the customer reaches Polar's cancel action: 1. **Ask for the reason** with a short list that maps to Polar's values (too expensive, missing features, other) plus a free text field. 2. **If the reason is price**, show one offer: for example, 30% off the next three months. Create this discount in advance as a `repeating` percentage discount with `duration_in_months` set to 3, limited to the relevant products. 3. **If the customer accepts**, call the update subscription endpoint with the `discount_id`. Confirm the new amount and when it starts. 4. **If the customer declines**, cancel. The cancel button must be visible at every step, and a refusal must lead straight to cancellation. See [click to cancel rules](/blog/click-to-cancel-rules/). 5. **Record the outcome**: reason, offer shown, accepted or declined. Store it next to Polar's own `customer_cancellation_reason`. For other reasons, a discount is usually the wrong tool. "Missing features" calls for a roadmap note or a follow-up when the feature ships. "Not using it" calls for help or a smaller plan. Our guide on [pause vs discount retention offers](/blog/pause-vs-discount-retention-offers/) maps reasons to offers. ## Pitfalls to avoid ### Forever discounts A `forever` retention discount is a permanent price cut for anyone who clicks Cancel. Word spreads. Prefer `once` or a short `repeating` discount. ### Shared codes A retention discount with a public code ends up on coupon sites. Apply retention discounts by ID through the API instead of handing out codes, and set maximum redemptions and an end date as a backstop. ### Stacking with existing discounts The update call sets the subscription's `discount_id`, so attaching a retention discount can replace a discount the customer already has. Check for an existing discount before you make an offer, or you may raise their price by accident. ### Offering the same thing twice If a customer declined a discount while cancelling, do not send the same discount in the first win-back email. Change the offer or change the message. ### Unclear timing Because the discount starts on the next billing cycle, a customer who expects immediate savings may feel misled. Show the exact next renewal amount and date. ## A worked example Suppose a customer on a monthly plan clicks Cancel and picks "too expensive". 1. Your app shows: "Stay for 30% less on your next 3 renewals. Or cancel now." Both buttons are equally visible. 2. The customer accepts. Your backend calls the update subscription endpoint with the ID of your prepared `repeating` discount. 3. You confirm by email: the current period is unchanged, and the next three renewals are 30% lower, starting on the next billing date. 4. You store the reason, the offer and the acceptance. 5. Before the discount ends, you decide whether to say anything. A short note that the regular price resumes on a given date avoids a surprise and a possible refund request. If the customer had declined, your app would cancel the subscription straight away, and Polar would keep it active until the end of the period with `cancel_at_period_end` set. ## Measuring whether it works For each offer, track: - How often it was shown, and how often it was accepted. - Of those who accepted, how many were still subscribed three and six months later. - Revenue kept versus the discount given. An offer that many accept but that only delays cancellation by one cycle is a cost, not a save. For the broader picture, see [cancel flow best practices](/blog/cancel-flow-best-practices/) and [cancellation reasons surveys](/blog/cancellation-reasons-survey/). ## Doing this with NoChurn NoChurn's cancel flow asks for the reason and shows a matching offer (a discount, or a pause or plan change where your billing setup supports it), with one-click cancel visible at every step. It runs hosted, or headless through the API so the step fits inside your own app. On Polar, the subscription and billing stay with Polar as merchant of record. Answers feed win-back emails at day 30, 60 and 90 and the churn score. See [NoChurn + Polar](/integrations/polar/). --- # What happens when a payment fails on Polar Source: https://www.nochurn.sh/blog/polar-failed-payments/ Polar sells your subscriptions as merchant of record. When a subscription renewal fails, Polar handles the recovery itself: it retries the card, keeps the subscription in a recoverable state, and revokes benefits if nothing works. The rules are simple and mostly fixed, which is good to know before you design anything around them. This guide explains the sequence step by step, the one setting you control, the webhooks to listen for, and what you can add without fighting Polar's own flow. It sticks to Polar's documentation: [recovering failed payments](https://polar.sh/docs/features/subscriptions/failed-payments), [how subscriptions work](https://polar.sh/docs/features/subscriptions/introduction), the [`subscription.past_due`](https://polar.sh/docs/api-reference/2026-04/subscription_past_due) and [`subscription.revoked`](https://polar.sh/docs/api-reference/webhooks/subscription.revoked) webhooks (all accessed November 2026). Where Polar's pages disagree or stay silent, we say so. ## The sequence, step by step According to Polar's [failed payments page](https://polar.sh/docs/features/subscriptions/failed-payments): 1. At renewal, Polar first advances the subscription to the next billing cycle, then attempts to charge the customer's default payment method. 2. If the charge fails, the subscription is not canceled. It moves to `past_due` and enters Polar's automated payment recovery. 3. Polar retries the payment on a fixed schedule: four attempts spread over 21 days, counted from the first failure. The schedule is set by Polar and is not configurable. 4. If the customer updates their payment method in the meantime, Polar retries the charge immediately instead of waiting for the next scheduled attempt. 5. If a retry succeeds, the subscription is back in good standing. 6. If all retries fail, or if the decline code shows the payment method will never succeed (Polar gives `lost_card` as an example), Polar stops retrying and revokes the subscription and its benefits. Point 6 is worth noticing. Polar does not keep retrying a card that cannot work, which is the right behavior, and it means hard declines end much sooner than 21 days unless the customer acts. ## The setting you control: the grace period By default, Polar revokes benefits strictly. Polar offers an organization-level grace period that holds off benefit revocation while a subscription is `past_due`. You set it under Settings, then Subscriptions, then "Grace period for benefit revocation". What the grace period does and does not do, per Polar's docs: | | During the grace period | |---|---| | Subscription status | Still `past_due` | | Customer's benefits | Kept | | Retry schedule | Unchanged | | Measured from | `past_due_at` | So the grace period is about access, not about collection. It is a good choice when benefits are things customers rely on day to day (a license key, access to a private repository, a Discord role), and losing them over a temporary card problem would make the customer leave for good. ## How the customer fixes it The fix for most hard declines is a new card. Polar's [subscriptions overview](https://polar.sh/docs/features/subscriptions/introduction) says the Customer Portal lets customers update their payment method, download invoices and cancel. Because Polar retries immediately after a payment method update, a customer who updates their card recovers the subscription right away. Polar's docs we checked do not detail the content or timing of any notification emails sent to customers on failure. Test it in sandbox: trigger a failure with a test card and see what reaches the customer's inbox before you write your own messages, so you do not send duplicates. ## The webhooks to listen for | Event | Meaning | |---|---| | `subscription.past_due` | A renewal failed. Polar describes this as a recoverable state: the customer can update their payment method to restore the subscription. | | `subscription.updated` | The subscription changed, including when it recovers | | `subscription.revoked` | The subscription was revoked, either because it was canceled or because payment retries are exhausted | One inconsistency to plan for: Polar's [`subscription.revoked` page](https://polar.sh/docs/api-reference/webhooks/subscription.revoked) says that when payment retries are exhausted the status becomes `unpaid`, while the failed payments page describes the subscription ending as canceled with benefits revoked. Write your handler to treat both as "no longer paying", and log the actual status you receive. ## A practical setup on Polar 1. **Decide on the grace period.** If benefits are part of daily work, set one. If benefits are cheap to restore, strict revocation is fine. 2. **Handle `subscription.past_due` in your app.** Show a banner with a link to the Customer Portal. Many customers never read billing emails, but they do see your product. 3. **Explain what happens next.** Tell the customer that Polar will try again and that updating the card fixes it right away. 4. **Handle revocation gracefully.** On `subscription.revoked`, keep the customer's data, explain why access stopped, and give a clear way back. 5. **Log every failure.** Store the subscription, the amount, the date and the outcome. After a few months you will see how many recover by retry and how many only after a card update. 6. **Test with sandbox cards.** Run a soft decline, a hard decline and a recovery before going live. ## What the timeline looks like for a customer Putting Polar's rules together, a typical soft decline plays out like this: 1. Renewal day: the charge fails, the subscription becomes `past_due`, and `subscription.past_due` reaches your app. 2. Over the next three weeks: Polar makes its scheduled retries. If you set a grace period, the customer keeps their benefits for that long. 3. Any time in that window: the customer updates their card in the Customer Portal, Polar retries at once, and the subscription recovers. 4. End of the window with no success: Polar revokes the subscription, and `subscription.revoked` reaches your app. For a hard decline, step 2 can be skipped entirely, because Polar stops retrying a payment method that cannot succeed. That is why the in-app banner matters most for hard declines: the customer's own action is the only path back, and the window is short. ## What Polar does not cover Polar's recovery is intentionally simple. The parts left to you: - **Context.** Polar treats every failure the same way. A failure on a long-time customer who uses the product daily deserves a different message than one on a dormant account. - **Messages in your own voice.** If you want recovery messages that mention the customer's plan, usage or team, you write them. - **Measurement.** Recovered versus lost per month, per cause. See [involuntary churn](/blog/involuntary-churn/) for the definitions and [dunning email templates](/blog/dunning-email-templates/) for message ideas. - **Prevention.** Cards expiring before the next renewal are predictable. A reminder before the renewal avoids the failure entirely; see [expiring cards](/blog/expiring-cards/). ## Doing this with NoChurn On Polar, payment collection, retries and the 21-day schedule stay with Polar as merchant of record; NoChurn does not change them. It reads your Polar subscriptions and failures, sends AI-written recovery emails that you review before they go out, and gives each customer a churn score from 0 to 100, enriched with your own data sent by API. Cancellations then get a cancel flow and win-back emails at day 30, 60 and 90. See [NoChurn + Polar](/integrations/polar/). --- # How to reduce subscription churn on Polar Source: https://www.nochurn.sh/blog/polar-reduce-churn/ Polar gives you more churn tooling than you might expect from a young billing platform: cancellation at period end that the customer can undo, recorded cancellation reasons, a pause option, and automatic retries on failed renewals. This guide explains how each piece works and how to add a retention step and win-back on top. It sticks to Polar's own documentation: [managing subscriptions](https://polar.sh/docs/features/subscriptions/manage), [recovering failed payments](https://polar.sh/docs/features/subscriptions/failed-payments), [customer portal](https://polar.sh/docs/features/customer-portal/introduction), [discounts](https://docs.polar.sh/features/discounts), [update subscription](https://docs.polar.sh/api-reference/subscriptions/update), [webhook events](https://polar.sh/docs/integrate/webhooks/events), [analytics](https://polar.sh/docs/features/analytics), [fees](https://polar.sh/docs/merchant-of-record/fees) and the [changelog](https://polar.sh/docs/changelog/recent) (all accessed November 2026). Polar's docs move quickly, so check the version of the API you use. ## Polar is the merchant of record Polar [sells to your customers as merchant of record](https://polar.sh/features/merchant-of-record), handling tax, payments and disputes. Its [fees page](https://polar.sh/docs/merchant-of-record/fees) says each dispute costs $15, won or lost, deducted from your balance. Its [account reviews page](https://polar.sh/docs/merchant-of-record/account-reviews) explains that Polar watches chargeback rates and, for orders below a certain value, may refund automatically when it gets an early signal from the card networks. You do not answer disputes yourself, but the way you handle cancellations has a direct effect on how many you get. ## Two ways a subscription ends Polar's [managing subscriptions page](https://polar.sh/docs/features/subscriptions/manage) describes two paths. | | Cancel at period end | Revoke | |---|---|---| | How | `PATCH /v1/subscriptions/{id}` with `cancel_at_period_end: true`, or the dashboard toggle | `DELETE /v1/subscriptions/{id}` | | Access | Kept until `current_period_end` | Ends immediately, benefits revoked | | Refund | Not applicable | None issued | | Reversible | Yes, until the end date (uncancel) | No | For a customer who asks to cancel, cancel at period end is the right default: they keep what they paid for, and they can change their mind. Polar says so itself: use cancel at period end if you want the option to reverse the decision. Uncancelling sets `cancel_at_period_end` back to false and clears `ends_at` and `canceled_at`. ### Record the reason When you cancel at period end through the API, Polar accepts an optional reason and comment. The eight reason codes are `too_expensive`, `missing_features`, `switched_service`, `unused`, `customer_service`, `low_quality`, `too_complex` and `other`. Polar asks you to set them only when the customer actually gave them, for example in a survey, and warns that the comment is visible to the customer in their purchase history, so internal notes do not belong there. Polar's [analytics](https://polar.sh/docs/features/analytics) show cancellation reasons in charts you can click through to the subscriptions and comments behind them. It also separates "canceled" (the customer asked to cancel during the period) from "churned" (paid access actually ended), which is a useful distinction when you measure a cancel flow. ## Pause Per Polar's [changelog](https://polar.sh/docs/changelog/recent), a pause is scheduled for the end of the billing period. At that point billing stops and benefits are revoked, but the subscription and payment method stay on file. You can let customers pause from the customer portal, and the `subscription.paused` and `subscription.resumed` webhooks tell you when the state changes. ## The customer portal Polar's hosted [customer portal](https://polar.sh/docs/features/customer-portal/introduction) lets customers cancel (at period end by default) and update their default payment method. Plan changes, seat changes and pause or resume depend on toggles in your portal settings. Updating the payment method is only available in the hosted portal, which keeps card details off your servers; the Customer Portal API you can use for your own portal does not cover it. If customers cancel from the hosted portal, they go straight to the cancellation. If you want a retention step first, send the "Cancel" button in your app to your own flow, and keep the hosted portal for payment details. ## Discounts Polar [discounts](https://docs.polar.sh/features/discounts) apply once, for a fixed number of months, or forever. To give a discount to an existing subscriber, set `discount_id` with the [update subscription](https://docs.polar.sh/api-reference/subscriptions/update) endpoint; Polar applies the change on the next billing cycle, and `null` removes it. Polar's docs do not say whether swapping a repeating discount resets its remaining months, so test that in the sandbox before you rely on it. ## What Polar does on failed payments Polar documents its behavior on [recovering failed payments](https://polar.sh/docs/features/subscriptions/failed-payments): 1. When a renewal charge fails, the subscription becomes `past_due` and `subscription.past_due` fires. 2. Polar retries four times: 2, 5, 7 and 7 days after the previous attempt, which is 2, 7, 14 and 21 days after the first failure. 3. If the customer updates their payment method in the portal, Polar retries the charge immediately. 4. If all retries fail, or the decline means the payment method will never work, Polar stops retrying, the subscription ends and benefits are revoked, and `subscription.revoked` fires. 5. An organization-level grace period can delay benefit revocation. It does not change the retry schedule. Usage-based meter orders follow a different schedule and do not affect the subscription itself; see Polar's [billing page](https://polar.sh/docs/features/usage-based-billing/billing). The retry timing is fixed by Polar; what you can add is clear communication with the customer while the subscription is past due, pointing them to the portal to update their card. ## Webhooks to listen to From Polar's [webhook events](https://polar.sh/docs/integrate/webhooks/events): | Event | Meaning | |---|---| | `subscription.updated` | Fires for every change, including the ones below | | `subscription.canceled` | Cancellation requested; the subscription may still be active until period end | | `subscription.uncanceled` | The customer undid a pending cancellation | | `subscription.revoked` | Access ends: period end reached after cancellation, or retries exhausted | | `subscription.past_due` | A renewal payment failed and can still be recovered | | `subscription.paused` / `subscription.resumed` | Pause state changed | | `subscription.cycled` | A renewal | For a cancellation at period end, Polar sends `subscription.updated` and `subscription.canceled` immediately (status still `active`, `cancel_at_period_end` true), then `subscription.updated` and `subscription.revoked` when the period ends. Polar's guidance is not to remove access on `subscription.canceled`, but to wait for the end of the period or `subscription.revoked`. ## A cancel flow on Polar, step by step 1. **Route "Cancel" in your app to your flow**, not to an immediate API call. 2. **Ask why**, using Polar's eight reason codes so the answers line up with Polar's analytics, plus a free-text field. 3. **Show one offer that fits the reason.** `too_expensive`: a discount for a few months. `unused`: a pause. `missing_features` or `too_complex`: a reply from a person. 4. **Keep "Cancel now" visible on every step**, finishing in one click. 5. **Apply the result.** Discount: `PATCH` with `discount_id`. Cancel: `PATCH` with `cancel_at_period_end: true`, the reason and, if the customer wrote one, the comment. Avoid revoking unless the customer asked for an immediate end, since it cannot be undone and issues no refund. 6. **Confirm the end date** from `current_period_end`, and offer a "keep my subscription" button until then. ## Win-back Start from `subscription.revoked`. Keep the reason the customer gave, wait, then contact them with something that answers that reason, and send them to a new checkout, with a discount if that fits. ## Doing this with NoChurn NoChurn reads your Polar subscriptions and webhooks and adds a cancel flow with reasons, offers and a one-click cancel that is always visible, hosted or headless through the API, plus win-back emails at day 30, 60 and 90 based on the cancel reason and a churn score from 0 to 100. Polar stays the merchant of record: checkout, payments, payment recovery, refunds and disputes stay with Polar, and disputes appear in NoChurn read only. NoChurn is free under $300 MRR, with every feature on every plan. See [NoChurn + Polar](/integrations/polar/). --- # Tracking churn with Polar webhooks Source: https://www.nochurn.sh/blog/polar-webhooks-churn-tracking/ Polar already shows churn in its dashboard. But if you want churn next to your own product data (usage, plan, signup source), you need the raw events in your own database. Polar's webhooks give you everything, as long as you read them the way Polar intends. This guide maps Polar's subscription events to churn, explains the delivery and signature rules that trip up handlers, and shows how to build a churn log you can trust. It sticks to Polar's own documentation: [webhook events](https://polar.sh/docs/integrate/webhooks/events), [handling and monitoring deliveries](https://polar.sh/docs/integrate/webhooks/delivery), [Managing subscriptions](https://polar.sh/docs/features/subscriptions/manage), [Recovering failed payments](https://polar.sh/docs/features/subscriptions/failed-payments), [Analytics](https://polar.sh/docs/features/analytics) and the [Get Metrics API](https://polar.sh/docs/api-reference/metrics/get) (all accessed November 2026). ## The subscription events Polar's [webhook events page](https://polar.sh/docs/integrate/webhooks/events) describes these subscription events: | Event | What Polar says it means | Churn meaning | |---|---|---| | `subscription.created` | A new subscription | New or returning customer | | `subscription.active` | A subscription becomes active: a new paid subscription, or a recovered payment | Paying | | `subscription.updated` | Any change to the subscription, including renewals | Use to sync state | | `subscription.canceled` | Canceled; the customer may keep access until the end of the period | Churn scheduled | | `subscription.uncanceled` | The customer reversed a pending cancellation | Scheduled churn reversed | | `subscription.past_due` | A renewal payment failed and can still be recovered | Involuntary churn risk | | `subscription.revoked` | Access ends now: the period of a canceled subscription ended, the merchant revoked it, or payment retries were exhausted | Churn happened | Polar notes that `subscription.updated` fires for every change and suggests listening to the specific events when you only need certain transitions. For churn, the specific events are clearer. ### The order of events Polar documents the sequences, and they matter for counting: - **Cancel at period end:** `subscription.updated` and `subscription.canceled` arrive immediately. When the period ends, `subscription.updated` and `subscription.revoked` follow. - **Immediate revocation:** `subscription.updated`, `subscription.canceled` and `subscription.revoked` arrive together. So every churned subscription produces both a `subscription.canceled` and a `subscription.revoked`, possibly a month or a year apart. Count churn on `subscription.revoked`. Count `subscription.canceled` separately as "cancellations scheduled", a leading indicator. ### Voluntary vs involuntary `subscription.revoked` covers both voluntary churn (a cancellation reached its end) and involuntary churn (payment retries ran out). To tell them apart: - If the subscription had `cancel_at_period_end` set and a `subscription.canceled` without a later `subscription.uncanceled`, it is voluntary. - If it went through `subscription.past_due` without returning to `subscription.active`, it is involuntary. Polar's [failed payments page](https://polar.sh/docs/features/subscriptions/failed-payments) explains the involuntary path: after a failed renewal the subscription moves to `past_due` and Polar emails the customer with a link to the Customer Portal. It retries 4 times, at 2, 5, 7 and 7 days after the previous attempt (2, 7, 14 and 21 days after the first failure), and revokes if all retries fail or if the decline code shows the payment method will never succeed, such as `lost_card`. A grace period for benefits can be set (immediate, 2, 7, 14 or 21 days from `past_due_at`); it does not change the retry schedule. One inconsistency to be aware of: Polar's revocation docs and its webhook reference describe the final status after exhausted retries differently (`canceled` in one, `unpaid` in the other). Do not hardcode either; rely on the `subscription.revoked` event and your log of what came before. ### Reasons come with the subscription When a cancellation has a reason, it is on the subscription: `customer_cancellation_reason` (values `too_expensive`, `missing_features`, `switched_service`, `unused`, `customer_service`, `low_quality`, `too_complex`, `other`) and `customer_cancellation_comment` ([Managing subscriptions](https://polar.sh/docs/features/subscriptions/manage)). Store them from the `subscription.canceled` payload so you can split churn by reason. ## Delivery rules Per Polar's [delivery page](https://polar.sh/docs/integrate/webhooks/delivery): - **Retries:** failed deliveries are retried up to 10 times with exponential backoff. - **Timeout:** 10 seconds, with a recommendation to respond within 2 seconds and do heavy work in a background job, since the timeout may be lowered. - **Disabled endpoints:** after 10 consecutive non-2xx responses, the endpoint is disabled and all organization members get an email. Re-enabling is manual, in the webhook settings. - **Firewalls:** Cloudflare Bot Fight Mode can cause 403 failures; allow Polar's requests with a WAF rule. That third point is the one to plan for. A deploy that breaks your handler for an afternoon can disable the endpoint, and nothing reaches you until someone turns it back on. ### Signatures The same page explains that the signing scheme depends on when the endpoint's secret was created. Secrets created on or after 8 September 2026 (00:00 UTC) use the Standard Webhooks scheme and are passed as-is to a Standard Webhooks library. Older secrets use Polar's original HMAC, where the full `whsec_` secret string is base64-encoded before being given to the library. The endpoint's `uses_standard_webhook_signature` field tells you which applies, and Polar's SDKs from 1.0.0-alpha.19 try both. If you are unsure, check that field before debugging a "signature mismatch" for hours. ### Local testing The Polar CLI's `polar webhook listen` forwards your organization's events to a local URL and shows the secret to use for verification ([CLI webhooks](https://polar.sh/docs/integrate/cli/webhooks)). ## Building a churn log 1. **One endpoint, specific events.** Subscribe to the seven events in the table above. 2. **Verify, store, return.** Check the signature, write the raw payload with the event type, subscription ID, customer ID and timestamp, and return a 2xx within a couple of seconds. 3. **Deduplicate.** Retries mean repeats. If your deliveries carry a unique message ID, use it; otherwise build a key from the event type, the subscription ID and the subscription's last-modified timestamp, and skip anything you have already stored. 4. **Process in the background.** Update your customer records from the stored event, never in the request. 5. **Keep it append-only.** Derive current status and metrics from the log, so you can replay after a bug. 6. **Watch the endpoint.** Alert on non-2xx responses before Polar's 10-failure limit is reached. 7. **Reconcile.** Weekly, list subscriptions through the API and compare with your log. ## Compare with Polar's own numbers Polar's [Analytics](https://polar.sh/docs/features/analytics) defines its metrics precisely, which makes it a good cross-check: - **Canceled subscriptions:** cancellations triggered by customers in the interval; the subscription may still be active. - **Churned subscriptions:** subscriptions whose paid period ended in the interval. - **Churn rate:** churned subscriptions in the interval divided by active subscriptions at the start of the interval. - **MRR:** excludes trialing subscriptions; includes paused and past-due ones until they actually end. The [Get Metrics API](https://polar.sh/docs/api-reference/metrics/get) returns fields such as `active_subscriptions`, `churned_subscriptions`, `canceled_subscriptions`, `churn_rate` and `monthly_recurring_revenue` per interval, with a breakdown of cancellation reasons. If you adopt the same definitions in your own log, your churn rate and Polar's should match for the same period. When they do not, you have probably missed events, often because the endpoint was disabled for a while. ## What your own log adds Polar's analytics answers "how much churn". Your log, joined with your product data, answers "whose churn and why": churn by signup source, by activation, by plan, by cancellation reason, by voluntary vs involuntary. That is where the actionable work is. ## Doing this with NoChurn Polar stays the source of truth for subscriptions, payments and its retry schedule, and its analytics remain useful. NoChurn subscribes to your Polar webhooks, stores and deduplicates the events, separates voluntary from involuntary churn, and joins them with custom data you send by API. It adds a churn score from 0 to 100 per customer and the reasons collected in its cancel flow. Disputes stay with Polar as the merchant of record and are shown read only. See [NoChurn + Polar](/integrations/polar/). --- # How to win back canceled subscribers on Polar Source: https://www.nochurn.sh/blog/polar-win-back/ Polar makes cancelling easy, on purpose. Its customer portal always lets subscribers cancel at the end of their period, and that option cannot be turned off. That is good for trust. It also means your win-back strategy has to work with Polar's model rather than around it. This guide explains what happens on Polar when a subscriber cancels, the two windows in which you can bring them back, and how to use cancellation reasons and discounts to do it. It sticks to Polar's own documentation: [Managing subscriptions](https://polar.sh/docs/features/subscriptions/manage), the [Customer Portal](https://polar.sh/docs/features/customer-portal/introduction), [webhook events](https://polar.sh/docs/integrate/webhooks/events), [Discounts](https://polar.sh/docs/features/discounts) and the [Update Subscription API reference](https://polar.sh/docs/api-reference/2026-10/subscriptions/update-subscription) (all accessed November 2026). ## How cancellation works on Polar Polar distinguishes two ways a subscription can end. ### Cancel at period end This is what the customer does in the portal, and what you do with `cancel_at_period_end: true` on the subscription ([Managing subscriptions](https://polar.sh/docs/features/subscriptions/manage)). The subscription stays active, the customer keeps their benefits, and it ends on `current_period_end`. The [Customer Portal docs](https://polar.sh/docs/features/customer-portal/introduction) say "cancel at period end" is always available to customers and that the portal cannot be turned off. Polar ties this to California's Automatic Renewal Law, which requires that customers can cancel the way they signed up. You can disable other portal actions (plan changes, email edits), but not this one. ### Revoke Revocation ends the subscription immediately. It is merchant-only and, per Polar, irreversible. It also happens automatically when payment retries are exhausted after failed renewals ([failed payments](https://polar.sh/docs/features/subscriptions/failed-payments)). ### The events The [webhook events page](https://polar.sh/docs/integrate/webhooks/events) describes the sequence: | What happens | Events sent | |---|---| | Customer or merchant cancels at period end | `subscription.updated` and `subscription.canceled`, immediately | | Customer reverses the pending cancellation | `subscription.uncanceled` | | Period ends | `subscription.updated` and `subscription.revoked` | | Merchant revokes immediately | `subscription.updated`, `subscription.canceled` and `subscription.revoked` together | So `subscription.canceled` means "will end", and `subscription.revoked` means "has ended". Your win-back logic keys off both. ## Window 1: before the period ends Between `subscription.canceled` and the end of the period, the subscription can still be saved without a new checkout. Polar's [Managing subscriptions](https://polar.sh/docs/features/subscriptions/manage) page says you can uncancel any time before the end date, which reverts the scheduled cancellation and sends `subscription.uncanceled`. What to do in this window: 1. **Show the end date in your app,** with a "Keep my subscription" button that sets `cancel_at_period_end` back to `false` through the API. 2. **Send one reminder** a few days before `current_period_end`: what they lose and when, with the same button. 3. **Do not lead with a discount.** The customer still has access and already chose to leave once. Remind them of value first. ### Recording the reason Polar has native fields for this. The subscription carries `customer_cancellation_reason` and `customer_cancellation_comment`, and [Managing subscriptions](https://polar.sh/docs/features/subscriptions/manage) lists the reason values: `too_expensive`, `missing_features`, `switched_service`, `unused`, `customer_service`, `low_quality`, `too_complex` and `other`. Polar's guidance is to set them only with what the customer actually said, for example from a cancellation survey or a support conversation. It also warns that customers can see their cancellation comment in their purchase history, so never put internal notes there. If you cancel through your own app, pass the reason in the same `PATCH` that sets `cancel_at_period_end`. The [List Subscriptions endpoint](https://polar.sh/docs/api-reference/2026-04/subscriptions/list-subscriptions) can then filter by `customer_cancellation_reason`, which is exactly what a reason-based win-back campaign needs. ## Window 2: after the subscription is revoked Once revoked, the subscription is gone. Bringing the customer back means a new checkout. This is where Polar's discounts help. ### Discounts for returning subscribers Polar's [Discounts](https://polar.sh/docs/features/discounts) support three durations for subscriptions: - **Once:** the first invoice only. - **Repeating:** a set number of months (`duration_in_months`, required for this type; Polar says to multiply by 12 for yearly prices). - **Forever:** every renewal. A discount can have a code, 3 to 256 alphanumeric characters, that customers enter at checkout. Without a code, it can only be applied through the API. For a win-back email, a `repeating` discount ("40% off your first 3 months back") is usually clearer than `forever`. ### Discounts on subscriptions that are still running For window 1, Polar also lets you attach a discount to an existing subscription. The [Update Subscription reference](https://polar.sh/docs/api-reference/2026-10/subscriptions/update-subscription) says you set `discount_id`, the change applies from the next billing cycle, and `discount_id: null` removes it. That makes "stay and get 3 months at a lower price" possible without a new checkout, combined with uncancelling. ## A reason-based win-back sequence Polar's docs we used do not describe a built-in win-back or marketing email feature, so the sequence runs from your own email tool, triggered by `subscription.revoked`. ### Match the message to the reason | `customer_cancellation_reason` | What to send | |---|---| | `too_expensive` | A time-limited discount code, or a cheaper plan | | `missing_features` | A note when the feature ships; no discount needed | | `unused` | What changed since they left, and a lighter plan if you have one | | `switched_service` | One honest message on what you do differently, then stop | | `too_complex` | A short guide or an offer to set it up with them | | `customer_service`, `low_quality` | A personal reply from the founder or team lead, not a campaign | | `other` or empty | A short, generic check-in | ### Timing Three touches is enough: around 30, 60 and 90 days after revocation. Stop at the first reply, unsubscribe or new subscription (`subscription.created` for the same customer). ### Consent A former customer is not automatically someone who opted in to marketing. Check your consent basis for each region before sending, keep the message relevant to their reason, and include a one-click unsubscribe. ### Measure Track, by reason and by offer: how many revoked subscribers start a new subscription within 90 days, and how many cancelled subscribers uncancel before the period ends. Polar's [Analytics](https://polar.sh/docs/features/analytics) reports canceled and churned subscriptions separately, which helps you see both windows. ## Common mistakes - **Removing access on `subscription.canceled`.** The customer paid for the period and Polar keeps the subscription active until it ends. - **Writing internal notes in `customer_cancellation_comment`.** The customer can see it. - **Guessing the reason.** Polar asks that these fields come from the customer. A wrong reason sends the wrong win-back message. - **Fighting the portal.** Customers can always cancel there. Make the in-app path better instead: ask the reason, offer a fitting alternative, keep cancel one click away. ## Doing this with NoChurn Polar keeps the subscription, the checkout and the portal, and its cancel option stays as it is. NoChurn reads your Polar webhooks, adds a cancel flow in your app (reason, a fitting offer such as a discount, pause or plan change, and a one-click cancel that is always visible), and sends win-back emails at day 30, 60 and 90 based on the reason. Each customer gets a churn score from 0 to 100. Disputes stay with Polar as the merchant of record and are shown read only. See [NoChurn + Polar](/integrations/polar/). --- # How to prevent chargebacks on subscriptions before they happen Source: https://www.nochurn.sh/blog/prevent-subscription-chargebacks/ You can win a chargeback and still lose: the dispute counts toward your network ratios whether you win or not, it costs a fee, and it takes time. Stripe's [measuring disputes](https://docs.stripe.com/disputes/measuring) page puts it directly: all disputes, won or lost, count toward your dispute rate, so the best strategy is prevention. For subscription businesses, prevention is mostly about one thing: making sure the customer recognizes the charge, expected it, and had an easier way out than calling their bank. This guide goes through the levers in order of effort, with the card network rules behind them. Sources: Visa's [trial subscription rules](https://usa.visa.com/dam/VCOM/global/support-legal/documents/visa-new-subscription-rules-flier.pdf) and [free trial policy](https://usa.visa.com/dam/VCOM/global/support-legal/documents/subscription-merchants-visa-public.pdf), Mastercard's [subscription and negative option billing standards](https://www.mastercard.us/content/dam/public/mastercardcom/na/global-site/documents/subscription_recurring-payments-and-negative-option-billing-merchants.pdf), Stripe's [statement descriptors](https://docs.stripe.com/get-started/account/statement-descriptors), [dispute prevention](https://docs.stripe.com/disputes/get-started/prevention) and [accepting disputes FAQ](https://support.stripe.com/questions/accepting-disputes-faq) (all accessed November 2026). ## Why subscription customers dispute Before the fixes, the causes. Most subscription disputes fall into a few patterns: | What the customer thinks | What usually happened | Prevention lever | |---|---|---| | "I don't know this charge" | Descriptor does not match the brand | Descriptor | | "I forgot I signed up" | Trial converted, or annual renewal, without a reminder | Reminders | | "I cancelled" | Cancel path hard to find, or cancellation not confirmed | Easy cancel, confirmation | | "I asked for a refund and got nothing" | Slow or missing reply from support | Refund policy, response time | | "Someone used my card" | Real fraud, or a family member | Fraud checks, authentication | Each lever below addresses one row. ## 1. A descriptor customers recognize The statement descriptor is the text on the customer's bank statement. If it shows a legal entity name the customer has never seen, the charge looks like fraud. - Use the brand name customers know, not the holding company. - Add a short product or plan suffix if your processor allows it. Stripe supports a static prefix and a dynamic suffix within 22 characters for card payments. - Make sure the support phone number or URL associated with the descriptor works. The details, limits and examples are in [billing descriptors](/blog/billing-descriptor-chargebacks/). ## 2. Reminders before charges the customer may not expect The networks require some of these, and they work. **Trials and promotions.** Visa's rules require a reminder by email or SMS, with a link to cancel online, at least seven days before the first charge after a trial, introductory offer or promotional period ends, and when the terms of the agreement change. Mastercard's standards require a notice three to seven days before the end of a trial longer than seven days. **Long billing intervals.** Mastercard requires a notice before billing for subscriptions billed every six months or less frequently, such as annual plans. Stripe's [Mastercard guidance](https://support.stripe.com/questions/guidance-for-mastercard-recurring-billing-compliance-updates) recommends sending it 7 to 30 days before renewal. See [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/) for a full sequence. **What a good reminder contains:** - the amount and the date of the charge; - the plan and the billing interval; - the card that will be charged (brand and last four digits); - a direct link to cancel or change plan; - how the charge will appear on the statement. The last point is often forgotten and directly prevents "unrecognized" disputes. ## 3. Receipts after every charge A receipt after every renewal gives the customer a searchable record and a link to their account. Mastercard's standards describe it as best practice for all subscription merchants and as a requirement for merchants identified for at least four months in its chargeback monitoring program. Include the descriptor text, the next billing date and a cancel link. ## 4. Cancellation that is easier than a dispute If cancelling means finding a hidden menu, emailing support or calling, the bank's dispute button is the easier path. The customer then files a "cancelled recurring" dispute (Visa 13.2, Mastercard 4841), which Visa's [dispute guidelines](https://usa.visa.com/dam/VCOM/global/support-legal/documents/merchants-dispute-management-guidelines.pdf) say you should accept if the cardholder had withdrawn permission and you did not refund. What works: - **A cancel button the customer can find** in account settings, without contacting support. Mastercard's standards require an online cancellation method; Visa's trial policy compares the ease of cancelling to unsubscribing from an email list. - **A retention step that never blocks.** Offering a pause or a discount is fine; making the customer go through three screens before "cancel" works is not. Keep "cancel now" visible at every step. - **An immediate confirmation email** with the cancellation date and the end of access. That email is also your evidence if a dispute arrives anyway. - **Honor it.** A cancellation that does not stop the next charge is the most expensive bug in your billing system. See [cancel flow best practices](/blog/cancel-flow-best-practices/) and [click-to-cancel rules](/blog/click-to-cancel-rules/). ## 5. Refunds that are faster than the bank Many disputes are refund requests that went to the bank because the customer did not get an answer. A few practices help: - **Answer refund requests within a business day.** Even a "we're looking into it" stops some customers from going to the bank. - **Publish a refund policy** and show it at checkout. It sets expectations and is evidence later. - **Refund obvious mistakes without debate:** a renewal the customer clearly did not want, a double charge, a charge after a cancellation that failed on your side. - **Send a refund confirmation** with the amount and the expected delay before it appears on the statement. This prevents "credit not processed" disputes (Visa 13.6, Mastercard 4860). One important constraint: once a chargeback is open, you can no longer refund. Stripe's [dispute withdrawals FAQ](https://support.stripe.com/questions/dispute-withdrawals-faq) explains that the bank already returned the money. A refund only prevents a dispute if it comes first. ## 6. Pre-dispute tools from the networks Visa and Mastercard offer services that intercept disputes before they are filed. Stripe's [dispute prevention](https://docs.stripe.com/disputes/get-started/prevention) bundles them: | Tool | Network | What it does | |---|---|---| | Order Insights | Visa (Verifi) | The issuer looks up purchase details while the cardholder is asking about a charge | | Consumer Clarity | Mastercard (Ethoca) | Same idea for Mastercard | | Rapid Dispute Resolution | Visa (Verifi) | Rules that refund qualifying disputes automatically, for a fee per case | | Ethoca Alerts | Mastercard | Alerts that let you refund before a chargeback is filed | | Compelling Evidence 3.0 | Visa | Prior undisputed transactions can stop a fraud dispute | Stripe says disputes resolved through these pre-dispute products are excluded from Visa's VAMP count, which makes them worth considering if you are close to a [monitoring threshold](/blog/chargeback-ratio-monitoring-programs/). They cost money per case, so compare the fee with your average charge. ## 7. Fraud checks at signup Real fraud is a smaller share of subscription disputes than of retail ones, but it exists, and card testing on signup forms can produce bursts of fraud reports. - **Use your processor's fraud rules** to block obviously risky signups. - **Authenticate with 3D Secure** where it is required or risk is high. Authenticated payments can shift fraud liability to the issuer, and Mastercard's fraud program takes 3D Secure usage into account. - **Act on early fraud warnings.** On Stripe, a warning means the issuer has received a fraud report. Refunding small charges and cancelling the subscription often costs less than the dispute that follows. See [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/). - **Stop future renewals on any card reported as stolen.** ## 8. Log what you will need later Prevention fails sometimes. When it does, your evidence comes from records made at the time: terms accepted with timestamps, IP and device at each session, usage, cancel attempts, every email and support conversation. Recording them costs little; reconstructing them later is often impossible. See the [chargeback evidence checklist for SaaS](/blog/chargeback-evidence-checklist-saas/). ## A one-page checklist - [ ] Descriptor matches the brand; suffix shows the product. - [ ] Trial-end reminder at least seven days before the first charge, with a cancel link. - [ ] Renewal reminder for annual and semi-annual plans. - [ ] Receipt after every charge, with descriptor text and cancel link. - [ ] Cancel button in account settings; confirmation email; cancellation honored. - [ ] Refund requests answered within a business day; refund confirmation sent. - [ ] Pre-dispute tools evaluated against your dispute volume. - [ ] Fraud rules and 3D Secure on signup; early fraud warnings reviewed. - [ ] Usage, sessions and communications logged per customer. ## Doing this with NoChurn NoChurn's cancel flows keep a one-click cancel visible at every step, offer a pause, discount or plan change without blocking, and record every answer. The churn score flags risky signups from day one. On Stripe, early fraud warnings come with a one-click refund. When a dispute still arrives on Stripe or Braintree, NoChurn gathers the evidence automatically and drafts a reply with AI that a person reviews before it is sent. See [cancel flows](/#cancel) and [chargebacks](/#disputes). --- # How to raise subscription prices without a churn spike Source: https://www.nochurn.sh/blog/price-increase-churn/ A price increase is one of the few changes that lifts revenue from customers you already have. It is also one of the few changes that can make many of them cancel in the same week. The difference between the two outcomes is mostly preparation: knowing how much churn the increase can absorb, choosing who it applies to, giving proper notice and making sure the renewal charge actually goes through. This guide covers each step. All numbers are hypothetical. ## Step 1: do the break-even math Before anything else, work out how many customers you could lose and still come out ahead. ```text revenue after = customers × (1 − extra churn) × old price × (1 + increase) break-even extra churn = increase ÷ (1 + increase) ``` | Price increase | Break-even extra churn | |---|---| | 10% | 9.1% | | 20% | 16.7% | | 30% | 23.1% | | 50% | 33.3% | Example: a fictional company with 1,000 customers at $40/month raises the price to $48 (20%). Revenue stays flat if it loses 167 extra customers because of the increase. Lose fewer and revenue goes up. This is the ceiling, not the target. Customers who leave also stop referring others, stop expanding and may have left angry. Use the break-even only to judge whether an increase is reckless or comfortable. ### Count the payment failures too A higher amount can change how the bank treats a renewal. In Europe, a change in amount is one of the situations where an issuer may ask for authentication on a payment the customer is not present for; see [SCA and authentication-required renewals](/blog/sca-authentication-required-renewals/). Plan for a few extra failed renewals in the first cycle, and make sure the recovery emails link straight to a page where the customer can confirm. ## Step 2: decide who gets the new price | Option | What it means | When it fits | |---|---|---| | New customers only | Existing customers keep their price indefinitely | Small increase, or a very price-sensitive base | | Everyone, at renewal | Existing customers move at their next renewal after notice | The usual choice | | Everyone, with a delay | Existing customers move after 3 to 12 months | Large increase, or a loyal base you want to reward | | By plan or cohort | Only some plans or older cohorts move | Old prices far below current ones | Keeping old prices forever is simple but creates a growing list of legacy prices you have to maintain. A delay is often the better gift: customers get time to plan, and you get a single price list in the end. ## Step 3: give clear notice ### What the notice should say - The current price and the new price, per billing period. - The exact date the new price applies. - What changes for the customer, if anything (new features, same features). - How to change plan or cancel, with a direct link. Keep the reason short and honest. "We are raising prices because our costs have risen and we have added X and Y" is better than a paragraph about value. ### Rules we could verify - **California.** Changes from [AB 2863](https://dwt.com/insights/2024/10/ab-2863-updates-california-automatic-renewal-law) (summary by Davis Wright Tremaine, accessed November 2026), most in force since July 1, 2025, require notice between 7 and 30 days before a price change under an existing automatic renewal for California consumers, together with how to cancel. - **App Store.** Apple notifies subscribers of a price increase. Subscribers must consent before renewal when they are in a region that requires it, when the increase exceeds both 50% and roughly US$5 per period (US$50 per year for annual plans), or when they already had an increase in the past 12 months; otherwise Apple sends a notice only. Subscribers who do not consent lose the subscription at the end of the current period. You can also keep existing subscribers on their current price ([Apple: manage pricing for auto-renewable subscriptions](https://developer.apple.com/help/app-store-connect/manage-subscriptions/manage-pricing-for-auto-renewable-subscriptions/) and [price increase thresholds](https://developer.apple.com/help/app-store-connect/reference/in-app-purchases-and-subscriptions/auto-renewable-subscription-price-increase-thresholds)). - **Google Play.** By default, a price increase for existing subscribers is opt-in: users must accept it before the first higher charge, or Google Play cancels the subscription. Opt-out increases exist only in certain countries, for eligible developers, at most once per base plan per country in 365 days, and with an in-app notice at least 30 days ahead ([Play Billing: change subscription prices](https://developer.android.com/google/play/billing/price-changes)). Other jurisdictions have their own rules on contract changes, and B2B contracts may have notice clauses of their own. Check your terms and your markets. The store rules have a direct churn consequence: on opt-in increases, a customer who simply ignores the notice is cancelled. Silence counts as no. Tell those customers yourself, in your app and by email, before the store's own notices start. ## Step 4: apply the change in billing On Stripe, you change an existing subscription's price by updating its subscription item to the new price. Stripe's guide on [changing the price of existing subscriptions](https://docs.stripe.com/billing/subscriptions/change-price) covers it. Two details matter for a price increase: - **Proration.** The default `proration_behavior` is `create_prorations`, which charges the difference for the rest of the current period. For an increase that should start at renewal, set it to `none`: the customer pays the old price until the next renewal and the new price from then on. - **Timing.** To move many customers at their own renewal dates, use subscription schedules or update each subscription shortly before its renewal, after the notice period. Test on a few internal subscriptions first and check the next invoice preview before touching real customers. ## Step 5: give customers an alternative to cancelling A price increase brings a wave of "too expensive" cancellations in the weeks around it. Have the right offer ready: - **A cheaper plan.** For customers who use a fraction of the product, a smaller plan at or below their old price keeps them. See [downgrade offers](/blog/downgrade-offers/). - **An annual plan at the old monthly equivalent.** Some customers will commit for a year to lock in a price. - **A pause.** For seasonal or occasional users. Avoid a blanket "keep your old price if you threaten to cancel" discount. It teaches customers that the cancel button negotiates prices. ## Step 6: measure it properly Compare the months after the increase with the months before, by cohort and by plan: | Metric | Why | |---|---| | Voluntary churn, "too expensive" reason | The direct effect | | Failed renewals at the new price | Authentication and bank effects | | Downgrades | Customers who stayed but pay less | | Net revenue retention | The overall result | | Support tickets about the price | Early warning | If you can, roll out to one segment first and keep a comparable segment on the old price for a cycle. That is the only clean way to separate the increase's effect from seasonality. ## Checklist - [ ] Break-even churn computed. - [ ] Who moves, and when, decided and written down. - [ ] Notice timing checked for your markets and stores. - [ ] Notice email and in-app message written, with a link to change plan or cancel. - [ ] Billing change tested with proration set as intended. - [ ] Downgrade and pause offers ready in the cancel flow. - [ ] Recovery emails ready for failed renewals. - [ ] Dashboard compares before and after by cohort. ## Doing this with NoChurn NoChurn helps around a price change without touching your prices. Its cancel flows ask for the reason and show one offer per reason (a discount, a pause or a plan change), with one-click cancel always visible, as a hosted modal or through a headless API. Failed renewals on Stripe get smart retries timed to the decline reason and payday, AI-written recovery emails you can review and a hosted card update page. Customers who leave get win-back emails at day 30, 60 and 90 by cancel reason, and each customer has a churn score from 0 to 100, updated on every change. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # How to add a cancel flow to Recurly Source: https://www.nochurn.sh/blog/recurly-cancel-flow/ A cancel flow is the step between a customer clicking "Cancel" and the cancellation itself: ask why, make one offer that fits the answer, and cancel cleanly if they still want to leave. This guide explains how cancellation works in Recurly Subscriptions, which save tools Recurly already offers, and how to build your own flow on its API. It sticks to Recurly's own documentation: [expire or cancel a subscription](https://docs.recurly.com/recurly-subscriptions/docs/expire-subscription), the [subscription management guide](https://docs.recurly.com/recurly-subscriptions/docs/managing-subscription-methods-guides), the [subscription lifecycle webhook guide](https://docs.recurly.com/recurly-subscriptions/docs/post-authorization-webhook-guide), [subscription notifications](https://docs.recurly.com/recurly-subscriptions/docs/subscription-notifications), [Hosted Account Management](https://docs.recurly.com/docs/hosted-account-management), [coupons](https://docs.recurly.com/recurly-subscriptions/docs/coupons), [change subscription](https://docs.recurly.com/recurly-subscriptions/docs/change-subscription) and [Recurly Engage Cancel Save](https://docs.recurly.com/recurly-engage/docs/cancel-save) (all accessed November 2026). Recurly also sells Recurly Commerce, a separate product with its own portal; this guide is about Recurly Subscriptions unless stated. ## Cancel, terminate, reactivate Recurly distinguishes two ways to end a subscription ([expire or cancel](https://docs.recurly.com/recurly-subscriptions/docs/expire-subscription)). | | Cancel | Terminate | |---|---|---| | When it ends | At the next bill date (`timeframe: bill_date`) or at the end of the term (`timeframe: term_end`) | Immediately, mid-cycle | | State | `canceled` until `expires_at`, then `expired` | `expired` right away | | Access | The customer keeps access until expiry | Ends now | | Refund | Not applicable | `none` (default), `partial` (prorated for the time left) or `full` (the last charge) | | Reversible | Yes, reactivate before expiry | No | Two details matter for a cancel flow: - **Bill date vs term end.** For a plan with a multi-period term, `bill_date` stops at the next billing event, while `term_end` keeps billing until the term is over. Pick the one that matches what you promised the customer when they signed up. - **Reactivation.** A canceled subscription can be reactivated until it expires, so it renews again at the end of the current cycle. Once it has expired, it cannot be reactivated and a new subscription is needed. In SCA regions, Recurly notes the customer may have to authenticate their stored billing information again before reactivation. Terminating also refunds only the last invoice; if that invoice is credit-only, Recurly ignores the refund request. For a customer who simply wants to stop, cancel rather than terminate. ## Where customers cancel today ### Hosted Account Management Recurly's hosted account pages can include a cancel button. Per the [Hosted Account Management docs](https://docs.recurly.com/docs/hosted-account-management), you enable it in the Admin Console under Configuration › Hosted Page Settings, "Cancel subscriptions" under Customer Options. Customers can then cancel straight from their hosted account page. Recurly's docs do not describe a reason survey in that path. ### Recurly Engage Cancel Save Recurly sells its own save tool in Recurly Engage. Per the [Cancel Save guide](https://docs.recurly.com/recurly-engage/docs/cancel-save), you start from a pre-built "Cancel Survey with Offers" guide, set a CSS selector on your cancel button as the trigger, and branch survey answers to actions: Recurly's example sends "too expensive" to a save offer and "technical issues" to support. Live Preview shows the design but does not run the flow, so Recurly suggests testing with a test users segment. Recurly says the integration with Recurly.js, Hosted Account Management and Recurly Checkout is enabled automatically, and notes the feature may not be included in Starter or Pro plans. ### Recurly Commerce If you sell through Recurly Commerce rather than Recurly Subscriptions, it has [cancellation flows](https://docs.recurly.com/recurly-commerce/docs/cancellation-and-churn-prevention-flows) configured in its Customer Portal: a multi-step survey, a retention action per answer (discount, pause, extended subscription or support), assigned to a plan before it goes live. If one of these fits your plan and your needs, use it. The rest of this guide is for when you want the flow in your own app, with your own design and offers. ## The offers Recurly's API supports ### Coupon Recurly [coupons](https://docs.recurly.com/recurly-subscriptions/docs/coupons) can last forever, for a single use, for a limited time, or for a set number of billing periods, and Recurly recommends billing-period coupons over time-based ones. For retention, two options help: - **Bulk unique codes**: one-time codes generated in batches, so a save offer cannot be shared. Each code can be redeemed once by default. - **Plan restrictions**: a coupon applies to all plans by default; restrict it to the plans where the offer makes sense. ### Plan change A downgrade is a [subscription change](https://docs.recurly.com/recurly-subscriptions/docs/change-subscription) that can apply immediately, at the next bill date, or at term renewal. Recurly keeps only one pending change; a second one replaces the first. For "too expensive", a change at the next bill date avoids surprise proration. ### Pause Recurly can pause a subscription for a number of billing cycles from the next bill date. It has enough rules of its own (active subscriptions only, annual plans, coupons that keep running) that we cover it in [how to pause subscriptions in Recurly](/blog/recurly-pause-subscriptions/). One rule to remember here: Recurly says customers cannot pause from Hosted Account Management, so a pause offer has to come from your own flow, your support team, or Recurly Commerce's portal. ## Building the flow 1. **Route "Cancel" in your app to your flow.** If Hosted Account Management also shows a cancel button, decide whether to keep it. Keeping it is honest and simple; it just means some customers skip the flow. 2. **Ask why.** A short list of reasons plus "Other". Store the answer with the subscription UUID. 3. **Show one offer that fits.** "Too expensive": a billing-period coupon or a cheaper plan at the next bill date. "Not using it right now": a pause. "Missing a feature" or "Something is broken": a reply from a person. 4. **Keep "Cancel now" visible on every step.** One click finishes the cancellation, with no offer to accept first. 5. **Apply the result through the API.** Apply the coupon, schedule the plan change, pause, or cancel with the `timeframe` you chose. 6. **Confirm the end date.** Read `expires_at` from the subscription Recurly returns, and show it. 7. **Offer to undo.** Until the subscription expires, a "Keep my subscription" button can call the reactivate endpoint. ## Webhooks to listen to The [lifecycle webhook guide](https://docs.recurly.com/recurly-subscriptions/docs/post-authorization-webhook-guide) describes the path: a cancellation sends a **canceled** notification; it is followed either by **reactivated**, if the customer comes back before expiry, or by **expired** when `expires_at` is reached. Termination and immediate refunds go straight to expired. Recurly's pages use more than one naming style for these events: the [subscription notifications](https://docs.recurly.com/recurly-subscriptions/docs/subscription-notifications) page uses event types such as "canceled" and "expired", while other pages use older names such as `canceled_subscription_notification` and `expired_subscription_notification`. Check the names in your own payloads. Recurly also advises treating webhooks as alerts: confirm the current state through the API, accept duplicates, and handle events that arrive out of order. ## Measuring the flow Recurly's [churned subscriptions export](https://docs.recurly.com/docs/subscriptions-churned) has an `expiration_reason` column (for example Canceled or Non-payment) that separates voluntary from involuntary churn. Combine it with the reasons your flow collected, and with how many customers accepted each offer and were still subscribed a few months later. ## Doing this with NoChurn NoChurn connects to Recurly with a private API key and follows its webhooks. It adds a cancel flow with reasons, offers that become a coupon, a pause or a plan change on the Recurly subscription, and a one-click cancel that is always visible, hosted or headless through the API. It also sends win-back emails at day 30, 60 and 90 based on the cancel reason and computes a churn score from 0 to 100. Invoicing, the charge itself and your gateway stay in Recurly. NoChurn is free under $300 MRR, with every feature on every plan. See [NoChurn + Recurly](/integrations/recurly/). --- # Chargebacks with Recurly: what Recurly shows and where you answer Source: https://www.nochurn.sh/blog/recurly-chargebacks/ Recurly bills your customers, but the card payment itself runs through a gateway such as Stripe or Adyen. When a customer disputes a charge, that split decides everything: the dispute is opened and answered at the gateway, and Recurly records the consequences on the invoice and the subscription. This guide explains what Recurly shows, what it does on its own, and where you actually respond. It sticks to Recurly's own documentation: [chargeback management for cards](https://docs.recurly.com/recurly-subscriptions/docs/chargeback-management-for-cards), [chargebacks and late failures for direct debit](https://docs.recurly.com/docs/chargebacks-for-direct-debit), the [Stripe gateway page](https://docs.recurly.com/recurly-subscriptions/docs/stripe), the [transactions dashboard](https://docs.recurly.com/recurly-subscriptions/docs/transactions-dashboard) and [subscription notifications](https://docs.recurly.com/recurly-subscriptions/docs/subscription-notifications) (all accessed November 2026). Where Recurly's docs are silent, we say so. ## Who does what | Step | Where it happens | |---|---| | The cardholder disputes the charge | Their bank, then the card network | | The dispute is opened and you are notified | Your gateway | | You submit evidence or accept | Your gateway, in its dashboard or API | | The bank decides | Bank and network | | The invoice and subscription are updated | Recurly, if chargeback management is on | Recurly's [chargeback page](https://docs.recurly.com/recurly-subscriptions/docs/chargeback-management-for-cards) is explicit about the response: the merchant disputes or accepts the chargeback through their gateway. Recurly does not submit evidence for you. ## Recurly's native chargeback management for cards ### Availability Per Recurly's docs, native card chargeback management is in **early access**: you ask Recurly Support or your account manager to enable it. It is available on three gateways: - **Adyen**: enable the Adyen webhook types `CHARGEBACK`, `SECOND_CHARGEBACK` and `DISPUTE_DEFENSE_PERIOD_ENDED`. Recurly notes that some Adyen statuses only arrive after you act in Adyen's dashboard. - **Chase Orbital**: Chase gives Recurly access to its chargeback file reports using Recurly's Partner ID; nothing is set up inside Recurly. - **Stripe**: chargeback status and reason code appear in the Recurly Admin UI, and Recurly refers you to Stripe's reason codes for their meaning. Recurly's [Stripe page](https://docs.recurly.com/recurly-subscriptions/docs/stripe) says the webhook events it uses need no extra configuration in Stripe. For other gateways, the docs we found do not describe native chargeback handling, and at least one gateway page (Ebanx) says chargebacks are not reflected. Check your gateway's page in Recurly's docs. ### What Recurly does, and when Recurly acts when the chargeback reaches a **final state**: accepted, lost or expired. At that point it receives a "Chargeback Completed" event from the gateway and: 1. creates an **external refund invoice**, with an origin of Chargeback; 2. creates a **chargeback transaction**, which shows with the status Chargeback in the [transactions dashboard](https://docs.recurly.com/recurly-subscriptions/docs/transactions-dashboard); 3. **expires the associated subscription**. Another part of Recurly's docs says affected subscriptions "can be" expired automatically depending on your settings, so check how yours are configured. Two consequences follow. First, nothing changes in Recurly while the dispute is open; the subscription keeps renewing unless you act. Second, Recurly's docs we found do not describe what happens in Recurly when you **win** a dispute, since the actions are tied to accepted, lost and expired. If you win, check the invoice and subscription yourself. ### One chargeback system at a time Recurly supports third-party chargeback tools as an alternative, but only one system can be active per site. When a third-party tool is enabled, Recurly stops processing gateway chargeback events for the supported gateways. Choose one source of truth. ## Direct debit is different For bank debits, Recurly's [direct debit page](https://docs.recurly.com/docs/chargebacks-for-direct-debit) describes chargebacks and late failures, with GoCardless as the main example and two modes: - **Default mode**: when Recurly receives the chargeback webhook, it creates a refund transaction itself. - **Manual mode**: Recurly sends a webhook notification for each chargeback and takes no action; you decide what to do. In this mode the Chargeback status filter on the transactions page returns nothing, because no chargeback refund transactions are created. Recurly notes that the gateway's Webhook Options must be enabled for automated handling to work. In both modes it sends a webhook for every chargeback event. ## Where you answer: the gateway Since the response happens at the gateway, your process there decides the outcome. If your gateway is Stripe, we explain the dispute lifecycle, evidence fields and deadlines in [how to win chargebacks on Stripe](/blog/win-chargebacks-stripe/). Whatever the gateway, the evidence for a subscription business comes largely from places Recurly can help with: - **Subscription history**: when the customer signed up, what plan, how many renewals they paid without dispute. Recurly's account and invoice pages hold this. - **Cancellation record**: if the dispute says "I cancelled", Recurly has `canceled_at` and `expires_at` for the subscription, and the canceled notification you received. If there is no cancellation, that is evidence too. - **Terms shown at signup**, including how to cancel and when renewals happen. - **Emails sent**: invoice, renewal or dunning emails that went to the customer, from Recurly or from you. - **Usage**: logins and activity in your product during the period charged. This lives in your systems, not in Recurly. - **Support conversations** with the customer, from your help desk. ## A process that works 1. **Know your gateway's support.** Check whether your gateway is one of the three with native handling, and whether it is turned on for your site. 2. **Get notified at the gateway, not at the end.** Recurly acts at the final state; by then the evidence deadline has passed. Subscribe to dispute notifications in the gateway itself. 3. **Decide what to do with the subscription right away.** If the cardholder says the charge was not theirs, the next renewal on that card will probably be disputed too. Consider cancelling the subscription in Recurly while the dispute is open, rather than waiting for Recurly to expire it. 4. **Gather evidence from Recurly and your own systems**, then respond at the gateway before its deadline. 5. **Reconcile at the end.** When Recurly creates the refund invoice and chargeback transaction, check that the subscription state matches what you decided, and handle won disputes by hand. 6. **Look for patterns.** "Subscription cancelled" disputes point at a cancel process that is hard to find or not honored; "unrecognized" disputes point at your payment descriptor or missing renewal reminders. ## Doing this with NoChurn With Recurly, disputes come from the gateway behind it. If that gateway is Stripe or Braintree, NoChurn reads the dispute, gathers evidence automatically (cancel flow answers, emails NoChurn sent, usage you send by API, and conversations from a connected help desk, read only), and drafts a reply with AI that is sent to the gateway only after a person on your team reviews it. The bank's decision, fees and deadlines stay with the gateway and the networks, and invoices and subscriptions stay in Recurly. NoChurn also adds cancel flows with a one-click cancel always visible, which helps prevent "I cancelled" disputes. See [NoChurn + Recurly](/integrations/recurly/). --- # How to set up dunning in Recurly Source: https://www.nochurn.sh/blog/recurly-dunning/ Recurly has one of the more complete native dunning setups among subscription billing platforms. Retries, emails, end-of-cycle actions and customer billing pages are all built in, and most of the work is choosing sensible settings and wiring the right webhooks into your app. This guide walks through each piece and gives you a setup checklist you can apply today. Everything Recurly-specific here comes from Recurly's own documentation: [Dunning campaigns](https://docs.recurly.com/recurly-subscriptions/docs/dunning-management), [Intelligent retries](https://docs.recurly.com/docs/retry-logic), [Static retries](https://docs.recurly.com/recurly-subscriptions/docs/static-retries), [Dunning 101: Understanding dunning windows](https://docs.recurly.com/recurly-subscriptions/docs/navigate-retain-dunning-101-dunning-windows), [Hosted account management](https://docs.recurly.com/docs/hosted-account-management) and the [webhooks reference](https://developers.recurly.com/reference/webhooks/) (all accessed November 2026). Recurly also sells a separate product, Recurly Commerce, with its own dunning settings; this guide covers Recurly Subscriptions. ## How Recurly splits the work: retries and dunning Recurly treats two things separately: - **Retries** decide when a declined charge is attempted again. - **Dunning** decides what the customer hears, for how long, and what happens to the invoice and subscription at the end. Both run on the same invoice at the same time, but you configure them in different places. Keeping that split in mind makes the rest of the settings easier to reason about. ## Retries: Intelligent Retries and static retries ### Intelligent Retries According to the [Intelligent retries documentation](https://docs.recurly.com/docs/retry-logic), Recurly uses a machine learning model to choose when to retry declined recurring card payments. It focuses on soft declines (such as insufficient funds). The documented limits: - Retries stop at **20 total transaction attempts** or **60 days from invoice creation**, whichever comes first. - Intelligent Retries does **not** apply to direct debit methods such as ACH and SEPA. Recurly documents those separately under [direct debit retries](https://docs.recurly.com/recurly-subscriptions/docs/sepa-retries). - Hard declines are generally treated as final and are not retried automatically, with a few documented exceptions, for example when the customer or the Account Updater changes the billing information. One thing to check in your own account: a Recurly [changelog entry from August 2026](https://docs.recurly.com/recurly-subscriptions/v2021-02-25/changelog/august-4-2026-recurly-subscriptions-management) describes soft declines being retried up to 20 times per 30-day period to align with card network rules. That wording differs from the 60-day window on the main page, so confirm which limit applies to you with Recurly before you rely on either. ### Static retries Recurly also documents a non-ML option, [static retries](https://docs.recurly.com/recurly-subscriptions/docs/static-retries), driven by gateway decline codes and merchant advice codes. It stops after 7 transaction declines, 20 total attempts or 60 days since invoice creation, whichever comes first, or earlier if the dunning cycle ends first. Whichever logic you use, retries never outlast the dunning cycle. If your dunning window is short, it caps your retries too. ## Dunning campaigns and cycles A **dunning campaign** is the set of rules Recurly applies to an unpaid invoice. Every site has a default campaign, and on eligible plans you can create additional campaigns and assign them to specific plans or accounts. The [dunning campaigns page](https://docs.recurly.com/recurly-subscriptions/docs/dunning-management) notes that multiple campaigns require a Professional or Elite plan. Campaigns live under Configuration, then Dunning Management. Dunning settings are versioned, so editing a campaign does not change invoices already in dunning. Each campaign contains up to three **cycle types**, each with its own schedule and emails: | Cycle type | Applies to | Default email template | |---|---|---| | Payment Declined | Automatically collected invoices that fail | Payment Declined | | Invoice Past Due | Manually collected invoices past their net terms | Invoice Past Due | | Post-Trial Payment Declined | Invoices that fail right after a free trial | Post-Trial Payment Declined | For manual invoices, the dunning period starts the day after the invoice exceeds its net terms. ### How long should a cycle be? Recurly's [dunning windows guide](https://docs.recurly.com/recurly-subscriptions/docs/navigate-retain-dunning-101-dunning-windows) recommends: - **Monthly billing:** a 27-day window, so the cycle ends before the next invoice, even in February. - **Quarterly and annual billing:** about 60 days. - **Weekly billing:** 7 days. These are recommendations, not hard limits. The idea behind them is sound: if a monthly cycle runs longer than a month, a second invoice lands on top of the first one, and you are now chasing two unpaid invoices from a customer who may never return. ### What happens at the end of the cycle For each cycle you choose what happens to the invoice and subscription if the customer has not paid. By default Recurly marks the invoice **failed**. You can also expire the subscription, keep it active, or set invoices to never fail automatically, which leaves them past due indefinitely. A few behaviours from Recurly's support articles that often surprise teams: - **Subscription state and invoice state are separate.** A subscription can be active while its invoice is past due ([support article](https://support.recurly.com/hc/en-us/articles/46649114797204-Why-Is-a-Subscription-Active-but-the-Invoice-Is-Past-Due)). Base access decisions on the invoice too, not only the subscription. - **Failing an invoice does not cancel the subscription.** If you want billing to stop, cancel the subscription separately ([support article](https://support.recurly.com/hc/en-us/articles/46251733087508-Subscription-Behavior-After-Dunning-Cycle-Ends)). - **Cancelling a subscription does not stop dunning on open invoices.** Use Stop Collection on the invoice for that ([support article](https://support.recurly.com/hc/en-us/articles/360027406932-Does-Canceling-a-Subscription-Stop-Dunning-on-Open-Invoices)). - There is no native pause option in the dunning configuration. ## Dunning emails Each step of a cycle can send an email. Recurly ships base templates (Payment Declined, Invoice Past Due, Post-Trial Payment Declined and Subscription Expired for Non-Payment) that cannot be deleted, and you can create your own and attach them to campaign steps. The default Payment Declined email already links the customer to their [hosted account management page](https://docs.recurly.com/docs/hosted-account-management). Each account has two hosted URLs: an Account Management URL that signs the customer in, and an Edit Billing Information URL that opens only the billing form. If you host your own billing page, you can edit the template to point there instead, using the account's hosted login token from the API. A sensible email plan for a monthly campaign: | Day | Email | Goal | |---|---|---| | 0 | Payment declined | Inform, one clear link to update billing | | 3 | Reminder | Restate the link, say what happens next | | 10 | Reminder | Short, mention access is at risk | | 20 | Final notice | Give the exact date the subscription ends | | End | Expired for non-payment | Confirm the end, offer a way back | Keep each email short and focused on the billing link. Do not repeat the raw decline reason to the customer. ## Billing updates trigger an immediate retry This is one of the most useful native behaviours. According to Recurly's docs, when a customer updates billing information, Recurly retries collection on all overdue invoices for that account. This applies to hard declines too: a new card is the one event that makes a hard-declined invoice worth retrying. For direct debit, switching to a new bank account resets the retry counter. In practice, this means your dunning emails do not need a separate "pay now" step. Getting the customer to the billing form is the whole job. ## Webhooks to listen to Recurly's [webhooks reference](https://developers.recurly.com/reference/webhooks/) and the dunning documentation list the events that matter during dunning. Which ones you receive depends on your site configuration: | Event | When it fires | What to do in your app | |---|---|---| | `failed_payment` | After each failed payment | Flag the account, show an in-app banner | | `successful_payment` | After a successful payment | Clear the flag, restore access | | `new_dunning_event` | When invoices enter and remain in dunning | Track dunning state per account | | `charge_invoice.past_due` | A charge invoice becomes past due (sites with credit invoices) | Start your own reminders if any | | `charge_invoice.failed` | A charge invoice fails, directly or at the end of dunning | Decide on access, stop reminders | | `subscription_expired` | Recurly expires a subscription, including for non-payment | Remove access | Sites without credit invoices receive Recurly's legacy invoice notifications instead, with different names. Check which set your site sends before writing your handlers. ## A setup checklist 1. **Pick your retry logic.** Intelligent Retries for most card businesses; check how direct debit is retried if you accept ACH or SEPA. 2. **Set cycle length by billing frequency.** Start from Recurly's 27-day (monthly) and 60-day (annual) recommendations. 3. **Choose the end-of-cycle action deliberately.** Decide whether the subscription expires or stays active, and whether invoices fail. Write it down so support knows. 4. **Write the emails.** One link per email, to the Edit Billing Information page or your own billing form. 5. **Add a post-trial campaign** if you run free trials. The first charge after a trial fails differently from a renewal: the customer has never paid you. 6. **Wire the webhooks.** Base access on invoice state, not only subscription state. 7. **Add an in-app banner** for logged-in customers with a past due invoice. Emails are easy to miss; the product is not. 8. **Review monthly.** Look at invoices that failed at the end of dunning and the decline codes behind them. ## Doing this with NoChurn Recurly's native retries and dunning are solid, and NoChurn does not replace them: retries, invoicing and the charge itself stay in Recurly. NoChurn connects with a Recurly API key, follows Recurly webhooks and adds AI-written recovery emails that you review before they go out, with a link for the customer to update billing info. It also covers what dunning does not: cancel flows with reasons and offers (a coupon, a pause or a plan change on the Recurly subscription) and a one-click cancel button that is always visible, win-back emails at day 30, 60 and 90 based on the cancel reason, and a churn score from 0 to 100. Chargebacks come from the gateway behind Recurly; with Stripe or Braintree, NoChurn gathers the evidence and drafts a reply for you to review. See [NoChurn + Recurly](/integrations/recurly/). --- # How to pause subscriptions in Recurly Source: https://www.nochurn.sh/blog/recurly-pause-subscriptions/ A pause is often the right offer for a customer who wants to cancel because they will not use the product for a while: they keep their account and you keep the customer. Recurly supports pausing natively, but it has a set of rules that are easy to miss, especially on annual plans and with coupons. This guide explains how pausing works in Recurly Subscriptions and how to offer it well. It sticks to Recurly's own documentation: [pause subscription](https://docs.recurly.com/recurly-subscriptions/docs/pause-subscription), [pause subscriptions: things to consider](https://docs.recurly.com/recurly-subscriptions/docs/navigate-retain-subscription-pause-considerations), the [subscription management guide](https://docs.recurly.com/recurly-subscriptions/docs/managing-subscription-methods-guides), [subscription notifications](https://docs.recurly.com/recurly-subscriptions/docs/subscription-notifications), the [subscription lifecycle webhook guide](https://docs.recurly.com/recurly-subscriptions/docs/post-authorization-webhook-guide) and the [webhooks overview](https://docs.recurly.com/recurly-subscriptions/docs/overview-webhooks) (all accessed November 2026). Recurly Commerce, a separate product, has its own pause settings; this guide is about Recurly Subscriptions. ## How a pause works You pause through the Pause Subscription endpoint with `remaining_pause_cycles`, the number of billing cycles to skip ([pause subscription](https://docs.recurly.com/recurly-subscriptions/docs/pause-subscription)). Recurly's examples use 10, which freezes billing for ten cycles. The mechanics: 1. **It starts at the next billing date.** Recurly does not support mid-cycle pauses. The customer keeps the period they already paid for. 2. **Each skipped renewal counts down.** At every billing date during the pause, `remaining_pause_cycles` drops by one and Recurly sends a renewal-skipped notification. 3. **It ends on its own.** When the count reaches zero, the subscription resumes: Recurly starts a new billing cycle and generates an invoice immediately, charged to the stored payment method if collection is automatic. 4. **You can end it early.** Admins can resume from the subscription or account page, and the API has a resume endpoint. Resuming early also starts a new billing cycle with an immediate invoice. There is no separate "pause indefinitely" setting. Recurly's own [pause notes](https://docs.recurly.com/recurly-subscriptions/docs/navigate-retain-subscription-pause-considerations) mention that some merchants set a very high cycle count instead. The docs we found do not state a maximum. ## What cannot be paused Recurly's [considerations page](https://docs.recurly.com/recurly-subscriptions/docs/navigate-retain-subscription-pause-considerations) lists the limits: | Situation | What Recurly says | |---|---| | Trial, canceled, expired or failed subscriptions | Cannot be paused; only active subscriptions can | | Customer in dunning or with past-due invoices | Resolve that first | | A pause already scheduled or running | Concurrent pauses are not supported; one must end first | | Immediate subscription change during a pause | Cancels the pause | | Usage-based add-ons | Usage logged before the pause is invoiced on the pause date; no usage can be logged during the pause | The last two matter in practice. If a support agent upgrades a paused customer, or your app makes an immediate change, the pause disappears. And if you bill usage, check that nothing in your product logs usage for paused accounts. ## Annual plans: postpone instead A pause skips whole billing cycles. On an annual plan, one cycle is a year. Recurly's example: a customer six months into an annual plan asks for a one-month break; pausing one cycle schedules a full one-year pause starting at the next annual renewal. For short breaks on annual plans, Recurly recommends postponing the next bill date instead, using the Modify (update) Subscription endpoint. That extends the current period rather than skipping a year. ## Coupons keep running Recurly says coupons are not paused with the subscription: their duration keeps running during the pause. If you saved a customer with "50% off for three months" and they then pause for three months, the discount may be used up before they are billed again. Either offer the discount after the pause, or choose one offer, not both. ## Other side effects - **Term dates.** Recurly notes that term renewal dates do not update during a pause. - **Reporting.** Paused subscriptions count as active in Recurly analytics but add no MRR, since no invoices are generated. Track them separately when you look at retention. - **SCA regions.** Recurly's pages advise resuming through the API with proper customer authentication in SCA regions rather than from the Admin Console. The two pages that mention it do not describe the issue identically, so test resume in your region before you rely on it. ## Who can pause Recurly's docs say customers **cannot** pause or resume their own subscription from Hosted Account Management. That page shows the paused status, but the pause itself has to come from: - **your support team**, in the Admin Console; - **your own app or account page**, through the pause and resume endpoints, which is the only self-serve option in Recurly Subscriptions; - **Recurly Commerce**, whose Customer Portal has a pause toggle, if you sell through that product. If you want pause to be part of a cancel flow, you need to build that step or use a tool that does. ## Webhooks Recurly sends notifications for each stage of a pause ([subscription notifications](https://docs.recurly.com/recurly-subscriptions/docs/subscription-notifications)): a pause scheduled, a pause modified, a pause canceled (the pause fields go back to null), the subscription paused, each skipped renewal, and the subscription resumed, sent when it goes from paused back to active with a new billing cycle. Recurly's pages name these events in different ways. The notifications reference uses titles such as "Scheduled subscription pause" and "Subscription pause canceled", the [lifecycle guide](https://docs.recurly.com/recurly-subscriptions/docs/post-authorization-webhook-guide) uses identifiers such as `pause.scheduled` and `renewal.skipped`, and another page uses `subscription.paused` and `subscription.resumed`. Check the names in the payloads your account actually receives. Recurly also says webhooks are configured in the Admin Console, not by API, that you should confirm state through the API before updating your systems, and that your endpoint must accept duplicates and out-of-order events. ## Offering a pause well 1. **Offer it for the right reason.** "I won't use it for a while", "seasonal business", "budget freeze until next quarter". It is a poor answer to "the product doesn't do what I need". 2. **Check eligibility first.** Only show the offer for active, non-trial subscriptions that are not in dunning and have no pause scheduled. 3. **Choose the right tool for the plan.** Pause cycles for monthly plans; postpone the next bill date for short breaks on annual plans. 4. **Say exactly what happens.** "Your subscription is paused from 12 December for 2 months. You will be billed again on 12 February." Read the dates from Recurly's response. 5. **Remind them before billing resumes.** Resuming creates an invoice right away. Send a reminder a few days before, with a link to cancel if they no longer need the product. 6. **Keep cancel visible.** A pause offer sits next to "Cancel now", never in its place. 7. **Track what happens after.** Look at how many paused customers resume and keep paying, and how many cancel at the end. ## Doing this with NoChurn NoChurn's cancel flow can offer a pause, alongside a coupon or a plan change, and applies the accepted offer to the Recurly subscription; a one-click cancel stays visible at every step, hosted or headless through the API. It follows Recurly's webhooks, so customers who cancel later get win-back emails at day 30, 60 and 90 based on their reason, and the 0–100 churn score takes their history into account. Billing, invoicing and the resume charge stay in Recurly. NoChurn is free under $300 MRR. See [NoChurn + Recurly](/integrations/recurly/). --- # How to win back churned customers on Recurly Source: https://www.nochurn.sh/blog/recurly-win-back/ Customers who cancelled already know your product, which makes them some of the easiest people to sell to again, if you ask at the right time with the right offer. This guide explains what Recurly gives you to run win-back: the window before expiry, the data on why customers left, coupons built for one-off offers, and how a returning customer starts again on their existing account. It sticks to Recurly's own documentation: [expire or cancel a subscription](https://docs.recurly.com/recurly-subscriptions/docs/expire-subscription), the [subscription lifecycle webhook guide](https://docs.recurly.com/recurly-subscriptions/docs/post-authorization-webhook-guide), [subscription notifications](https://docs.recurly.com/recurly-subscriptions/docs/subscription-notifications), the [churned subscriptions export](https://docs.recurly.com/docs/subscriptions-churned), Recurly's support article on [finding reactivation MRR](https://support.recurly.com/hc/en-us/articles/360041810792-How-to-Find-Your-Reactivation-MRR-Using-Exports), [coupons](https://docs.recurly.com/recurly-subscriptions/docs/coupons), [bulk unique coupons](https://docs.recurly.com/recurly-subscriptions/docs/bulk-unique-coupons), [multiple subscriptions](https://docs.recurly.com/docs/multiple-subscriptions) and [hosted payment pages](https://docs.recurly.com/recurly-subscriptions/docs/hosted-payment-pages) (all accessed November 2026). ## Two windows: before and after expiry In Recurly, a cancelled subscription does not end right away. It stays in the `canceled` state, still valid, until `expires_at`, then becomes `expired` ([expire or cancel](https://docs.recurly.com/recurly-subscriptions/docs/expire-subscription)). That gives you two different win-back moments. | | Before expiry | After expiry | |---|---|---| | Subscription state | `canceled` | `expired` | | Customer access | Still active | Gone | | How they come back | Reactivate the same subscription | A new subscription | | Webhook to start from | canceled | expired | ### Before expiry: reactivation A canceled subscription can be reactivated before it expires; it then renews at the end of the current cycle as if nothing happened. The API has a reactivate endpoint for this, and Recurly sends a **reactivated** notification when it happens ([lifecycle guide](https://docs.recurly.com/recurly-subscriptions/docs/post-authorization-webhook-guide)). In SCA regions, Recurly notes the customer may need to authenticate their stored billing information again. This window is the cheapest win-back there is. A message a few days before `expires_at` ("Your plan ends on 30 November. Keep it with one click") needs no new checkout and no new card. Only send it if the customer's reason suggests they might stay; someone who left for a competitor will not appreciate a countdown. ### After expiry: a new subscription Once a subscription has expired it cannot be reactivated. A returning customer needs a new subscription. Recurly's [multiple subscriptions](https://docs.recurly.com/docs/multiple-subscriptions) page says the purchase endpoint works for both new and existing accounts, so the customer can come back on the same account, with their history. On hosted pages: each plan has a [hosted payment page](https://docs.recurly.com/recurly-subscriptions/docs/hosted-payment-pages) URL, but Recurly marks Hosted Payment Pages as deprecated and supported for legacy use only, recommends Recurly Checkout instead, and describes the plan page as creating a new account on purchase. For returning customers, a checkout in your own app built on the purchase endpoint, or Recurly Checkout, keeps everything on one account. ## Find who left, and why Recurly's [churned subscriptions export](https://docs.recurly.com/docs/subscriptions-churned) (Analytics › Exports) lists expired subscriptions with an `expiration_reason` column. Values include Canceled, Non-payment, Fixed billing cycles and Tax Location Invalid, plus nonpayment variants (one applies only to cardless trials). Two points from the docs: - A subscription does not count as churned until it has **expired**; `canceled_at` and `expires_at` are different dates. - Filtering `expiration_reason` splits churn into voluntary (Canceled) and involuntary (Non-payment). The two groups need different win-back messages. A customer lost to non-payment may still want the product; the first message should be "your card failed and your plan ended, here is how to restart", not a discount. A customer who cancelled needs a reason to come back. Recurly's export does not tell you *why* a customer cancelled beyond "Canceled". If you run a cancel flow, store the reason the customer gave with their account code, so you can choose the win-back message by reason. ## Offers that suit win-back Recurly [coupons](https://docs.recurly.com/recurly-subscriptions/docs/coupons) have two features that fit win-back well: - **Bulk unique codes.** One-time-use codes generated in batches, up to five million per campaign, each redeemable once by default ([bulk unique coupons](https://docs.recurly.com/recurly-subscriptions/docs/bulk-unique-coupons)). One code per former customer means the offer cannot be posted on a coupon site. - **Relative expiration.** For bulk codes, you can set an expiry period such as 7 days, 2 weeks or 1 month that starts for each code when it is generated. That gives each email a real deadline without managing dates by hand. For duration, Recurly recommends billing-period coupons, which apply for an exact number of cycles. "Two months at half price" is clearer than "50% off for 60 days". Not every reason calls for a discount. Match the offer to the reason: | Cancel reason | Win-back message | |---|---| | Too expensive | A unique coupon, or a cheaper plan | | Missing a feature | Tell them when it ships; no discount needed | | Not using it | Show what changed, or suggest a lighter plan | | Switched to another tool | One honest message about what you do differently | | Non-payment | Restart link; no offer | ## A win-back sequence, step by step 1. **Listen to canceled and expired notifications.** Recurly's pages use more than one naming style (for example "canceled" and `canceled_subscription_notification`), so check the names in your payloads, and confirm state through the API, as Recurly advises. 2. **Store the reason** from your cancel flow or support conversation, keyed by account code. 3. **Before expiry**, for reasons that suggest the customer might stay, send one reactivation reminder. 4. **After expiry**, wait. Contact the customer at intervals rather than the day after they leave, each time with a message that answers their reason. 5. **Generate a unique code per customer** from a bulk coupon with a relative expiry, if the offer is a discount. 6. **Bring them back on the same account** through the purchase endpoint or Recurly Checkout. 7. **Stop the sequence** as soon as a new subscription starts on the account, and stop for anyone who unsubscribes. ## Measure reactivations Recurly's support article on [reactivation MRR](https://support.recurly.com/hc/en-us/articles/360041810792-How-to-Find-Your-Reactivation-MRR-Using-Exports) shows how to find returning customers in exports: look for duplicate `account_code` values with one expired and one active subscription, and a gap of at least a month between `expires_at` of the old one and `activated_at` of the new one. Use the same method to compare win-back offers, and look at whether reactivated customers stay longer than a couple of cycles. ## Doing this with NoChurn NoChurn follows Recurly's webhooks and sends win-back emails at day 30, 60 and 90 after a customer leaves, written from the reason they gave in the cancel flow, with a link to come back. The cancel flow itself offers a coupon, a pause or a plan change on the Recurly subscription before anyone leaves, with a one-click cancel always visible, hosted or headless through the API. Coupons, checkout, invoicing and the charge stay in Recurly. NoChurn is free under $300 MRR, with every feature on every plan. See [NoChurn + Recurly](/integrations/recurly/). --- # Refund or fight? How to decide on a chargeback Source: https://www.nochurn.sh/blog/refund-or-fight-chargeback/ Every dispute forces a decision. Before a chargeback, you can refund. After it is filed, you can accept it or contest it. Each option has a different cost, and none of them removes the dispute from your network ratios once it exists. Teams that fight everything waste hours on cases they cannot win; teams that accept everything leave money on the table and teach some customers that disputing works. This guide gives a practical way to decide. It relies on Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work), [accepting disputes FAQ](https://support.stripe.com/questions/accepting-disputes-faq), [dispute withdrawals FAQ](https://support.stripe.com/questions/dispute-withdrawals-faq), [dispute fees FAQ](https://support.stripe.com/questions/dispute-fees-faq) and [pricing](https://stripe.com/pricing); Braintree's [disputing chargebacks](https://developer.paypal.com/braintree/articles/risk-and-security/chargebacks-retrievals/disputing-chargebacks) and [pricing](https://www.paypal.com/us/enterprise/paypal-braintree-fees); and Visa's [Dispute Management Guidelines for Merchants](https://usa.visa.com/dam/VCOM/global/support-legal/documents/merchants-dispute-management-guidelines.pdf) (all accessed November 2026). ## First: which stage are you in? The options depend on timing. | Stage | Your options | |---|---| | Before any dispute (complaint, early fraud warning) | Refund, or keep the charge | | Inquiry / retrieval | Answer with information; refund if appropriate | | Chargeback open | Accept, or contest with evidence | | After a decision | Pre-arbitration in some cases | The key constraint: **once a chargeback is open, you cannot refund.** Stripe's withdrawals FAQ explains that you cannot refund a charge with a pending dispute, because the issuing bank has already returned the money to the cardholder; a direct refund would pay the customer twice. If you want the customer to have their money and the matter closed, accepting the dispute is the way. ## What each option costs Using Stripe's US prices as an example (check your own country and contract): | Option | Money | Fees | Counts toward dispute ratios? | |---|---|---|---| | Refund before a dispute | You return the payment | None for the dispute | No dispute is created | | Accept a chargeback | You lose the payment | Dispute fee ($15), not returned | Yes | | Contest and lose | You lose the payment | Dispute fee plus countered fee ($15 + $15) | Yes | | Contest and win | You keep the payment | Dispute fee ($15); countered fee returned | Yes | On Braintree, the [pricing page](https://www.paypal.com/us/enterprise/paypal-braintree-fees) lists a $15 chargeback fee for standard US merchants, and Braintree's [fee documentation](https://developer.paypal.com/braintree/articles/wells-flat/pricing-fees) describes it as non-refundable, even if you win. Three things stand out: 1. **Winning is not free.** The dispute fee stays, and Stripe's FAQ says an accepted or won dispute counts against your dispute rate just like a lost one. 2. **Contesting adds a small extra cost**, refunded if you win. 3. **The biggest cost is often time.** Preparing a good response takes someone from support or finance away from other work. There is one more cost to weigh. Stripe notes that the issuer's decision can take 60 to 75 days after you submit, and the funds are held for that period. ## The questions that decide it ### 1. Is the customer right? Start here, and be honest. If the customer cancelled and you charged them anyway, or you promised a refund and never sent it, accept. Visa's guidelines say this explicitly for cancelled recurring disputes (13.2): if the cardholder withdrew permission and you did not issue a credit, accept the dispute. Then fix the cause. A lost case teaches you something; a contested case you should not have contested teaches you nothing and costs more. ### 2. Do you have the evidence the reason code asks for? Each reason code needs specific proof (see [reason codes for subscriptions](/blog/chargeback-reason-codes-subscriptions/)). For subscriptions, ask: - **Fraud (Visa 10.4, Mastercard 4837):** Do you have prior undisputed payments from this customer on this card, with matching IP or device? Usage around the billing date? Was the payment authenticated with 3D Secure? Strong history may qualify for [Visa Compelling Evidence 3.0](/blog/visa-compelling-evidence-3/). - **Cancelled recurring (Visa 13.2, Mastercard 4841):** Can you show there was no cancellation before the charge, the terms the customer accepted, and usage after the claimed cancellation date? - **Not received (Visa 13.1, Mastercard 4855):** Can you show the account was available and used during the billed period? - **Credit not processed (Visa 13.6, Mastercard 4860):** Did you refund? If not, were they entitled to one? If the answer is "we have nothing beyond the invoice", accept. Banks decide on what you send, and an invoice alone does not prove the customer authorized or used anything. ### 3. Is the amount worth the time? A $9 monthly charge and a $1,200 annual renewal deserve different effort. Set a threshold based on your own numbers: what an hour of your team's time costs, and how long a response takes. Below the threshold, contest only if the evidence is already assembled (for example, automatically). ### 4. Is this customer abusing the system? A customer who disputes every month, or uses the product heavily and then claims fraud, is worth contesting even for small amounts, with the full usage record. Stop future renewals on that card either way. ### 5. Is the account still active? If the customer is still subscribed and has disputed one charge, contact them before the deadline. Some disputes come from a family member or an accounting team who did not recognize the charge. Stripe's docs note that a cardholder can withdraw a dispute, but also that a withdrawn dispute still counts and you should submit evidence anyway, because the case can still be decided against you otherwise. ## Before a dispute: refund or wait? When a customer complains, or an early fraud warning arrives on Stripe, you still have the refund option. **Refund when:** - the customer clearly did not want the charge (forgot to cancel, cancelled and was charged); - the account shows no use since the charge; - the amount is close to or below the dispute fee; - an early fraud warning arrives on a new account with no activity. **Keep the charge when:** - the customer has used the service during the billed period and simply wants it free; - the account has a long, consistent payment and usage history; - your refund policy, accepted at signup, says no refund applies and the customer has not contacted you with a real problem. Stripe's guidance on early fraud warnings, covered in [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/), adds that refunding is most sensible for amounts around or below the dispute fee, and that a refund does not erase the fraud report itself. ## A decision table | Situation | Decision | |---|---| | Customer cancelled before the charge and you have no usage after | Accept (or refund, if no chargeback yet) | | Refund was promised and not sent | Accept, then fix your refund process | | Fraud claim, new account, no usage | Accept; cancel the subscription; review fraud rules | | Fraud claim, months of payments and usage on the same card | Contest; check CE 3.0 eligibility | | Cancelled claim, no cancellation in your records, usage continues | Contest with logs and terms | | Small amount, no evidence assembled | Accept | | Large amount, strong evidence | Contest | | Repeat disputer | Contest; stop renewals on that card | ## After the decision Whatever you decide, record three things: the reason code, the decision, and why. After a few months, patterns appear: which reason codes you win, which product situations create disputes, which disputes you should have prevented. That record is how you lower your ratios over time; see [preventing subscription chargebacks](/blog/prevent-subscription-chargebacks/). ## Doing this with NoChurn For Stripe and Braintree disputes, NoChurn gathers the evidence automatically (cancel flow answers, emails sent, usage you send by API, help desk conversations read only), so you can see quickly whether a case is worth contesting. If you contest, it drafts a reply with AI and nothing is sent until a person on your team has reviewed it. On Stripe, early fraud warnings come with a one-click refund. The decision to accept, refund or contest always stays with you, and the bank decides the outcome. See [chargebacks](/#disputes). --- # Silent churn: members who leave without clicking cancel Source: https://www.nochurn.sh/blog/silent-churn-memberships/ When people talk about churn, they picture a member clicking "Cancel membership." For many membership businesses, a large part of churn never goes through that button. The card expires and nobody updates it. A store subscription lapses after billing retries. A member who forgot about the charge disputes it with their bank. Or a member stops showing up months before they finally leave. None of these exits pass through your cancel flow, so none of them answer your cancellation survey. This guide shows how to find them in your data and what works for each. ## Four kinds of silent exit | Exit | What the member did | What you see | |---|---|---| | Failed payment | Nothing; the card or bank account stopped working | Retries fail, subscription ends | | Store lapse | Nothing, or turned off renewal in their phone settings | A store notification, often days later | | Dispute | Asked their bank to reverse the charge | A dispute, and often a cancelled subscription | | Fade-out | Stopped using the membership, still paying | Usage at zero; churn arrives later | The first three end the membership without a cancel click. The fourth is churn that has already happened in the member's head but not yet in your billing. ## How to find them in your data ### Split ended subscriptions by how they ended On Stripe, each cancelled subscription carries `cancellation_details.reason`, with values such as `cancellation_requested`, `payment_failed` and `payment_disputed` ([cancel API reference](https://docs.stripe.com/api/subscriptions/cancel), accessed November 2026). Group last quarter's ended subscriptions by that field: ```text silent share = subscriptions ended by payment_failed or payment_disputed ÷ all subscriptions ended ``` Hypothetical example: 200 memberships ended last quarter, 120 with `cancellation_requested`, 72 with `payment_failed` and 8 with `payment_disputed`. The silent share is 80 ÷ 200 = 40%. Those 80 members never saw your cancel flow. On the App Store, the expiration intent in a subscription's renewal info distinguishes a customer cancellation from a billing error or a declined price increase ([Apple reference](https://developer.apple.com/documentation/appstoreserverapi/expirationintent)). On Google Play, real-time developer notifications report when a subscription enters account hold or is cancelled ([RTDN reference](https://developer.android.com/google/play/billing/rtdn-reference)). Our guides on [App Store notifications](/blog/app-store-server-notifications-churn/) and [Google Play RTDN](/blog/google-play-rtdn-churn-tracking/) go through the fields. ### Look at subscriptions stuck in past due If your billing settings leave subscriptions past due after the last retry, silent churn does not show up as churn at all. The member is gone, but the subscription still counts as active. List every subscription that has been past due for more than your retry window. Each one is churn you have not recorded yet. ### Track last activity For the fade-out, you need product data: last visit, last class booked, last login, last download. A simple rule surfaces the at-risk group: ```text faded = active, paid membership AND no activity in the last N days ``` Pick N from your own usage rhythm. A weekly-class membership and a quarterly content box need very different values. Then check whether faded members churn more than others over the next 90 days, using your own history; do not assume it. ## What to do about each ### Failed payments: fix the card before it fails Much payment churn is predictable. A card with an expiry date next month will fail next month unless it is updated. - **Card account updater.** Stripe updates saved card details with the networks when a member gets a new card number ([revenue recovery docs](https://docs.stripe.com/billing/revenue-recovery)). It covers many reissued cards, not all. - **Expiring card emails.** Stripe can email the customer one month before a saved card expires ([customer emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails)). Turn it on. - **Retries and recovery emails.** After a failure, retry at sensible times and tell the member, with a direct link to update their card. A member may not notice a failed charge until access stops. More detail in [expiring cards](/blog/expiring-cards/) and [involuntary churn](/blog/involuntary-churn/). ### Store lapses: use the store's own tools On the App Store and Google Play, the store collects payment and runs retries. You cannot email a card update link, because the payment method belongs to the member's store account. What you can do is turn on the billing grace period, so members keep access while the store retries, and show an in-app message sending them to their store payment settings. See [App Store billing retry](/blog/app-store-billing-retry-grace-period/) and [Google Play grace period and account hold](/blog/google-play-grace-period-account-hold/). ### Disputes: make the charge recognizable and the exit easy A member who does not recognize a charge, or cannot find how to cancel, may go to their bank instead of to you. Three things help: 1. **A clear statement descriptor.** The text on the bank statement should name your brand as members know it. Stripe lets you set it ([statement descriptors](https://docs.stripe.com/get-started/account/statement-descriptors)). 2. **A visible cancel path.** If cancelling takes one click, members have less reason to ask their bank to do it for them. Our [cancel flow guide](/blog/cancel-flow-best-practices/) covers the design. 3. **Renewal reminders on long plans.** An annual membership renewing without warning is a dispute waiting to happen. See [annual plan renewal reminders](/blog/annual-plan-renewal-reminders/) for the notice rules. When a dispute does arrive, gather evidence: the signup, the reminders sent, usage, and any cancel or support history. See [winning chargebacks on Stripe](/blog/win-chargebacks-stripe/). ### Fade-out: reach out before the renewal, not after A faded member is still a member. That gives you a window to help, and an honest choice to offer: - **A nudge back.** Something concrete and specific to what they used: the next class on their usual day, new content in their usual category. - **A pause.** If they are away or busy, a pause keeps them from paying for nothing and keeps the relationship. - **A cheaper tier.** If they use a fraction of the membership, a smaller plan may fit better than leaving. What not to do: keep billing a member you know has stopped using the service and hope they do not notice. It invites disputes and angry cancellations. ## Measure it Add these to your monthly report: | Metric | Formula | |---|---| | Silent share of churn | Ended by failed payment or dispute ÷ all ended | | Failed payment recovery rate | Failed invoices later paid ÷ invoices that failed | | Dispute rate | Disputes ÷ successful charges in the period | | Faded members | Paid members with no activity in N days ÷ paid members | | Faded-to-churn rate | Faded members who churn within 90 days ÷ faded members | If the silent share is large, your cancel flow and cancellation survey are only describing part of your churn. Fixing payments and reminders is often the quicker win. ## Doing this with NoChurn NoChurn handles the silent exits as well as the visible ones. For failed payments on Stripe, it runs smart retries timed to the decline reason and payday, sends AI-written recovery emails you can review, and links to a hosted card update page; on other billing tools it adds those emails and the card update link next to the provider's own dunning. App Store and Google Play lapses are read from store notifications. For disputes on Stripe and Braintree, it gathers evidence automatically (cancel flow answers, emails sent, usage, support conversations) and drafts a reply that is sent only after a human reviews it. Each member gets a churn score from 0 to 100 at signup and on every change, and your own usage data sent by API shows churn drivers (correlation, not causation). Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # Stripe Billing retention features: what's built in and what isn't Source: https://www.nochurn.sh/blog/stripe-billing-retention-features/ Stripe Billing ships with more retention tooling than many teams realize. Before you build or buy anything, it is worth knowing exactly what is already in your account, what each piece does, and where it stops. This guide maps the built-in features from [Stripe's documentation](https://docs.stripe.com/billing/revenue-recovery) (accessed November 2026), then lists the gaps. We already covered retry timing in depth in [how Stripe Smart Retries work](/blog/stripe-smart-retries/), so this article stays at the level of the whole toolkit. ## The built-in toolkit at a glance | Area | What Stripe provides | Where to read more | |---|---|---| | Retries | Smart Retries or a custom schedule | [Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries) | | Customer emails | Failed payment, expiring card and reminder emails | [Customer emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails) | | Workflows | No-code automations (trigger, filters, actions) | [Automations](https://docs.stripe.com/billing/revenue-recovery/automations) | | Card updates | Card account updater with the networks | [Revenue recovery](https://docs.stripe.com/billing/revenue-recovery) | | Cancellation | Customer portal cancellation page, reasons, retention coupon | [Cancellation page](https://docs.stripe.com/customer-management/cancellation-page) | | Targeted offers | Retention rules (private preview) | [Retention rules](https://docs.stripe.com/billing/retention/rules) | | Plan changes | Portal plan switching, downgrades at period end | [Configure the portal](https://docs.stripe.com/customer-management/configure-portal) | | Pause | Pause a subscription or pause collection | [Pause subscriptions](https://docs.stripe.com/billing/subscriptions/pause) | | Reporting | Billing analytics, retention performance, benchmarking | [Analytics](https://docs.stripe.com/billing/subscriptions/analytics) | ## Failed payments: what is built in ### Retries Smart Retries picks retry times with a model; Stripe recommends 8 tries within 2 weeks. You can switch to a custom schedule instead. Stripe will not retry after certain hard declines until a new payment method is collected. Details and settings are in our [Smart Retries guide](/blog/stripe-smart-retries/). ### Customer emails Stripe can send the customer an email after each failed payment, an email one month before a saved card expires, and reminders for unpaid invoices and payments waiting for confirmation (for example, an authentication step). These are switched on in the Billing settings ([customer emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails)). ### Automations Automations are no-code workflows built from a trigger (such as a failed subscription payment, an overdue invoice or a cancellation), optional filters and actions (such as setting a custom retry policy, marking a subscription unpaid, marking an invoice uncollectible or emailing your team) ([automations](https://docs.stripe.com/billing/revenue-recovery/automations)). They are useful for treating segments differently, for example a longer grace period for large accounts. ### Card account updater Stripe works with card networks to update saved card details when a customer receives a new card number. This quietly prevents a share of failures that would otherwise happen at expiry. It does not help when the bank account behind the card is empty or the customer cancelled the card on purpose. See [network tokens and card account updater](/blog/network-tokens-card-account-updater/). ## Cancellations: what is built in ### The portal cancellation page The customer portal can show a cancellation page with a fixed list of reasons (too expensive, missing features, switched to an alternative, no longer needed, and others, plus free text). The answer is stored on the subscription in `cancellation_details.feedback` and visible in the Dashboard, in Sigma and in the `customer.subscription.updated` webhook ([cancellation page](https://docs.stripe.com/customer-management/cancellation-page)). ### Retention coupon and retention rules You can attach one retention coupon to the portal's cancellation step. It is off by default. Retention rules, in private preview at the time of writing, let you target offers by conditions such as cancellation reason, tenure and spend; turning them on disables the single retention coupon ([retention rules](https://docs.stripe.com/billing/retention/rules)). ### Plan switching and downgrades If you enable subscription updates in the portal, customers can switch plans themselves. A "manage downgrades" option can schedule a downgrade for the end of the billing period instead of applying it immediately; Stripe implements this with a subscription schedule, and it only works between prices of the same product ([configure the portal](https://docs.stripe.com/customer-management/configure-portal)). ### Pause Stripe documents two mechanisms. A full pause suspends service and invoicing. Pausing collection (`pause_collection`) keeps the subscription in its current status and handles invoices created during the pause by keeping them as drafts, marking them uncollectible or voiding them ([pause subscriptions](https://docs.stripe.com/billing/subscriptions/pause)). Our [Stripe pause guide](/blog/stripe-pause-subscription/) compares them. ## Reporting: what is built in [Billing analytics](https://docs.stripe.com/billing/subscriptions/view-metrics) gives you MRR, an MRR roll-forward (new, reactivation, expansion, contraction, churn, FX adjustment), churned revenue, subscriber churn and a retention-by-cohort view. A few definitions are worth knowing before you compare Stripe's numbers with your own: - **Subscriber churn rate** is measured over a rolling 30-day window, and its denominator includes subscribers active at the start plus new subscribers during the window. - **Churned revenue** includes both voluntary churn and churn from failed payments. - You can configure whether discounts are excluded from MRR and whether a cancellation counts as churn immediately or at period end. [Retention performance](https://docs.stripe.com/billing/retention/performance) reports on cancellations through the portal only, and counts a save only if the customer stays subscribed at least 7 days after accepting an offer. Cancellations made through your support team or your own app are not in it. ## What isn't built in This is where you either write code, accept the limitation or use a separate tool. We list what we could not find in Stripe's Billing documentation; if Stripe adds something, its docs win. ### Recovery messages that match the decline Stripe's failed payment email goes out after each failed attempt. We found no documented option to vary its message by decline reason, yet an insufficient funds decline and an expired card need different words: one asks the customer to wait or switch cards, the other to enter a new card. If you want a message per decline reason or per segment, you send it yourself from `invoice.payment_failed` webhook events. ### An offer per cancel reason, without the preview Without retention rules, the portal has one coupon for everyone. "Not using it enough" is usually better served by a pause; "too expensive" by a downgrade. Matching offers to reasons is the core of a [good cancel flow](/blog/cancel-flow-best-practices/). ### A cancel flow in your own app The portal is a Stripe-hosted page. If customers cancel inside your web app, a desktop app or a mobile app, you build the screens and call the Subscriptions API yourself, including the reasons, the offer logic and the "cancel now" button. ### Win-back after the subscription ends Once a subscription is cancelled, we found no built-in sequence that writes to the former customer at set intervals based on why they left. You keep the Customer object and the reason, but sending anything is up to you. See [how to win back canceled subscribers on Stripe](/blog/stripe-win-back-canceled-customers/). ### Risk scoring with your own data Stripe sees payments. It does not see your product usage, your support tickets or the attributes you collect at signup, so it cannot tell you which of your customers look likely to churn, or which attributes go together with churn. That analysis needs your data joined with billing data; our guide to [predicting churn with customer data](/blog/predict-churn-with-customer-data/) shows the method. ### One view across sources If part of your revenue comes from the App Store, Google Play or another billing tool, Stripe's analytics only show the Stripe part. ## Is the built-in toolkit enough? For many early-stage products, yes. A reasonable minimum setup: 1. Smart Retries on, with a deliberate end-of-retries action. 2. Failed payment and expiring card emails on. 3. Portal cancellation page on, with reasons collected. 4. Downgrades scheduled at period end if you have more than one plan. 5. A monthly look at churned revenue split between voluntary and failed payments. You likely need more when cancellations happen inside your own app, when you want different offers per reason, when failed payments are a large share of churn, or when you want to act on customers before they reach the cancel button. ## Doing this with NoChurn NoChurn connects to Stripe in one click and adds what the list above leaves out. For failed payments, it runs smart retries timed to the decline reason and payday, sends AI-written recovery emails you can review, and links to a hosted card update page. For cancellations, it runs cancel flows with reasons and one offer per reason (discount, pause or plan change), with a one-click cancel always visible, as a hosted modal or through a headless API in your own app. After a cancellation it sends win-back emails at day 30, 60 and 90 based on the reason. It also gives each customer a churn score from 0 to 100 at signup and on every change, and accepts your own data by API to show churn drivers (correlation, not causation). Every feature is on every plan, priced only by MRR, and never as a share of recovered revenue. See [pricing](/pricing/). --- # Stripe early fraud warnings: refund or fight? Source: https://www.nochurn.sh/blog/stripe-early-fraud-warnings/ An early fraud warning on Stripe is the card issuer telling you, before any dispute exists, that a cardholder has reported a charge as fraud. For a subscription business that raises an awkward question: do you refund now and lose the revenue for sure, or wait and defend the charge if a dispute arrives? This guide explains what an early fraud warning (EFW) is on Stripe, what you can and cannot do with one, and a practical way to decide. It sticks to Stripe's own pages: the [Early Fraud Warning API reference](https://docs.stripe.com/api/radar/early_fraud_warnings/object), [how disputes work](https://docs.stripe.com/disputes/how-disputes-work), [dispute and fraud monitoring programs](https://docs.stripe.com/disputes/monitoring-programs) and Stripe's [monitoring program FAQ](https://support.stripe.com/questions/monitoring-program-faq) (all accessed November 2026). Where Stripe's docs do not answer a question, we say so. ## What an early fraud warning is Stripe's [API reference](https://docs.stripe.com/api/radar/early_fraud_warnings/object) describes the object plainly: an early fraud warning indicates that the card issuer has notified Stripe that a charge may be fraudulent. It is not a dispute. No money has moved, and there is nothing to respond to. Each warning carries a few fields worth knowing: | Field | What it holds | |---|---| | `charge` | The charge the warning is about | | `payment_intent` | The PaymentIntent behind that charge | | `fraud_type` | The issuer's label: `card_never_received`, `fraudulent_card_application`, `made_with_counterfeit_card`, `made_with_lost_card`, `made_with_stolen_card`, `unauthorized_use_of_card` or `misc` | | `actionable` | Whether you can still do something about it | | `created` | When the warning was created | ### The actionable flag Stripe defines `actionable` precisely: a warning is actionable if the charge has not received a dispute and has not been fully refunded. Once either happens, the flag turns false. In practice this flag is your to-do list. An actionable warning is one where your decision still matters. ### The webhooks Stripe sends `radar.early_fraud_warning.created` when a warning is created and `radar.early_fraud_warning.updated` when it changes (for example, when it stops being actionable). You can also list warnings through the `/v1/radar/early_fraud_warnings` endpoint, which is useful for a daily review if you do not want to act on webhooks in real time. ## What Stripe itself suggests Stripe's API reference states the option directly: you may wish to proactively refund a charge that receives an EFW, in order to avoid receiving a dispute later. That is a suggestion, not a rule, and Stripe does not refund every warning on your behalf. Its support article on [getting started with fraud and disputes](https://support.stripe.com/questions/getting-started-with-stripe-fraud-and-disputes) says Stripe may proactively refund a payment that receives an early fraud warning only in certain, comparatively rare, situations. If you use Radar for Fraud Teams, Stripe also documents a preview feature called Smart Refunds on its [reviews page](https://stripe.com/docs/radar/review): Radar estimates the likelihood of a dispute after a payment completes, and when that likelihood is high it adds a refund recommendation to your Reviews list. It is a recommendation you act on, not an automatic refund. ## What a refund changes, and what it does not This is where most teams get confused. A refund and a warning are tracked separately. - **A refund can prevent a dispute.** That is the whole point of Stripe's suggestion above. - **A refund does not erase the warning.** Stripe's [monitoring programs page](https://docs.stripe.com/disputes/monitoring-programs) says early fraud warnings, although they are not disputes, are considered fraudulent regardless of their outcome, and that Visa's VAMP program includes them in its calculations. - **Stripe's own rates and the networks' rates differ.** Stripe's [monitoring program FAQ](https://support.stripe.com/questions/monitoring-program-faq) notes that card networks such as Visa and Mastercard count these when they calculate your dispute and fraud rates on their network, even where Stripe's own dispute and fraud rates do not. So refunding is not a way to make fraud disappear from your record. It is a way to avoid the cost and work of a dispute on top of the fraud report. ## What a dispute costs if you wait If you do not refund and the cardholder disputes, Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) page describes what follows: 1. Stripe notifies you through the Dashboard, email, webhooks and the API. 2. Stripe debits the disputed amount plus a dispute fee from your balance. 3. If you counter the dispute, a further dispute countered fee applies, which Stripe returns if you win. Unless your Stripe contract says otherwise, Stripe never returns the dispute received fee. 4. You get one opportunity to respond. Stripe forwards your response and files to the issuer immediately, and you cannot edit it or add files afterwards. Fee amounts vary by country and contract, so check your own [Stripe pricing](https://stripe.com/pricing) rather than relying on a figure from a blog. The response deadline is shown on each dispute in your Dashboard and is the one that counts. ## Refund or wait: a practical way to decide Stripe does not give a universal rule, and neither will we. But the decision is easier if you look at the same few signals every time. For a subscription business, the useful ones are: | Signal | Leans toward refund | Leans toward waiting | |---|---|---| | Account activity | No logins or usage since signup | Regular, ongoing use of the product | | Billing history | First payment on a new account | Many months of paid renewals on the same card | | `fraud_type` | `made_with_stolen_card`, `made_with_lost_card`, `fraudulent_card_application` | `misc` with an account that looks genuine | | Amount | Small relative to the cost and time of a dispute | Large annual plan where evidence is strong | | Customer contact | No reply, or the email bounces | The customer recognizes the purchase when you ask | A few practical rules sit on top of the table: 1. **Stop future charges first.** If the card really was stolen, the next renewal will produce another warning or dispute. Cancel the subscription or remove the card before anything else. 2. **Refund the whole charge, not part of it.** Stripe's `actionable` flag only clears on a full refund, and a partial refund leaves a disputable balance. 3. **Do not refund blindly.** Refunding every warning means every warning costs you the full amount, including ones that would never have become disputes. 4. **Write down why.** For each warning, record the signals you looked at and what you decided. After a few months you will see which kinds of warnings actually turn into disputes for your business. 5. **Fix the source.** Clusters of warnings from new signups usually point to card testing or a leaky signup flow. Stripe's [Radar rules](https://docs.stripe.com/radar/rules) are the place to tighten that. ### When waiting makes sense Waiting is reasonable when the account shows real, sustained use by the cardholder. A family member using a parent's card, or an employee using a company card without telling finance, can produce a fraud report on an account that has been active for months. If a dispute follows, that usage is your evidence. Keep it ready: login history, feature usage, emails sent and answered, the terms the customer accepted at signup and any cancellation attempts. ### When refunding is the obvious call Refund quickly when the account was created and paid in one go with no activity afterward, when several warnings arrive on accounts created around the same time, or when the amount is too small to justify the time a dispute takes. In those cases the money is very unlikely to stay with you, and the dispute adds its own cost on top. ## A weekly routine that takes ten minutes 1. List actionable warnings (filter on `actionable` being true). 2. For each one, open the customer and check usage, history and the `fraud_type`. 3. Decide: refund and cancel, or keep and prepare evidence. 4. Log the decision and the reason. 5. Once a month, compare decisions with what happened: which kept charges were later disputed, and which disputes you won. ## Doing this with NoChurn NoChurn connects to Stripe and, when a dispute does arrive, gathers the evidence automatically: cancel flow answers, emails sent, product usage you send by API and support conversations from your help desk. It drafts a reply with AI, and nothing is sent to Stripe until a person on your team has reviewed it. The refund decision on an early fraud warning stays yours, made in Stripe. The churn score and custom data help you see which accounts look genuine. See [NoChurn + Stripe](/integrations/stripe/). --- # How to pause a subscription on Stripe instead of losing the customer Source: https://www.nochurn.sh/blog/stripe-pause-subscription/ A customer who says "I don't need this for a couple of months" is not the same as one who wants to leave. If the only button they see is Cancel, you lose both. A pause keeps the account, the history and the payment method in place, and gives the customer an easy way back. Stripe now has more than one way to pause, and they behave differently. This guide explains each one, when to use it, and how resuming works. It sticks to Stripe's documentation: [pause payment collection](https://docs.stripe.com/billing/subscriptions/pause-payment), [pause subscriptions](https://docs.stripe.com/billing/subscriptions/pausing), the [pause subscription API reference](https://docs.stripe.com/api/subscriptions/pause), the changelog entries for [pause and resume on demand](https://docs.stripe.com/changelog/endive/2026-09-30/pause-subscription) and [pausing in the customer portal](https://docs.stripe.com/changelog/endive/2026-10-28/customer-portal-subscription-pausing), and [using webhooks with subscriptions](https://docs.stripe.com/billing/subscriptions/webhooks) (all accessed November 2026). ## Two different things called "pause" Stripe has two mechanisms, and mixing them up causes most of the confusion. | | Pause payment collection | Pause the subscription | |---|---|---| | How | Set `pause_collection` on the subscription | Call the pause subscription endpoint | | Subscription status | Unchanged (for example, stays `active`) | Becomes `paused` | | Invoices | Still created, then handled by the behavior you chose | Not generated while paused | | Billing periods | Keep advancing | Do not advance | | Resume | Clear `pause_collection`, or set `resumes_at` | Resume through the API | | Events | `customer.subscription.updated` | `customer.subscription.paused`, then `customer.subscription.resumed` | The first is older and widely used. The second was added in Stripe's [2026-09-30 changelog](https://docs.stripe.com/changelog/endive/2026-09-30/pause-subscription) and is closer to what customers mean by "pause my account". Check which API version your integration uses before relying on the newer endpoint. ## Option 1: pause payment collection [Pausing payment collection](https://docs.stripe.com/billing/subscriptions/pause-payment) keeps the subscription running but stops you from charging for it. You choose one of three behaviors: - **`keep_as_draft`**: you offer the service for free for now and collect payment later. Invoices stay as drafts. - **`mark_uncollectible`**: you offer the service for free and mark the invoices as uncollectible. - **`void`**: you offer the service for free and never collect for the period. Invoices are voided. You can set an optional `resumes_at` timestamp so collection restarts on its own. Without it, collection stays paused until you clear `pause_collection`. Stripe also notes that any existing customer balance is still applied to invoices during the pause. ### When it fits Payment collection pauses suit situations where the customer keeps access: a goodwill gesture after an outage, a few free weeks while a customer sorts out a budget, or a B2B account waiting on a purchase order. For a customer who will not use the product at all for a while, it is a poor fit: the subscription status stays the same, periods keep advancing, and your own app has to decide whether to block access. For a retention offer, `void` is usually the honest choice. `keep_as_draft` means the customer owes the paused months later, which surprises people who thought "pause" meant "no charge". ## Option 2: pause the subscription itself With the [pause subscription endpoint](https://docs.stripe.com/api/subscriptions/pause), the pause takes effect immediately. According to Stripe's [pause subscriptions guide](https://docs.stripe.com/billing/subscriptions/pausing): - The subscription status becomes `paused`. - A paused subscription does not generate invoices and does not advance to new billing periods. - You resume it through the API. Resume is only available on subscriptions that use `charge_automatically` collection. - If resuming does not generate an invoice, the status goes back to `active` immediately. - A coupon on the subscription keeps its original validity period. The pause does not extend it. Stripe sends `customer.subscription.paused` when the status changes to `paused` and `customer.subscription.resumed` when it comes back. The [webhooks guide](https://docs.stripe.com/billing/subscriptions/webhooks) is explicit that `customer.subscription.resumed` does not apply when only payment collection is unpaused, which is a good reminder that the two mechanisms are separate. ### Other ways a subscription becomes paused Two cases produce the `paused` status without you calling the endpoint: 1. **A trial ends without a payment method**, if you configured the trial to pause in that case. Stripe documents this in the [webhooks guide](https://docs.stripe.com/billing/subscriptions/webhooks). 2. **A payment fails** and you use [pause on payment failure](https://docs.stripe.com/billing/revenue-recovery/smart-retries/pause-on-payment-failure). Only eligible subscriptions on flexible billing mode can pause this way. You choose automatic resume or a manual resume, and the `status_details.paused.subscription.type` field tells you why a subscription paused. If you read `paused` subscriptions in your own reports, use that field so a voluntary pause is not counted the same way as a trial that ended without a card. ## Option 3: let customers pause in the customer portal Stripe's [2026-10-28 changelog](https://docs.stripe.com/changelog/endive/2026-10-28/customer-portal-subscription-pausing) adds pausing to the redesigned customer portal: 1. In your portal configuration, set `features.subscription_pause.enabled` to true. 2. Optionally set `features.subscription_pause.duration` to offer predefined pause lengths. 3. To send a customer straight into the pause flow for one subscription, create a portal session with `flow_data.type` set to `subscription_pause` and the subscription ID. This is new, and older Stripe support articles still say the portal cannot pause subscriptions. Rely on the changelog and the API reference for your API version, and test it in a sandbox before you announce it to customers. ## How to offer a pause well Whichever mechanism you use, the offer matters as much as the plumbing. 1. **Offer it at the right moment.** A pause is most useful when the cancel reason is temporary: seasonal business, a project on hold, travel, budget timing. It is a weak answer to "it's too expensive" or "missing features". Our guide on [pause vs discount offers](/blog/pause-vs-discount-retention-offers/) covers which offer fits which reason. 2. **Give fixed lengths.** One, two or three months is easier to choose than an open-ended pause, and the subscription comes back on its own. Use `resumes_at` for collection pauses, or the portal's predefined durations. 3. **Say exactly what happens.** Will the customer keep access? Will they be charged on resume? When? Put the resume date in the confirmation email. 4. **Remind before resuming.** Send a short email a few days before the pause ends, with a link to extend the pause or cancel. Surprise renewals after a pause turn into refund requests and disputes. 5. **Keep cancel visible.** A pause offer is an offer, not a gate. The customer must still be able to cancel in one step. See [click to cancel rules](/blog/click-to-cancel-rules/). ## Handling resume in your app Pausing touches access control, so wire up the events: - On `customer.subscription.paused`, switch the account to a paused state. Decide whether data stays readable and say so in the product. - On `customer.subscription.resumed`, restore access and log the resume. - For collection pauses, watch `customer.subscription.updated` and read the `pause_collection` field, since the status does not change. - Count pauses separately in your churn reporting. A paused customer has not churned, but a pause that ends in a cancellation should be attributed to the original cancel reason. See [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ## Testing checklist - [ ] A collection pause with `void` produces voided invoices and no charge. - [ ] A collection pause with `resumes_at` restarts billing on that date. - [ ] A subscription pause sets status `paused` and stops invoices. - [ ] Resume returns the subscription to `active` and your app restores access. - [ ] Your app reacts to `paused` and `resumed` events, and ignores collection unpauses for the resumed logic. - [ ] The reminder email goes out before every scheduled resume. ## Doing this with NoChurn NoChurn's cancel flow asks for the cancellation reason and can offer a pause, a discount or a plan change based on it, with a one-click cancel button visible at every step. It runs hosted, or headless through the API if you want your own design. The pause itself is applied in your Stripe account. Every answer is stored and later used for win-back emails at day 30, 60 and 90 and for the churn score. See [NoChurn + Stripe](/integrations/stripe/). --- # Which Stripe webhooks to track churn, and what each one means Source: https://www.nochurn.sh/blog/stripe-webhooks-churn-tracking/ Stripe's Dashboard shows you subscriptions as they are now. Churn analysis needs the story of how they got there: when a cancellation was requested, when it took effect, whether it followed a failed payment, whether the customer paused first. That story lives in webhook events, and if you do not store them as they arrive, you cannot rebuild it later with much confidence. This guide lists the Stripe events that matter for churn, what each one means and what to store. It sticks to Stripe's [using webhooks with subscriptions](https://docs.stripe.com/billing/subscriptions/webhooks) guide, the [webhooks overview](https://docs.stripe.com/webhooks), the [cancel subscription API reference](https://docs.stripe.com/api/subscriptions/cancel), the [Early Fraud Warning reference](https://docs.stripe.com/api/radar/early_fraud_warnings/object) and Stripe's support article on the [card updater](https://support.stripe.com/questions/how-can-i-see-cards-updated-automatically-via-card-updater) (all accessed November 2026). ## The short list | Event | What it means for churn | |---|---| | `customer.subscription.created` | A subscription started. Not proof of payment. | | `customer.subscription.updated` | Something changed: plan, coupon, renewal, a scheduled cancellation, a collection pause | | `customer.subscription.deleted` | The subscription ended. This is the churn event. | | `customer.subscription.paused` | The status changed to `paused` | | `customer.subscription.resumed` | A paused subscription came back | | `customer.subscription.trial_will_end` | A trial ends soon | | `invoice.payment_failed` | A payment attempt failed | | `invoice.paid` | An invoice was paid, including after a failure | | `payment_method.automatically_updated` | The card updater replaced card details | | `charge.dispute.created` | A customer disputed a charge | | `radar.early_fraud_warning.created` | An issuer flagged a charge as possible fraud | The rest of this guide goes through them in the order they usually happen. ## Starting and changing ### `customer.subscription.created` Stripe sends this when a subscription is created. It is the start of your cohort data, but it is not proof that the customer paid. On a first invoice that fails, the [webhooks guide](https://docs.stripe.com/billing/subscriptions/webhooks) says the subscription stays `incomplete`. Store the created date, but count a customer as acquired only once the first invoice is paid. ### `customer.subscription.updated` Stripe describes this event as sent when a subscription starts or changes: renewing, adding a coupon, applying a discount, adding an invoice item and changing plans all trigger it. For churn, three changes inside it matter most: 1. **A cancellation is scheduled.** When `cancel_at_period_end` turns true, the customer has decided to leave, even though the subscription is still active. Store this date. It is when the decision happened, which can be weeks before the subscription ends. 2. **A cancellation is removed.** When `cancel_at_period_end` goes back to false, you kept the customer. Store this too, or your saves are invisible. 3. **A downgrade.** A plan change to a cheaper price is contraction, the quiet cousin of churn. Because this event fires for many reasons, compare the new object with `previous_attributes` in the event to see what actually changed. ## Ending ### `customer.subscription.deleted` The [webhooks guide](https://docs.stripe.com/billing/subscriptions/webhooks) says it plainly: sent when a customer's subscription ends. This is your churn event. Its timestamp is when revenue stopped. Read `cancellation_details` on the subscription, documented in the [cancel API reference](https://docs.stripe.com/api/subscriptions/cancel): - `reason` tells you why it ended: `cancellation_requested`, `payment_failed` or `payment_disputed`, among others. This is how you split voluntary from involuntary churn without guessing. - `feedback` holds the customer's chosen reason, such as `too_expensive`, `unused`, `missing_features` or `switched_service`. - `comment` holds the free text the customer wrote. If you remember one thing from this guide, store `reason` and `feedback` at the moment of deletion. For the metrics built on top, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/) and [involuntary churn](/blog/involuntary-churn/). ## Pausing ### `customer.subscription.paused` and `customer.subscription.resumed` Stripe sends `customer.subscription.paused` when a subscription's status changes to `paused`, including automatically when a trial ends without a payment method if you configured that. It sends `customer.subscription.resumed` when a paused subscription is resumed, and the guide notes it does not apply when only payment collection is unpaused. That distinction matters: a pause of payment collection (`pause_collection`) does not change the status, so you only see it through `customer.subscription.updated`. If you offer pauses as a retention tool, track both kinds. Details are in [how to pause a subscription on Stripe](/blog/stripe-pause-subscription/). A paused customer has not churned. Report them separately, and attribute any later cancellation to the original reason. ## Trials ### `customer.subscription.trial_will_end` Stripe sends this three days before a trial ends, or right away if the trial is shorter than three days. It is your last good moment to remind the customer, check that a payment method is on file, and make sure they reached the part of the product that makes them stay. Trial-to-paid is a churn metric in its own right; see [trial to paid conversion](/blog/trial-to-paid-conversion/). ## Payments ### `invoice.payment_failed` A payment attempt on an invoice failed. On renewals this starts the dunning window. Store the attempt number, the decline code and the advice code from the PaymentIntent's `last_payment_error`; our guide to [Stripe decline codes](/blog/stripe-decline-codes/) explains what each means. Do not record churn here. A failed payment is a risk, not an exit. The subscription only churns when it is deleted, or when your recovery settings move it to a state where you stop serving the customer. ### `invoice.paid` The invoice was paid. After a failure, this is your recovery event. Store which attempt succeeded and whether the customer changed their card first. Over time, that tells you whether retries or emails do most of the recovery work. ### `payment_method.automatically_updated` Stripe's [card updater support article](https://support.stripe.com/questions/how-can-i-see-cards-updated-automatically-via-card-updater) says Stripe creates this event when the card updater changes a card's details. It explains a renewal that succeeds on a card that would otherwise have expired. Logging it lets you see how much involuntary churn the network prevents for you; more in [expiring cards](/blog/expiring-cards/). ## Disputes and fraud ### `charge.dispute.created` A customer disputed a charge with their bank. For churn, a dispute is almost always the end of the relationship, and Stripe records `payment_disputed` as a cancellation `reason` when a subscription ends for that cause. Track disputes separately from cancellations: they cost fees, and they need a response. ### `radar.early_fraud_warning.created` The [Early Fraud Warning reference](https://docs.stripe.com/api/radar/early_fraud_warnings/object) describes it as the issuer notifying Stripe that a charge may be fraudulent. It is not a dispute yet. If you sell subscriptions, decide quickly whether to refund and stop future charges. We cover that decision in [Stripe early fraud warnings](/blog/stripe-early-fraud-warnings/). ## Storing events so the numbers hold up Stripe's [webhooks overview](https://docs.stripe.com/webhooks) documents a few behaviors that shape how you store events: 1. **Events can arrive out of order.** Stripe does not guarantee delivery order. Use the event's `created` time and the object's own fields, not arrival order, to build history. 2. **Events can arrive more than once.** Deduplicate on the event ID before writing anything. 3. **Return a 2xx quickly.** Store the raw event, acknowledge it, and process it in a background job. 4. **Verify signatures.** Check the `Stripe-Signature` header with your endpoint secret before trusting a payload. A simple table works well: event ID, type, created time, customer ID, subscription ID, and the raw payload. Derive your churn tables from it. When a definition changes, you can recompute from the raw events instead of losing history. ### What to derive - Subscription start (first paid invoice), cancellation requested, cancellation removed, ended. - `reason` and `feedback` at the end. - Pause start and end. - Each failed payment with codes, and the recovery that followed. - Disputes and early fraud warnings by customer. ## Doing this with NoChurn NoChurn connects to Stripe in one click, and reads these events for you, so you do not have to build the storage above yourself. It uses them for smart retries, recovery emails you review, cancel flow answers, win-back emails at day 30, 60 and 90, and a churn score from 0 to 100. You can add your own customer data by API. Stripe stays the source of truth for billing. See [NoChurn + Stripe](/integrations/stripe/). --- # How to win back canceled subscribers on Stripe Source: https://www.nochurn.sh/blog/stripe-win-back-canceled-customers/ A canceled subscriber is not a stranger. You know what they bought, how long they stayed, and often why they left. That makes them some of the easiest people to sell to again, if you ask at the right time with the right offer. This guide covers what Stripe keeps after a cancellation, how to read the reason, how to plan a win-back sequence, and how to restart billing cleanly when someone comes back. Stripe details come from the [cancel subscription API reference](https://docs.stripe.com/api/subscriptions/cancel), the [customer portal cancellation page](https://docs.stripe.com/customer-management/cancellation-page), [retention rules](https://docs.stripe.com/billing/retention/rules), [coupons and promotion codes](https://docs.stripe.com/billing/subscriptions/coupons) and [using webhooks with subscriptions](https://docs.stripe.com/billing/subscriptions/webhooks) (all accessed November 2026). ## What Stripe keeps after a cancellation When a subscription ends, Stripe sends `customer.subscription.deleted`. The subscription moves to `canceled` and, as the [cancel API reference](https://docs.stripe.com/api/subscriptions/cancel) puts it, you can no longer update it. Coming back means a new subscription. The Customer object is a different matter. It stays, with its email, invoices and payment history. That is what makes win-back practical: you do not start from zero, and if you attach the new subscription to the same Customer, your reporting shows a returning customer rather than a new one. ### Scheduled cancellations are not cancellations yet Many cancellations are set to take effect at the end of the paid period (`cancel_at_period_end`). Until that date, the subscription is still active and the cancellation can be removed. This window is your cheapest win-back: a short "Your access ends on [date]" email with a one-click way to keep the plan often does more than any later campaign. ## Read the reason before you write a word Stripe stores why a subscription ended in `cancellation_details` on the subscription, documented in the [cancel API reference](https://docs.stripe.com/api/subscriptions/cancel): | Field | What it holds | |---|---| | `reason` | Why the subscription ended, for example `cancellation_requested`, `payment_failed` or `payment_disputed` | | `feedback` | The customer's chosen reason: `too_expensive`, `unused`, `missing_features`, `switched_service`, `too_complex`, `low_quality`, `customer_service` or `other` | | `comment` | Free text the customer wrote, up to 5,000 characters | `reason` separates voluntary churn from involuntary churn. A subscription that ended with `payment_failed` was never a decision; the right win-back there is a card update link, not a discount. For more on that split, see [involuntary churn](/blog/involuntary-churn/). `feedback` and `comment` are filled when the customer tells you. If you use Stripe's customer portal, you can [turn on a cancellation page](https://docs.stripe.com/customer-management/cancellation-page) that asks for a reason from Stripe's list, with free text when the customer picks "Other". If you build your own cancel flow, pass the answer to the cancel call so it lives with the subscription. Treat `comment` with care. It is written by the customer and can contain personal details. Store it, read it, but do not paste it into templates. ## Retention at the moment of cancellation Stripe's [retention rules](https://docs.stripe.com/billing/retention/rules) let the customer portal present an offer when a customer tries to cancel, matched on the cancellation reason. Stripe evaluates the rules in the order you define and shows the offer from the first match; if nothing matches, the customer continues to cancel. Offers can be a discount coupon or, if the switch plan option is enabled in the portal, a plan switch. Retention rules replace the older retention coupon setting in the portal configuration. That is prevention, not win-back, but it matters for one reason: if a customer already turned down a discount while cancelling, sending the same discount a week later is unlikely to land. Record what was offered and refused. ## Plan the win-back sequence A practical sequence for most subscription products: | When | Who | Message | |---|---|---| | Before the period ends | Scheduled cancellations | Reminder of the end date, one click to keep the plan | | Day 30 | All voluntary churn | What changed since they left, tied to their reason | | Day 60 | Those who did not return | A specific offer, if the reason was price | | Day 90 | Those who did not return | A last, low-pressure note, and an easy way to stop emails | Match the message to the `feedback` value: 1. **`too_expensive`**: lead with a cheaper plan or a time-limited discount on return. 2. **`missing_features`**: wait until you ship something relevant, then say what it is. No discount needed. 3. **`unused` or `too_complex`**: offer help getting started, a short call or a guide, not money. 4. **`switched_service`**: ask what the other tool does better. Some of these come back; most valuable is the answer. 5. **`customer_service` or `low_quality`**: apologize specifically and say what you fixed. A discount alone reads as dismissive. Examples of full emails are in our [win-back email examples](/blog/win-back-email-examples/). ### Keep the list clean - Exclude customers who disputed a charge (`reason` is `payment_disputed`). - Exclude anyone who asked not to be contacted, and respect marketing consent rules where you operate. - Stop the sequence the moment someone resubscribes. ## Restarting billing when someone comes back ### Use the same Customer Create the new subscription on the existing Customer ID. If you send people to Stripe Checkout, pass the existing customer rather than letting Checkout create a new one, so payment history and reporting stay connected. ### Discounts for returning customers Stripe [coupons](https://docs.stripe.com/billing/subscriptions/coupons) have a duration that controls how long they apply to a subscription: - `once`: the first invoice only. - `repeating`: a set number of months, which you must specify. - `forever`: every invoice. For win-back, `once` or a short `repeating` coupon is usually enough. A `forever` discount for returning customers teaches people to cancel to get a better price. If you share a code, use a promotion code on top of the coupon. One trap: Stripe's promotion codes can be restricted with `restrictions.first_time_transaction`, and Stripe counts a customer with prior payments or non-void invoices as not first-time. A returning customer will fail that check. Use a dedicated win-back code without that restriction, and limit it by expiry date or redemptions instead. ### Check the payment method The card that was on file when they left may have expired or been replaced since. Make the return path go through a page where the customer confirms or updates the card, rather than charging silently. ## Measure it honestly Track, per month of cancellation: - How many customers came back within 90 days, and on which plan. - Which `feedback` values return most, and which never do. - How many returning customers used a discount, and how long they stayed afterward. Count a reactivation only when the new subscription is on the same Customer. Without that, your churn rate and your new customer count are both wrong. See [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ## Doing this with NoChurn NoChurn reads cancellations from Stripe, including `cancellation_details` and the answers from its own cancel flow, and sends win-back emails at day 30, 60 and 90 based on the cancellation reason. For subscriptions that ended on a failed payment, the better path is recovery: smart retries, recovery emails you review, and a hosted card update page. Restarting the subscription and the payment stay in Stripe. See [NoChurn + Stripe](/integrations/stripe/). --- # Visa Compelling Evidence 3.0 explained for subscription merchants Source: https://www.nochurn.sh/blog/visa-compelling-evidence-3/ Subscription businesses have one advantage in fraud disputes: history. A customer who has paid every month for a year and then disputes the thirteenth renewal as "unauthorized" has left a trail of earlier, undisputed payments on the same card. Visa's **Compelling Evidence 3.0** (CE 3.0), in force since April 2023, turns that trail into a formal remedy. This guide explains what CE 3.0 is, which disputes it covers, what data you need, and how a subscription business can be ready for it. It relies on Visa's own documents: the [CE 3.0 merchant readiness guide](https://usa.visa.com/content/dam/VCOM/regional/na/us/support-legal/documents/compelling-evidence-3.0-merchant-readiness-mar2023.pdf) (March 2023), the [Evolution of Compelling Evidence merchant FAQ](https://usa.visa.com/content/dam/VCOM/regional/na/us/support-legal/documents/evolution-of-compelling-evidence-merchant-faqs-mar2023.pdf) and the [Dispute Management Guidelines for Merchants](https://usa.visa.com/dam/VCOM/global/support-legal/documents/merchants-dispute-management-guidelines.pdf) (June 2024), plus Stripe's [CE 3.0 API docs](https://docs.stripe.com/disputes/api/visa-ce3) and [support article](https://support.stripe.com/questions/how-does-stripe-support-visa-compelling-evidence-3-0) (accessed November 2026). Where sources word a rule differently, we say so. ## What CE 3.0 is for CE 3.0 targets first-party misuse: a cardholder who made a purchase, or whose household did, and then reports it as fraud. Visa's idea is simple: if the same cardholder, on the same card, made earlier purchases from you that they did not dispute, and the identifying data matches, the disputed purchase was very likely theirs too. It is not a magic win. Visa's guidelines state that compelling evidence is not a remedy that guarantees an outcome, and Stripe's support article says issuers still have discretion. But when the conditions are met, the case is much stronger, and Stripe's [dispute prevention docs](https://docs.stripe.com/disputes/get-started/prevention) describe cases where the issuer must block the dispute when qualifying evidence is shared before it is filed. ## Which disputes qualify CE 3.0 applies only to **Visa** disputes with reason code **10.4, Other Fraud: Card-Absent Environment**. It does not cover 13.2 (cancelled recurring) or other consumer disputes; those need their own evidence (see [reason codes for subscriptions](/blog/chargeback-reason-codes-subscriptions/)). ## The conditions ### Two prior transactions You need at least **two prior transactions** on the same card that: - were settled between about **120 and 365 days** before the dispute. Visa's 2024 guidelines say 120 to 365 calendar days prior to the dispute processing date; Stripe's API docs say within 120 to 364 days of the disputed transaction; Stripe's support article says more than 119 and fewer than 366 days. The differences only matter at the edges; - were **not reported as fraud** and are not disputed. Stripe adds that they must be paid and cannot be validation charges (such as a zero-amount card check). Visa's FAQ also states the obvious consequence: CE 3.0 is not available for a first-time transaction. A customer in their first four months with you cannot qualify, because no payment is old enough. ### Matching data The prior transactions and the disputed one must share identifying data. Visa's March 2023 readiness guide describes four core data elements: | Element | Example for a SaaS | |---|---| | User ID | Your customer account ID or login | | IP address | IP at checkout or login for that payment | | Device ID or fingerprint | A device identifier from your app or checkout | | Shipping address | Usually not relevant for digital goods | At least two elements must match, and one of the two must be the IP address or the device ID or fingerprint. Stripe's API docs describe the same rule in their own terms: two main evidence elements, or one main element plus one secondary element. Because the wording varies between documents, check the current requirements with your processor. For a subscription, the practical combination is **customer account ID plus IP address** or **account ID plus device ID**. ### Product description Stripe also asks for a description of what was purchased for each transaction, and its prevention onboarding asks merchants to pass product descriptions, IP address and customer email on payments so CE 3.0 can work. ## The subscription problem: renewals have no IP Here is the catch for recurring billing. A renewal is merchant-initiated: no customer is at a browser when it runs, so the payment itself has no IP address or device ID attached. If you only record the IP at signup, your history may have one data point, not one per transaction. What you can do: 1. **Record IP and device at every customer session**, not just checkout. Store them with timestamps against the customer account ID. 2. **Link each renewal to the most recent session** before it. When you build evidence, show the IP and device the customer used around each billed period. 3. **Pass the customer's IP when the customer is present**, for example on upgrades, card updates and the first payment. 4. **Keep the data for at least a year and a few months.** The prior transactions can be up to a year old, and the dispute itself can arrive months after the charge. Whether issuers accept session data in place of transaction-time data is up to Visa's rules and the issuer; your processor's CE 3.0 tooling tells you which fields it sends. ## How it works on Stripe Stripe's [CE 3.0 docs](https://docs.stripe.com/disputes/api/visa-ce3) describe the flow: - For Visa 10.4 disputes, Stripe evaluates your transaction history automatically. - The dispute's `enhanced_eligibility_types` includes `visa_compelling_evidence_3` when it may qualify. - You provide the data in the `enhanced_evidence` object of the dispute evidence: the disputed transaction's details and the prior transactions with their identifiers. - The status in `evidence_details.enhanced_eligibility.visa_compelling_evidence_3.status` is `qualified`, `requires_action` or `not_qualified`. - Stripe tries to fill in prior transactions automatically when it has the data. If the evidence turns out not to qualify after submission, it is still submitted, just not as CE 3.0. Stripe's [changelog](https://docs.stripe.com/changelog/acacia/2024-10-28/visa-compelling-evidence-3-0) lists the API support in the 2024-10-28 release. Other processors offer CE 3.0 in their own way; check their docs. ## Recent changes to watch Visa's [merchant business news digest](https://usa.visa.com/support/merchant/library/visa-merchant-business-news-digest.html) announced two updates: from 17 October 2025, Visa began qualifying some transactions for CE 3.0 automatically through Visa Secure, and from 17 April 2026, Visa introduced a fee associated with successful qualifications. Visa's merchant FAQ and acquirer FAQ also word the original start date differently (pre-arbitration attempts versus disputes processed on or after 15 April 2023). Ask your processor how these changes apply to your account and who bears the fee. ## Building the evidence A CE 3.0 response for a subscription looks like this: 1. **Disputed transaction:** date, amount, product description ("Pro plan, monthly, March 2026"), customer account ID, IP and device from the nearest session. 2. **Prior transaction 1 and 2:** same card, 120 to 365 days old, undisputed, with the same account ID and matching IP or device. 3. **Cover note:** one paragraph tying them together. "Customer acc_123 has paid 14 monthly renewals on this card since January 2025. The two renewals listed were made from the same account and IP. The account was active on the following dates around the disputed charge." 4. **Supporting usage:** logins and activity in the disputed period, which helps even if CE 3.0 does not apply. Keep it short. The issuer reads structured data first. ## Common reasons it fails - **Not 10.4.** CE 3.0 does not apply to other codes. - **Prior transactions too recent.** Monthly customers under four months old cannot qualify. - **No IP or device data.** Account ID alone is not enough. - **Card changed.** Prior transactions must be on the same card. A customer who updated their card recently starts again. - **Earlier disputes.** If a prior transaction was disputed or reported as fraud, it cannot be used. ## Should you rely on it? CE 3.0 is a strong tool for long-lived subscriptions and useless for new ones. It works best alongside prevention: a clear [descriptor](/blog/billing-descriptor-chargebacks/), renewal reminders, and an easy cancel so customers do not reach for the fraud button. Fraud disputes still count toward your [network ratios](/blog/chargeback-ratio-monitoring-programs/) even when you win, so preventing them is worth more than winning them. ## Doing this with NoChurn When a Stripe or Braintree dispute arrives, NoChurn gathers evidence automatically: usage and custom data you send by API (such as logins with IP and device), cancel flow answers, emails sent and help desk conversations (read only). It drafts the reply with AI and sends nothing until a person on your team has reviewed it. Whether a case qualifies for CE 3.0 is decided by Visa's rules, your processor and the issuer. See [chargebacks](/#disputes) and [NoChurn + Stripe](/integrations/stripe/). --- # How to win chargebacks on Stripe Source: https://www.nochurn.sh/blog/win-chargebacks-stripe/ A chargeback on a subscription payment costs you the payment, a fee, and some of your standing with the card networks. You get one chance to answer it, usually within a few weeks, and the bank decides based only on what you send. This guide explains how the dispute process works on Stripe and how to build an evidence packet that fits a subscription business. It sticks to Stripe's own documentation: [how disputes work](https://docs.stripe.com/disputes/how-disputes-work), [respond to disputes](https://docs.stripe.com/disputes/responding), [dispute reason code categories](https://docs.stripe.com/disputes/categories), [dispute reason codes](https://docs.stripe.com/disputes/reason-codes-defense-requirements), [evidence best practices](https://docs.stripe.com/disputes/best-practices), the [Dispute object](https://docs.stripe.com/api/disputes/object), [Smart Disputes](https://docs.stripe.com/disputes/smart-disputes) and the [dispute fees FAQ](https://support.stripe.com/questions/dispute-fees-faq) (all accessed November 2026). Where Stripe's pages leave a gap, we say so. ## The dispute lifecycle A dispute starts when the cardholder contacts their bank. Stripe then creates a Dispute object on the charge and sends the `charge.dispute.created` webhook. From there, the [Dispute object](https://docs.stripe.com/api/disputes/object) moves through a small set of statuses: | Status | What it means | |---|---| | `warning_needs_response` | An inquiry (not yet a chargeback) that needs a response | | `warning_under_review` | An inquiry under review after you submitted evidence | | `warning_closed` | An inquiry closed without becoming a formal dispute | | `needs_response` | A chargeback that needs a response | | `under_review` | A chargeback under review after you submitted evidence | | `won` / `lost` | Resolved in your favor / in the customer's favor | | `prevented` | A dispute that was prevented from becoming a formal chargeback | Inquiries matter because, per Stripe, no funds are withdrawn unless the inquiry is escalated to a dispute. If you lose an inquiry, it escalates: the status changes with a `charge.dispute.updated` event and the funds are withdrawn with `charge.dispute.funds_withdrawn`. When the case ends, `charge.dispute.closed` fires with `won`, `lost` or `warning_closed`. On timing, Stripe's [how disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says you usually have 7 to 21 days to respond after a chargeback is created, depending on the card network, and that the issuer typically takes 60 to 75 days to decide after you submit. The whole process can take two to three months. The exact deadline for each case is on the Dispute object and in the Dashboard; always work from that date, not from a rule of thumb. ## Fees Stripe charges a dispute fee when a dispute is opened, and a separate countered fee if you contest it. According to the [dispute fees FAQ](https://support.stripe.com/questions/dispute-fees-faq) and [Stripe's US pricing page](https://stripe.com/pricing), in the US both are $15.00; the countered fee is returned if you win, and the dispute fee is not returned unless your contract says otherwise. Amounts differ by country, so check the pricing page for yours. Accepting a dispute does not avoid the dispute fee. For Visa and Mastercard compliance disputes, Stripe collects an extra 500 USD network fee (or local equivalent) if you contest, refunded if you win. ## Reason categories Every network has its own reason codes. Stripe maps them to a `reason` value on the dispute, which is the first thing to read because it decides what evidence the bank will look at. The [categories page](https://docs.stripe.com/disputes/categories) lists them; the three that come up most for subscriptions are: - **`fraudulent`**: the cardholder says they did not authorize the payment (for example Visa 10.4, Mastercard 4837). - **`subscription_canceled`**: the cardholder says they were charged after cancelling (Visa 13.2, Mastercard 4841, Amex C28). - **`product_not_received`**: the cardholder says they did not get what they paid for (Visa 13.1, Mastercard 4855). Other values exist, such as `duplicate`, `credit_not_processed`, `product_unacceptable` and `general`. Use the [reason codes page](https://docs.stripe.com/disputes/reason-codes-defense-requirements) to see what the network expects for each one. ## What Stripe accepts as evidence You submit evidence through the Dashboard or by updating the dispute through the [API](https://docs.stripe.com/disputes/api). The `evidence` hash has file fields and text fields. A few that matter for subscriptions, with Stripe's descriptions paraphrased from the [Dispute object](https://docs.stripe.com/api/disputes/object): | Field | Type | Use it for | |---|---|---| | `cancellation_policy` | File | Your cancellation policy as shown to the customer | | `access_activity_log` | Text, max 20,000 characters | Logs proving the customer used the product: IP addresses, timestamps, activity | | `customer_communication` | File | Emails or messages with the customer | | `uncategorized_text` / `uncategorized_file` | Text / file | Anything relevant that does not fit another field | The constraints Stripe documents on [respond to disputes](https://docs.stripe.com/disputes/responding) and [best practices](https://docs.stripe.com/disputes/best-practices): - **One submission.** You can only submit once. After that you cannot edit the response or add evidence. - **Stage first.** Updating the dispute with `submit=false` stages evidence without sending it. A later request with `submit=true` (the default) sends it to the bank. - **One file per evidence type.** Combine several documents of one kind into a single multi-page file. - **Size limits.** Files are limited to a combined 4.5 MB, and Mastercard evidence to a combined 19 pages. All text fields together are limited to 150,000 characters. If the compiled packet is too long, the API returns `dispute_evidence_page_limit_exceeded`. - **No links.** Stripe notes that banks will not review external content, so do not rely on URLs or "call us". ## Evidence that works for subscriptions Stripe's [reason codes page](https://docs.stripe.com/disputes/reason-codes-defense-requirements) gives the direction for each category. Translated to a subscription business: ### Subscription canceled The bank wants to know whether the customer really cancelled before the charge, and whether they agreed to the terms. 1. Show proof the customer accepted the subscription terms, including how and when they could cancel. Upload the relevant section of the policy as `cancellation_policy`, not your whole terms; Stripe suggests highlighting the part that applies. 2. Give the cancellation record with exact timestamps. If the customer never cancelled, or cancelled after the charge, say so with the system log. 3. If they used the product after the date they claim to have cancelled, include usage with timestamps and IPs in `access_activity_log`. 4. If you refunded anything, include the refund record. ### Fraudulent The cardholder says they never authorized the payment. For a subscription, the strongest answer is that the same customer has been paying and using the account for a while. 1. Show the history: earlier undisputed payments on the same card, account creation date, the email on file. 2. Show use of the account: logins, IP addresses, devices, activity around the billing date. 3. Include any communication from that customer that shows they know the service. ### Product not received For digital services, Stripe points to login records, download logs and usage timestamps, plus your terms. Show that the account was provisioned and used during the period that was charged. ### Write a short cover note Whatever the reason, put a plain summary in `uncategorized_text`: who the customer is, what they bought, what happened, and which attached document proves each point. The reviewer reads many cases; make yours easy to follow. ## Early fraud warnings Visa, Mastercard and JCB issuers can send early fraud warnings (EFWs) for payments they suspect are fraudulent, often before any dispute. Stripe exposes them as [Early Fraud Warning objects](https://docs.stripe.com/api/radar/early_fraud_warnings) and the `radar.early_fraud_warning.created` webhook. The object's `actionable` field is true only while the charge has no dispute and has not been fully refunded. Stripe's guidance is not to refund every warning. Its docs say a refund does not remove the warning itself and only prevents the fraud report when it is processed as a reversal, which usually happens within about two hours of capture. Stripe suggests that refunding makes the most sense for charges roughly equal to or below your dispute fee, and gives a [Workflows example](https://docs.stripe.com/workflows/use-cases) that refunds under that amount and alerts a person above it. For a subscription, also consider cancelling the subscription on that card so the next renewal does not create a second dispute. ## Smart Disputes Stripe offers [Smart Disputes](https://docs.stripe.com/disputes/smart-disputes), which assembles an evidence packet from data Stripe already has and, if you take no action, submits it just before the deadline. You can turn off auto-submit in the Dashboard. Stripe's docs say the Smart Disputes fee is charged only when the dispute is won; check the current terms on that page, as Stripe lists the product as a preview. Smart Disputes can only use the data Stripe holds, so evidence that lives in your own systems (logins, usage, support threads) still has to come from you. ## A response checklist 1. Subscribe to `charge.dispute.created`, `charge.dispute.updated`, `charge.dispute.closed` and `radar.early_fraud_warning.created`. 2. On each dispute, read `reason` and the response deadline first. 3. Decide quickly whether to accept. If the customer did cancel and was charged anyway, accepting and fixing the cause may be the honest answer. 4. Gather evidence for that reason: terms accepted, cancellation record, usage logs, communications. 5. Stage the evidence with `submit=false`, check limits, have someone review it, then submit once. 6. Record the outcome and the reason, so you can fix the patterns that cause disputes (unclear billing descriptor, hard-to-find cancel button, missed renewal reminders). ## Doing this with NoChurn NoChurn reads Stripe disputes and gathers evidence for each one automatically: the customer's cancel flow answers, the emails NoChurn sent, usage data you send by API, and conversations from a connected help desk (read only). It drafts the response with AI, and nothing is sent to Stripe until a person on your team has reviewed it. Stripe still decides fees, deadlines and the outcome with the bank, and NoChurn cannot change those. NoChurn is free under $300 MRR, with every feature on every plan. See [NoChurn + Stripe](/integrations/stripe/). --- # Zendesk macros for cancellation and pause requests Source: https://www.nochurn.sh/blog/zendesk-cancellation-macros/ If customers can email support to cancel, your Zendesk agents are running a cancel flow whether you designed one or not. Without macros, each agent improvises: one cancels immediately, another sends three retention offers, a third forgets to confirm the end date. The result is inconsistent for customers and impossible to measure. This guide gives you a small set of macros for cancellation and pause requests, explains how to build them in Zendesk, and sets out the rules that keep them honest. It relies on Zendesk's help center articles on [creating macros](https://support.zendesk.com/hc/en-us/articles/4408844187034-Creating-macros-for-repetitive-ticket-responses-and-actions), [creating macros from existing tickets](https://support.zendesk.com/hc/en-us/articles/4408886850586-Creating-macros-from-existing-tickets), [Liquid markup and placeholders](https://support.zendesk.com/hc/en-us/articles/4408883291290-Understanding-Liquid-markup-and-Zendesk-Support), [suggested macros](https://support.zendesk.com/hc/en-us/articles/4408826078362-Applying-suggested-macros-to-tickets) and the [Comment text condition](https://support.zendesk.com/hc/en-us/articles/4408823778458-How-does-the-Comment-text-condition-work-in-business-rules) (all accessed November 2026). ## How Zendesk macros work A [macro](https://support.zendesk.com/hc/en-us/articles/4408844187034-Creating-macros-for-repetitive-ticket-responses-and-actions) is a saved set of actions an agent applies to a ticket in one click. Actions can add comment text, update ticket fields, add or remove tags, add followers and change the assignee. Points from Zendesk's documentation that matter for this use case: - **Where to create them:** in Admin Center, under Workspaces, Agent tools, Macros, then "Create macro". - **Who can use them:** the "Available for" setting limits a macro to all agents, specific groups, or only you. - **Shared vs personal:** by default, agents can only create personal macros; shared macros are created by admins (or by agents whose custom role allows it, on plans with custom roles). - **From a real ticket:** you can turn a good reply into a macro with "Create as macro" in the ticket options menu. Zendesk suggests rewriting the comment so it is less specific to the original request. - **Placeholders:** macros can insert ticket and user data, such as the requester's first name, with placeholders like `{{ticket.requester.first_name}}`. Custom user fields can be used as placeholders too, which is how you can show a plan name or renewal date if you sync them into Zendesk. ## Rules before the templates Cancellation macros are retention tools, and retention tools are easy to abuse. Four rules: 1. **Cancelling is always an option in the first reply.** The customer must be able to answer "just cancel" and have it done. 2. **One offer, at most.** If the customer declines, cancel. Do not send a second macro with a bigger discount. 3. **Confirm in writing, every time.** State what was cancelled, the effective date, and whether any charge or refund follows. 4. **The macro does not do the cancellation.** Zendesk macros change the ticket, not the subscription. The agent still cancels in your billing system or admin. Build a checklist into the internal note so nobody forgets. Click-to-cancel rules in several jurisdictions require cancellation to be as easy as signing up; see [click-to-cancel rules for SaaS](/blog/click-to-cancel-rules/). ## The macro set Name macros so they sort together in the picker, for example with a `Cancel ::` prefix. ### Cancel :: First reply **Actions:** add tag `cancel-request`, set a custom "Request type" field to Cancellation if you have one, add comment: > Hi `{{ticket.requester.first_name}}`, thanks for getting in touch. I can cancel your subscription for you right away. > > If you have a moment, could you tell me what made you decide to cancel? It helps us improve. If you'd rather not say, just reply "cancel" and I'll take care of it. ### Cancel :: Offer pause Use only when the reason is temporary: a seasonal business, a project ending, a team on leave. **Actions:** add tags `cancel-offer` and `offer-pause`, add comment: > Thanks for explaining. Since it sounds like a quiet period rather than a problem with the product, I can pause your subscription instead: no charges while it's paused, and your data stays as it is. It would restart on [date]. > > If you'd still prefer to cancel, reply "cancel" and I'll do it straight away. ### Cancel :: Offer plan change Use when the reason is price, and you have a cheaper plan that really covers their usage. **Actions:** add tags `cancel-offer` and `offer-downgrade`, add comment: > I understand. Based on how you're using the product, the [plan] plan at [price] would cover what you need. I can switch you now, effective from your next billing date. > > If you'd rather cancel, just reply "cancel" and I'll take care of it. How to choose between pause, discount and downgrade is covered in [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). ### Cancel :: Confirm cancellation **Actions:** add tag `cancel-done`, set status to Solved, add comment: > Your subscription is cancelled. You'll keep access until [end date], and you won't be charged again. If you ever want to come back, you can restart from your account at any time. > > Thanks for having been a customer. ### Cancel :: Confirm pause **Actions:** add tag `cancel-paused`, set status to Solved, add comment: > Done: your subscription is paused until [date]. You won't be charged during the pause. We'll send you a reminder a few days before it restarts, and you can cancel at any point. Only promise the reminder if you actually send one. ### Cancel :: Internal checklist A separate macro that adds an internal note, not a public reply: > Checklist: (1) cancelled or paused in billing, (2) end date confirmed to customer, (3) reason tag added, (4) refund decision noted. ## Tagging reasons The macros tag the outcome. Add a second tag for the reason so you can learn from the requests: `reason-price`, `reason-not-using`, `reason-missing-feature`, `reason-switching`, `reason-support`, `reason-other`. Keep the list short and stable; if you need help choosing categories, see [churn survey questions](/blog/cancellation-reasons-survey/). With outcome and reason tags on every ticket, a monthly report answers: how many cancellation requests came in, which reasons dominate, and which offers were accepted for which reason. ## Getting the right macro in front of agents - **Route cancellation tickets.** A trigger with [Comment text](https://support.zendesk.com/hc/en-us/articles/4408823778458-How-does-the-Comment-text-condition-work-in-business-rules) conditions ("cancel", "close my account", "unsubscribe", "pause") can add the `cancel-request` tag and assign the ticket to the group that handles billing. Expect false matches and review them. - **Suggested macros.** Zendesk can [suggest macros](https://support.zendesk.com/hc/en-us/articles/4408826078362-Applying-suggested-macros-to-tickets) to agents based on the ticket; the availability of this feature depends on your plan, so check it in your account. - **Restrict who can use offer macros.** Use "Available for" to limit discount or plan-change macros to the group that is allowed to grant them. ## Measuring Once tags are in place, build a view or an Explore report of tickets tagged `cancel-request` by month, split by outcome tag. Compare offer acceptance by reason. If a paused customer cancels at the end of the pause, count that too: a pause that only delays churn by two months is still useful, but it is not a save. ## Doing this with NoChurn NoChurn's Zendesk connector is read-only, so your macros, tags and triggers stay in Zendesk and keep working as they are. What NoChurn adds is a self-serve cancel flow you can link to from the first-reply macro: reasons, one matching offer (discount, pause or plan change) and a one-click cancel that is always visible, hosted or built headless with the API. Customers who cancel can get win-back emails at day 30, 60 and 90 based on their reason. NoChurn also reads Zendesk tickets, matched to customers by email (doubtful matches are suggested, never merged automatically), for the churn score and as evidence if a cancelled customer later disputes a charge. See [NoChurn + Zendesk](/integrations/zendesk/). --- # How to use Zendesk tickets as chargeback evidence Source: https://www.nochurn.sh/blog/zendesk-chargeback-evidence/ When a subscriber disputes a charge, your support history is often the strongest evidence you have. A ticket where the customer asked a question about the product after the renewal, or a ticket where you confirmed their cancellation and refunded them, can decide the case. A ticket that was paraphrased, redacted badly or exported without dates is worth much less. This guide covers what makes a Zendesk ticket useful as evidence, how to set up fields and macros so the right facts are captured at the time, and how to get tickets out of Zendesk in a form a card network reviewer can read. Zendesk features come from Zendesk's own documentation: [printing tickets](https://support.zendesk.com/hc/en-us/articles/4408836523930-Printing-tickets), [exporting data](https://support.zendesk.com/hc/en-us/articles/4408886165402-Exporting-ticket-user-or-organization-data-from-your-account), [custom ticket fields](https://support.zendesk.com/hc/en-us/articles/4408883152794-Adding-custom-ticket-fields-to-your-tickets-and-forms), [macro actions](https://support.zendesk.com/hc/en-us/articles/4408832783642-Building-macro-action-statements), [redaction](https://support.zendesk.com/hc/en-us/articles/4408846470170-Redacting-ticket-content) and the [Ticket Audits](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/) and [Ticket Comments](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_comments/) APIs. Dispute fields come from Stripe's [dispute categories](https://docs.stripe.com/disputes/categories) and [evidence best practices](https://docs.stripe.com/disputes/best-practices) (all accessed November 2026). ## What a reviewer is looking for A dispute is decided by someone at the card issuer who has never heard of your product and has a few minutes to read your file. For subscription disputes, the questions are usually simple: - Did the customer know they would be charged? - Did they try to cancel, and if so, when, and what happened? - Did they keep using the service after the charge? For the "subscription canceled" category, Stripe's [dispute categories page](https://docs.stripe.com/disputes/categories) points you to the `cancellation_rebuttal` field (why the subscription was not cancelled, or why the charge is still valid) and `customer_communication` (correspondence showing the customer kept using the service or knew about the renewal). Stripe's [best practices](https://docs.stripe.com/disputes/best-practices) recommend combining several communications, such as emails and chat transcripts, into a single file for that field. A Zendesk ticket can answer all three questions, if it has three things. ## The three things that make a ticket evidence ### 1. Timestamps you can trust Every comment in Zendesk carries its own creation time, and Zendesk keeps an audit trail. The [Ticket Audits API](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/) describes audits as a read-only history of all updates to a ticket, each with its own `created_at`. That matters: a dispute often turns on whether the customer wrote before or after a renewal date. When you present a ticket, show the date and time of every message and state the time zone. Zendesk's data export page notes that CSV timestamps use the account's default time zone; your billing provider may use UTC. Put both on the same basis before you build a timeline. ### 2. The customer's own words Quote, don't paraphrase. "Customer confirmed they were using the reports feature" is your opinion. A dated message from the customer's email address saying "the export in reports is broken again, can you fix it before our board meeting" is evidence. Keep these rules: - Quote the full message, or a clearly marked excerpt with "[…]" where you cut. - Never correct, summarise or translate inside the quote. If you translate, give the original next to it. - Include messages that hurt your case if they are relevant. A reviewer who finds an omitted cancellation request will not trust the rest of the file, and submitting a misleading file is not something you should do anyway. ### 3. A clear resolution The ticket should show how it ended: cancelled on a given date, refunded, credit issued, question answered. If an agent cancelled a subscription, the ticket should say so in a public reply to the customer, not only in an internal note. ## Set up Zendesk to capture this at the time Evidence is much easier to find when it was labelled the day it was created. ### Custom fields Zendesk's [custom ticket fields guide](https://support.zendesk.com/hc/en-us/articles/4408883152794-Adding-custom-ticket-fields-to-your-tickets-and-forms) explains that admins add fields in Admin Center under Objects and rules > Tickets > Fields. Drop-down options each get their own tag. Useful fields for disputes: | Field | Type | Values | |---|---|---| | Billing request | Drop-down | Cancel request, Refund request, Charge question, Downgrade, None | | Cancellation outcome | Drop-down | Cancelled immediately, Cancelled at period end, Customer withdrew request, Not applicable | | Refund issued | Checkbox | Yes / No | | Billing customer ID | Text | The ID from your billing system | Do not create a field for card numbers or full payment details. You never need them as evidence, and Zendesk documents [automatic redaction of credit card numbers](https://support.zendesk.com/hc/en-us/articles/4408822124314-Automatically-redacting-credit-card-numbers-from-tickets) (Professional plans and above) for when customers paste them anyway. Per Zendesk, it keeps the first six and last four digits and does not apply to numbers already in the system; older ones have to be [redacted manually](https://support.zendesk.com/hc/en-us/articles/4408846470170-Redacting-ticket-content), which is irreversible. ### Macros for refund and cancel requests Zendesk's [macro actions](https://support.zendesk.com/hc/en-us/articles/4408832783642-Building-macro-action-statements) can set drop-down, multi-select and checkbox fields, and set, add or remove tags. A "Cancel request handled" macro could: 1. Post a public reply confirming the cancellation and the date it takes effect. 2. Set Billing request to Cancel request. 3. Set Cancellation outcome to the matching value. 4. Add a tag such as `cancel_confirmed`. The confirmation reply is the important part. It turns "we cancelled it" into a dated message in the customer's inbox and on the ticket. Keep the wording factual: what was cancelled, from when, and whether any refund applies. Zendesk's macro actions list covers tag-setting fields (drop-down, multi-select, checkbox), so plan on the billing customer ID coming from an integration or being typed by the agent. ## Getting tickets out ### One ticket at a time: print Zendesk's [printing tickets article](https://support.zendesk.com/hc/en-us/articles/4408836523930-Printing-tickets) describes opening the ticket, clicking the Ticket options menu and choosing Print ticket. You can choose whether to include internal notes and side conversations (Suite Professional and above). For evidence, leave internal notes out unless they matter: they are written for colleagues and can read badly out of context. Print to PDF and check every message shows its date. ### Many tickets: export or API | Method | Includes comments? | Notes from Zendesk's docs | |---|---|---| | Admin Center data export, JSON | Yes | Off by default; the account owner asks Zendesk Support to enable it; comments are dropped for tickets over 1 MB | | Admin Center data export, CSV | No | Ticket fields only; no comments or descriptions | | View export to CSV | No | Fields of the tickets in a view | | Ticket Comments API | Yes | Can be sorted by `created_at` | | Ticket Audits API | Yes, with every change | Read-only history of all updates | Sources: [data export](https://support.zendesk.com/hc/en-us/articles/4408886165402-Exporting-ticket-user-or-organization-data-from-your-account), [view export](https://support.zendesk.com/hc/en-us/articles/5521220496154-Exporting-a-view-of-tickets-to-a-CSV-file), [Ticket Comments](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_comments/), [Ticket Audits](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/). The CSV exports are useful to find the right tickets (filter on your Billing request field) but not as evidence on their own, because they leave out what the customer wrote. ## Building the evidence file, step by step 1. Find every ticket from the disputing customer's email address, and any other address on their account. 2. Sort all messages by time and place them on one timeline with billing events: signup, renewal notices, charges, cancellation. 3. Pick the messages that answer the reviewer's questions. Quote them in full with date, time zone and sender. 4. Write a short cover note in plain language: "The customer contacted support on [date] about [feature], [N] days after the disputed charge. Full message below." 5. Combine the transcripts into one file for `customer_communication`, as Stripe recommends. 6. Check nothing in the file contains card numbers or unrelated personal data. 7. Submit before the deadline shown on the dispute. ## Doing this with NoChurn NoChurn's Zendesk connector is read-only: it reads tickets and never replies, tags or edits anything in Zendesk. Tickets are matched to your customers by email; doubtful matches are suggested for you to confirm and never merged automatically. When a dispute opens on Stripe or Braintree, NoChurn gathers the evidence automatically (cancel flow answers, emails sent, usage, and the matched Zendesk messages, quoted verbatim with their dates), drafts a reply with AI, and sends it only after you review it. Ticket handling, macros and redaction stay in Zendesk, and the dispute decision stays with the card issuer. See [NoChurn + Zendesk](/integrations/zendesk/). --- # How to spot churn signals in Zendesk tickets Source: https://www.nochurn.sh/blog/zendesk-churn-signals/ Customers rarely cancel without warning. The warning just lands in a place nobody connects to revenue: a support ticket about an invoice, a third bug report in a month, a sharp message that ends with "we're looking at alternatives". If those tickets live in Zendesk, you can catch them, but only if you tag them consistently and check them against who actually cancels. This guide covers which ticket signals are worth tracking, how to capture them with Zendesk's own tools, and how to test them against churn. It sticks to Zendesk's documentation: [intelligent triage](https://support.zendesk.com/hc/en-us/articles/4964463770650-About-intelligent-triage), [how the Comment text condition works](https://support.zendesk.com/hc/en-us/articles/4408823778458-How-does-the-Comment-text-condition-work-in-business-rules), the [Explore recipe for sentiment and intent changes](https://support.zendesk.com/hc/en-us/articles/9387513640090-Explore-recipe-Tracking-sentiment-and-intent-changes-in-tickets), and the [Incremental Exports API](https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/) (all accessed November 2026). ## Signals worth tracking Not every unhappy ticket predicts churn. These are the kinds of signal that tend to be worth testing, grouped by what they suggest: | Signal | What it can mean | How to capture it in Zendesk | |---|---|---| | Explicit cancellation or downgrade request | Decision already being made | Tag via trigger on keywords, or intent from intelligent triage | | Mention of a competitor or "alternatives" | Evaluation under way | Trigger on Comment text with competitor names | | Billing confusion (unexpected charge, invoice question) | Risk of cancellation or dispute | Ticket form or field for billing, plus tag | | Repeated bugs on the same feature | Product not delivering | Tag by feature, count per organization | | Negative sentiment, especially worsening | Frustration building | Intelligent triage sentiment | | Sudden silence after heavy use | Disengagement | Not visible in Zendesk alone; needs product data | | Bad CSAT rating with comment | Support or product failure | Satisfaction ratings (see [using Zendesk CSAT](/blog/zendesk-csat-churn/)) | Treat this list as hypotheses. Which ones matter for your business is something you check, not something you assume. ## Capturing signals with Zendesk's own tools ### Intelligent triage: intent, sentiment, language [Intelligent triage](https://support.zendesk.com/hc/en-us/articles/4964463770650-About-intelligent-triage) adds AI-predicted fields to tickets: a topic (labelled "Intent" on some accounts), sentiment and language. According to Zendesk's documentation: - Sentiment has five levels, from very negative to very positive, and each prediction comes with a confidence value. - The model is calibrated for customer service, so a ticket is not marked negative just because the customer has a problem. - Classification is based on the ticket subject and first public comment. Topic and sentiment can be re-evaluated on later customer messages; on messaging channels the whole conversation is used. - It only applies to tickets created after you turn it on. - Classifications are available on Suite and Support Professional plans and above; using them in triggers and other workflows requires the Copilot add-on. Zendesk publishes an [Explore recipe](https://support.zendesk.com/hc/en-us/articles/9387513640090-Explore-recipe-Tracking-sentiment-and-intent-changes-in-tickets) for tracking how sentiment and intent change over a ticket's life. A ticket that starts neutral and ends very negative is a stronger signal than one that was negative from the first message and got resolved. ### Triggers on comment text If you do not have intelligent triage, keyword triggers still work. Zendesk's [Comment text condition](https://support.zendesk.com/hc/en-us/articles/4408823778458-How-does-the-Comment-text-condition-work-in-business-rules) also looks at the subject when a ticket is created, and at the latest comment when it is updated. It offers operators such as "contains at least one of the following words" and "contains the following string". Each phrase needs its own condition under "Meet ANY of the following conditions". A simple churn-signal trigger: 1. In Admin Center, create a ticket trigger. 2. Under **Meet ANY**, add Comment text conditions for phrases such as "cancel", "close my account", "switching to", "too expensive", "refund", and the names of your main competitors. 3. Under **Actions**, add a tag such as `churn-signal` (use "Add tags", which appends, rather than "Set tags", which replaces existing tags; see the [automation conditions and actions reference](https://support.zendesk.com/hc/en-us/articles/4408885654298-Automation-conditions-and-actions-reference)). 4. Optionally, add a second tag per category (`signal-price`, `signal-competitor`) so you can compare them later. Keyword matching is noisy. "Cancel the meeting" and "refund policy question" will match. Review a sample of tagged tickets every week for the first month and tighten the phrases. ### Fields and forms for billing tickets A dedicated ticket form or a "Billing" drop-down field gives you cleaner data than keywords. If customers pick "Billing question" when they open a ticket, you get the category without guessing. Combine it with the organization or user, and you can count billing tickets per account. ### Views for a weekly review Create a view of open and recently solved tickets tagged `churn-signal`, grouped by organization. Someone on the customer success or support team reviews it weekly and decides who needs a proactive follow-up. This is the step most teams skip, and it is the one that turns signals into saved accounts. ## Checking signals against real churn A signal is only useful if customers who show it cancel more often than customers who do not. To check: 1. **Export ticket data.** Zendesk's [Incremental Exports API](https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/) returns tickets changed since a given time, including tags and custom fields. For one-off analysis, an Explore export also works. 2. **Export billing data.** From Stripe or your billing system: customer, email, start date, cancellation date, and whether churn was voluntary or caused by a failed payment. 3. **Match tickets to customers by email.** Zendesk users can have [several email identities](https://support.zendesk.com/hc/en-us/articles/4408822763546-Managing-end-users); check all of them, not just the primary one. For B2B, decide whether you match at the user or organization level. 4. **Use a fixed window.** For example: signals in the 60 days before a reference date, churn in the 90 days after. Otherwise older customers look riskier just because they had more time to file tickets. 5. **Compare voluntary churn rates** between customers with and without each signal. Leave involuntary churn out of this comparison; a card expiring is not caused by a support ticket. 6. **Report counts.** "4 of 12 tagged customers churned" is honest. "33% churn rate" hides that it is 12 customers. For the formulas, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). For a broader method that combines support data with product and billing attributes, see [how to find what predicts churn with your own customer data](/blog/predict-churn-with-customer-data/). ## Pitfalls - **More tickets is not always worse.** Customers who file tickets are using the product. In many businesses the riskier group is the one that never contacts support at all. - **Do not merge users to make matching easier.** Zendesk's [user merge](https://support.zendesk.com/hc/en-us/articles/4408887695898-Merging-a-user-s-duplicate-account) cannot be undone. Match in your analysis, not in Zendesk. - **Watch for drift.** If you change a form or a trigger, your signal counts change too. Note the date of every change. - **Remember it is correlation.** A signal that predicts churn tells you who to talk to. It does not prove that fixing that ticket would have kept the customer. ## Doing this with NoChurn NoChurn's Zendesk connector is read-only: it never writes tags, fields or replies, so your triggers and views stay as they are. It reads tickets and matches them to billing customers by email (doubtful matches are suggested for you to confirm, never merged automatically). Those tickets feed the 0–100 churn score and the churn drivers analysis, which ranks the attributes most correlated with churn alongside billing data and any custom data you push by API. The same tickets are kept as dated, verbatim evidence if a customer later disputes a charge. See [NoChurn + Zendesk](/integrations/zendesk/). --- # Using Zendesk CSAT to find customers about to churn Source: https://www.nochurn.sh/blog/zendesk-csat-churn/ Zendesk CSAT is usually read as a team metric: what share of solved tickets were rated good this month. Read per customer instead, it becomes something else: a list of people who just told you, in one click, that something went wrong. Some of them are about to leave. This guide explains what Zendesk's satisfaction data contains, how to get it out, how to follow up on bad ratings quickly, and how to test whether ratings predict churn in your business. It relies on Zendesk's documentation for the [CSAT user experience](https://support.zendesk.com/hc/en-us/articles/4408886173338-About-the-CSAT-Customer-Satisfaction-user-experience-for-email-and-messaging), [sending a CSAT survey](https://support.zendesk.com/hc/en-us/articles/7689997846554-Sending-a-CSAT-survey-to-your-customers), [satisfaction reasons](https://support.zendesk.com/hc/en-us/articles/4408829326234-Working-with-satisfaction-reasons), [unexpected bad ratings](https://support.zendesk.com/hc/en-us/articles/4408831380122-Why-am-I-receiving-unexpected-bad-satisfaction-ratings), and the [Satisfaction Ratings](https://developer.zendesk.com/api-reference/ticketing/ticket-management/satisfaction_ratings/) and [CSAT Survey Responses](https://developer.zendesk.com/api-reference/ticketing/ticket-management/csat_survey_responses/) API references (all accessed November 2026). ## How Zendesk collects CSAT The survey is tied to solved tickets. For messaging channels, Zendesk creates a system trigger that shows the survey right after a ticket is solved. For email, a default automation sends the request 24 hours after the ticket is set to solved, according to Zendesk's [CSAT experience article](https://support.zendesk.com/hc/en-us/articles/4408886173338-About-the-CSAT-Customer-Satisfaction-user-experience-for-email-and-messaging). With the current survey experience described in [Sending a CSAT survey](https://support.zendesk.com/hc/en-us/articles/7689997846554-Sending-a-CSAT-survey-to-your-customers), admins choose the rating scale (two, three or five points), and can add an open-ended question. Zendesk also supports [satisfaction reasons](https://support.zendesk.com/hc/en-us/articles/4408829326234-Working-with-satisfaction-reasons): a drop-down of reasons shown when a customer gives a negative rating. Reasons are optional for the customer. Messaging surveys only show the comment prompt after the customer has clicked a rating. ## What the data looks like There are two API representations, and it helps to know both. **Satisfaction ratings.** The older [Satisfaction Ratings](https://developer.zendesk.com/api-reference/ticketing/ticket-management/satisfaction_ratings/) endpoint (`GET /api/v2/satisfaction_ratings`) returns ratings with a score of `offered`, `unoffered`, `good` or `bad`. You can filter by score, including variants with and without comments, and by a `start_time`. "Offered" means the customer was sent a survey and has not answered; "unoffered" means no survey was sent. **CSAT survey responses.** The [CSAT Survey Responses](https://developer.zendesk.com/api-reference/ticketing/ticket-management/csat_survey_responses/) API covers the newer survey, with ratings grouped as bad, neutral or good. Zendesk's guide on [getting CSAT survey responses](https://developer.zendesk.com/documentation/ticketing/data-and-reporting/processing-csat/) recommends this data for more accurate feedback when you use the newer survey. Either way, each rating ties back to a ticket, and the ticket to a requester and, often, an organization. That is the path to a customer. ## One data quality problem to fix first Zendesk documents a known cause of [unexpected bad ratings](https://support.zendesk.com/hc/en-us/articles/4408831380122-Why-am-I-receiving-unexpected-bad-satisfaction-ratings): email security scanners that follow every link in a message. Because the rating stores the last link clicked, a scanner clicking "good" then "bad" records a bad rating the customer never gave. Zendesk's recommended fix is to replace the direct good and bad links in the CSAT email with a link to the survey landing page. If you plan to use bad ratings as a churn signal, fix this first. Otherwise some of your "unhappy customers" are a mail filter at a large company. ## Following up on bad ratings The fastest win does not need any analysis: someone reads every bad rating within a day and acts on it. 1. **Build a view.** Zendesk documents a [view for ratings with comments](https://support.zendesk.com/hc/en-us/articles/4408886290970-How-can-I-track-satisfaction-ratings-with-comments-), using conditions such as "Satisfaction Is Bad with comment". Create one for bad ratings with and without comments. 2. **Assign an owner.** A team lead or customer success manager, not the agent who handled the ticket. 3. **Read the comment and reason**, then look at the account: plan, tenure, recent billing events, other open tickets. 4. **Reply personally** to what the customer said. A short message from a named person that fixes or explains something does more than a generic apology. 5. **Tag the outcome** (`csat-followup-done`, `csat-followup-churned`) so you can measure it later. For reporting, Zendesk publishes an [Explore recipe for bad ratings with comments](https://support.zendesk.com/hc/en-us/articles/4408838658074-Explore-recipe-Bad-ratings-with-comments). ## Reading reasons and comments Scores tell you that something went wrong; satisfaction reasons and comments tell you what. Before any statistics, read a month of bad ratings with comments and sort them into a handful of themes: - **Support experience:** slow reply, unclear answer, ticket closed too early. - **Product problem:** a bug, a missing feature, something that does not work as advertised. - **Billing problem:** an unexpected charge, a renewal the customer forgot about, a refund refused. - **Not about you:** a rating clicked by mistake, or a complaint about something outside your control. The second and third groups are the ones most worth comparing with churn. A customer upset about a slow reply may stay once it is fixed; a customer upset about a charge is also a dispute risk, so check their billing at the same time. ## Testing whether ratings predict churn A bad rating feels like a churn signal. Check it. ### Build the dataset 1. **Export ratings** for a period, using either API above, with ticket ID, requester, organization, score, reason, comment and date. 2. **Export billing customers** with start date, cancellation date and churn type (voluntary or failed payment). 3. **Match requesters to customers by email.** Zendesk users can have [several email identities](https://support.zendesk.com/hc/en-us/articles/4408822763546-Managing-end-users); use all of them. In B2B, decide whether a rating from any user counts for the organization. 4. **Fix a window.** Ratings in the 90 days before a reference date; churn in the 90 days after. ### Compare groups | Group | Definition | |---|---| | At least one bad | One or more bad ratings in the window | | Good only | Only good ratings | | Offered, never answered | Surveys sent, no response | | No solved tickets | No survey offered in the window | Compute voluntary churn in each group, with the customer count next to every rate. Leave failed-payment churn out; see [involuntary churn](/blog/involuntary-churn/) for why it behaves differently. The churn formulas are in [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ### Read it with care - **Response rates shape everything.** If few customers answer, the "bad" group is small and self-selected. The "offered, never answered" group can be as informative as the bad ratings. - **Reasons matter more than scores.** A bad rating with the reason "issue not resolved" is a different signal from "agent was slow". Break the comparison down by reason when you have enough data. - **Follow-up changes the result.** If you start following up on bad ratings, their link to churn should weaken. That is the goal, not a broken analysis. - **Correlation, not causation.** A bad rating can be a symptom of a decision already made. It still tells you who to talk to. If CSAT does not separate churners from stayers in your data, look at other support signals; see [how to spot churn signals in Zendesk tickets](/blog/zendesk-churn-signals/). ## Doing this with NoChurn NoChurn's Zendesk connector is read-only: it does not send surveys, change your CSAT settings or write to tickets. It reads tickets and their satisfaction ratings, matches requesters to billing customers by email (doubtful matches are suggested for you to confirm, never merged automatically), and uses them as inputs to the 0–100 churn score and to churn drivers, which ranks the attributes most correlated with churn (correlation, not causation). You can push other attributes by API, such as product usage, to see how support signals compare. See [NoChurn + Zendesk](/integrations/zendesk/). --- # How to handle refund requests in Zendesk before they become chargebacks Source: https://www.nochurn.sh/blog/zendesk-refund-requests/ A chargeback is often a refund request that nobody answered in time. The customer writes to support, waits, gets a vague reply or none, then calls their bank. From that moment, a simple refund turns into a dispute with a fee, a deadline, a mark on your dispute rate and an outcome you no longer control. This guide shows how to set up Zendesk so refund requests are spotted, answered fast and decided consistently, and how to keep the record you will need if a dispute happens anyway. It relies on Zendesk's documentation for the [Comment text condition](https://support.zendesk.com/hc/en-us/articles/4408823778458-How-does-the-Comment-text-condition-work-in-business-rules), [macros](https://support.zendesk.com/hc/en-us/articles/4408844187034-Creating-macros-for-repetitive-ticket-responses-and-actions), [intelligent triage](https://support.zendesk.com/hc/en-us/articles/5222280338202-Intelligent-triage-use-cases-and-workflows) and [printing tickets](https://support.zendesk.com/hc/en-us/articles/4408836523930-Printing-tickets), and on Stripe's [How disputes work](https://docs.stripe.com/disputes/how-disputes-work), [fraud prevention best practices](https://docs.stripe.com/disputes/prevention/best-practices) and [dispute evidence best practices](https://docs.stripe.com/disputes/best-practices) (all accessed November 2026). The payment side uses Stripe as the example; check your own processor's rules if you use another. ## Why speed matters more than the decision Two facts from Stripe's documentation explain why refund requests deserve priority: - **Once a dispute is open, the refund door closes.** Stripe's [How disputes work](https://docs.stripe.com/disputes/how-disputes-work) page says you cannot issue a refund outside the dispute process while a dispute is open. The only way to overturn it is to submit evidence. - **A full refund prevents a dispute; a partial one does not.** According to the same page, customers cannot dispute fully refunded payments, but they can dispute partially refunded ones. So the question is not only "should we refund?" but "can we decide before the customer goes to their bank?" ## Spotting refund requests in Zendesk ### Keyword trigger A ticket trigger using the [Comment text condition](https://support.zendesk.com/hc/en-us/articles/4408823778458-How-does-the-Comment-text-condition-work-in-business-rules) catches most requests. The condition looks at the subject on creation and the latest comment on updates. Under "Meet ANY of the following conditions", add one condition per phrase: - "refund", "money back", "charged twice", "double charged" - "didn't authorize", "did not authorize", "unauthorized", "don't recognize this charge" - "dispute", "chargeback", "my bank" Actions: add the tag `refund-request`, set priority to High, assign to the billing group. Give the second group of phrases its own tag (`charge-not-recognized`). A customer who does not recognize a charge is the one most likely to go straight to their bank, and the one most likely to be a fraud case rather than a refund case. ### Intelligent triage If you have [intelligent triage](https://support.zendesk.com/hc/en-us/articles/5222280338202-Intelligent-triage-use-cases-and-workflows), the predicted intent and sentiment can route refund tickets without keyword lists. Zendesk's use case guide suggests, for example, raising the priority of very negative tickets or sending them to a senior group. Using these predictions in triggers requires the Copilot add-on; the classifications themselves are available on Suite and Support Professional plans and above. ### A billing form or field A "Billing" ticket form with a "Request type" field (Refund, Charge not recognized, Invoice question, Cancel) gives cleaner data than any keyword. It only works for tickets created through your help center or widget, so keep the trigger for email. ## Answering fast Set a target first reply time for `refund-request` and `charge-not-recognized` tickets that is shorter than your normal one, and keep a view of those tickets sorted by age so nothing waits unseen. The reply does not need to contain the decision. It needs to tell the customer that a person is on it and when they will hear back. A first-reply macro: > Hi `{{ticket.requester.first_name}}`, thanks for reaching out about this charge. I'm looking into it now and will get back to you by [time] with an answer. You don't need to contact your bank; we'll sort this out directly. Only say the last sentence if you mean it and will follow through. ## Deciding consistently Write down a refund policy your agents can apply without escalating every ticket. A simple decision table: | Situation | Typical decision | |---|---| | Charged after a cancellation the customer did request | Full refund, confirm cancellation | | Annual renewal charged, customer did not use it after renewal | Full or prorated refund, per your published policy | | Duplicate charge | Refund the duplicate | | Customer does not recognize the charge, no account match | Escalate as possible fraud | | Customer used the service and wants money back | Per your policy; explain it clearly if you decline | Two Stripe points to keep in mind: - **Partial refunds can still be disputed.** If you offer a partial refund, explain it, and know that the customer can still dispute the rest. - **Early fraud warnings.** If Stripe flags a payment with an early fraud warning, its [fraud prevention guidance](https://docs.stripe.com/disputes/prevention/best-practices) says you can refund proactively to prevent the cardholder from disputing, but that refunding every warning automatically is not a good strategy. A refund also does not remove a fraud report from card network counts. ## Writing the decision When you refund: > I've refunded [amount] to your card ending in [last4]. It can take a few business days to appear, depending on your bank. Your subscription is [cancelled / still active until date]. Let me know if anything else looks wrong. When you decline: > I've looked at your account. Your subscription renewed on [date] under the terms you accepted at signup, which you can read here: [policy]. Since then, the account has been used on [dates]. I'm not able to refund this charge, but I've cancelled the renewal so you won't be charged again. If you have questions, reply here and I'll help. A decline written like this is also good evidence: it is factual, dated and polite, and it shows the customer was offered a resolution. ## Keeping the record If a dispute arrives anyway, the ticket is part of your answer. Stripe's [evidence best practices](https://docs.stripe.com/disputes/best-practices) ask you to state whether the customer tried to resolve the issue with you before disputing, and to include relevant communication as excerpts in a single file. From Zendesk: - **One ticket:** use [Print ticket](https://support.zendesk.com/hc/en-us/articles/4408836523930-Printing-tickets) from the ticket options menu and save as PDF from the browser. You can choose whether to include internal notes; for evidence, leave them out. There is no bulk print. - **Many tickets or automation:** Zendesk points to the [Ticket Comments](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_comments/) and [Ticket Audits](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/) APIs, which return each comment with its author and timestamp. Keep the customer's own words verbatim, with dates. Do not edit them. ## Measuring Track three numbers each month: refund requests received, median time to first reply on them, and disputes from customers who had an open or recent refund ticket. If that last number is not zero, look at those tickets one by one. They usually show a reply that came too late or a decision that was never explained. ## Doing this with NoChurn NoChurn's Zendesk connector is read-only, so refunds, replies and triggers stay with your team in Zendesk and Stripe. NoChurn reads tickets and matches them to customers by email (doubtful matches are suggested, never merged automatically), and uses them in the churn score. When a dispute opens on Stripe or Braintree, it gathers the evidence automatically, including dated verbatim excerpts from Zendesk tickets, cancel flow answers, emails sent and usage, and drafts a reply with AI that is only sent after someone on your team reviews it. See [NoChurn + Zendesk](/integrations/zendesk/). --- # How to add a cancel flow to Zuora Source: https://www.nochurn.sh/blog/zuora-cancel-flow/ Zuora is built to manage subscriptions, not to talk customers out of cancelling. It gives you precise cancellation dates, suspend and resume, discount charges and events, but no customer-facing screen that asks why someone is leaving or offers an alternative. A cancel flow is the layer you put in front of those tools. This guide explains the Zuora building blocks a cancel flow relies on, then shows how to put them together. It sticks to Zuora's own documentation: [Cancel a subscription (API)](https://developer.zuora.com/v1-api-reference/api/operation/PUT_CancelSubscription/), [Order, subscription and amendment dates](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/common-subscription-information/order-subscription-and-amendment-dates), [Cancel a subscription using the Zuora UI](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/orders/order-actions-tutorials/subscriptions-cancellation-by-order-creation/cancel-a-subscription-using-the-zuora-ui), [Suspend a subscription (API)](https://developer.zuora.com/v1-api-reference/api/operation/PUT_SuspendSubscription/), [Specify the discount scope](https://docs.zuora.com/en/zuora-billing/set-up-zuora-billing/build-product-and-prices/charge-models---configure-any-pricing/discount-pricing/discount-charge-models/specify-the-discount-scope) and [Zuora custom events for Orders](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/zuora-custom-events/zuora-custom-events-for-orders) (all accessed November 2026). ## What a cancel flow needs to do A cancel flow sits between the "Cancel subscription" button and the actual cancellation: 1. **Ask why**, with a short list of reasons and an optional free-text answer. 2. **Offer an alternative that matches the reason**: a discount for price, a pause for "not using it right now", a cheaper or different plan for "missing feature" or "too much". 3. **Cancel immediately if the customer still wants to.** The cancel button stays visible at every step. Many jurisdictions now require cancellation to be as easy as sign-up; see [our guide to click-to-cancel rules](/blog/click-to-cancel-rules/). 4. **Record the outcome** so you can see which reasons and offers actually work. Each of those steps maps to a Zuora operation. ## Cancelling: the three cancellation policies Zuora's [cancel operation](https://developer.zuora.com/v1-api-reference/api/operation/PUT_CancelSubscription/) and the Orders cancel action accept a cancellation policy: | Policy | What happens | Notes from Zuora's docs | |---|---|---| | End of current term | Billing runs until the term ends | The cancellation date is filled in with the term end date; not available in the UI for evergreen subscriptions | | End of last invoice period | Billing stops after the last invoiced service period | Date filled in automatically | | Specific date | Billing stops on the date you give | The date cannot be before the contract effective date, after the term end, or inside an already-invoiced period | Zuora also separates two dates that a cancel flow should keep apart, per its [dates documentation](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/common-subscription-information/order-subscription-and-amendment-dates): - the **contract effective date**, when the customer gave notice; - the **cancellation date**, when service actually ends. So a customer can cancel today (contract effective date) with service running to the end of the paid period (cancellation date). For a self-serve cancel flow, "end of last invoice period" usually matches what customers expect: they keep what they paid for, and nothing more is billed. If you choose a specific date, Zuora advises checking the service period on the last posted invoice first, because a wrong date can create unexpected credits or charges. Two more points from Zuora's docs: - Cancellation applies to a **subscription**, not to the billing account. A customer with several subscriptions needs each one cancelled. - Cancellation can be combined with refunds or write-offs of unpaid invoices; Zuora documents these as separate scenarios ([cancel with refund](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/orders/order-actions-tutorials/subscriptions-cancelation-for-different-scenarios/subscriptions-cancellation-and-refund-end-customers-automatically/cancel-a-subscription-with-a-refund-using-the-zuora-ui), [cancel and write off](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/orders/order-actions-tutorials/subscriptions-cancelation-and-write-off-all-unpaid-invoices/cancel-a-subscription-and-write-off-all-unpaid-invoices-using-the-zuora-ui)). Decide your policy before you build the flow. ## The pause offer: suspend and resume Zuora supports **suspending** a subscription and resuming it later, which is the natural backing for a pause offer. From the [suspend API reference](https://developer.zuora.com/v1-api-reference/api/operation/PUT_SuspendSubscription/) and the [Orders suspend guide](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/orders/order-actions-tutorials/subscriptions-suspension/use-the-zuora-ui---suspend-subscriptions): - Suspend only works on subscriptions in **Active** status, and requires a suspend policy (for example today, end of the last invoice period, a number of periods from today, or a specific date). - You can resume on a specific date or a fixed period after the suspend date, and optionally extend the term by the suspended period. - Without a resume date, the subscription stays suspended until someone resumes it. - The resume date cannot be before the suspend date or after the subscription term end date. - While suspended, the only action available on the subscription is to resume it. For a cancel flow, always set a resume date when you suspend. An open-ended pause is just a cancellation that nobody followed up on. Offer one or two fixed lengths (one month, three months) and send a reminder a few days before the resume date. For when a pause beats a discount, see [pause vs discount retention offers](/blog/pause-vs-discount-retention-offers/). ## The discount offer: discount charges Discounts in Zuora are **discount charges** in a product rate plan, added to the subscription through an order (Add Product). Zuora's [discount scope documentation](https://docs.zuora.com/en/zuora-billing/set-up-zuora-billing/build-product-and-prices/charge-models---configure-any-pricing/discount-pricing/discount-charge-models/specify-the-discount-scope) describes three levels: | Scope | Applies to | |---|---| | Rate plan | Charges in the same rate plan only | | Subscription | All charges in the subscription, for a set period | | Account | Regular charges across all the account's subscriptions (must be enabled in settings; not supported in Orders) | For retention offers, a subscription-level discount with a fixed duration is usually the right fit: "30% off for the next 3 months". Set up a dedicated retention discount product in your catalog, so the offer is easy to report on and does not get mixed up with sales discounts. Zuora notes that a fixed-amount discount cannot be changed in place: to correct one, you remove it and add a new one. Percentage discounts can be updated with an amendment ([change a discount charge](https://docs.zuora.com/en/zuora-billing/set-up-zuora-billing/build-product-and-prices/charge-models---configure-any-pricing/discount-pricing/manage-discount-charges/change-a-discount-charge)). ## The plan change offer A downgrade or plan switch is an order that removes one rate plan and adds another. Use the same Orders API as for discounts. Preview the order first, so the cancel flow can show the customer the new price before they accept. ## Knowing when a cancellation happened Your app and your analytics need to know when a subscription is cancelled, whether through your flow, by support in the Zuora UI, or by an integration. Zuora provides a **Cancel Subscription** event among its [custom events for Orders](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/zuora-custom-events/zuora-custom-events-for-orders), related to Order Action Processed. Suspend and Resume have equivalent events. Zuora's docs say that enabling the Orders feature and these events goes through a request to Zuora Global Support. Attach a notification with **callout** delivery to the event so Zuora calls your endpoint. Use it to revoke access on the cancellation date and to log cancellations that did not pass through your flow. ## Building the flow, step by step 1. **Put your own cancel page in front of Zuora.** The button in your app opens the flow, never a direct API call. 2. **Ask the reason.** Five to seven options, plus "Other". Store the answer in your system against the Zuora subscription number. For reason ideas, see [cancellation reason surveys](/blog/cancellation-reasons-survey/). 3. **Map reasons to one offer each:** | Reason | Offer | Zuora operation | |---|---|---| | Too expensive | Time-limited discount | Add a subscription-level discount charge | | Not using it right now | Pause for 1 to 3 months | Suspend with a resume date | | Missing a feature, or need less | Plan change | Order removing and adding rate plans | | Switching to a competitor, closing business | No offer | Cancel | 4. **Keep "Cancel now" on every screen,** with the same weight as the offer. 5. **On accept,** run the Zuora operation, confirm by email, and record that an offer was accepted. 6. **On cancel,** run the cancel with your chosen policy (usually end of last invoice period), show the date service ends, and send a confirmation. 7. **Listen to Zuora's cancel event** for cancellations made elsewhere. 8. **Review monthly:** reasons, offer acceptance, and how many accepted offers are still subscribed three months later. ## Doing this with NoChurn Zuora keeps the subscription, invoicing and the cancellation itself; NoChurn provides the flow in front of it. NoChurn's cancel flow asks for the reason, shows an offer (a discount, a plan change or a cancellation on the Zuora subscription) and keeps a one-click cancel visible at every step. It can be hosted or built headless through the API, and every answer is stored for win-back emails at day 30, 60 and 90 and for the churn score from 0 to 100. See [NoChurn + Zuora](/integrations/zuora/). --- # How to measure churn in Zuora Source: https://www.nochurn.sh/blog/zuora-churn-metrics/ Zuora has several places that report churn, and they do not all measure the same thing. One counts accounts, another counts subscriptions, a third counts MRR, and some depend on features your tenant may or may not have. If two dashboards disagree, it is usually because they use different definitions, not because one is wrong. This guide maps the churn metrics Zuora provides, explains what each one counts, and shows how to build a churn view you can trust. It sticks to Zuora's own documentation: the [Analytics metric glossary](https://docs.zuora.com/en/zuora-platform/data/analytics-quick-reference/analytics-metric-glossary), [Standard booking reports](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/reporting-quick-reference/standard-reports/standard-booking-reports), the [Reporting overview](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/reporting-quick-reference/reporting-overview), the [Order Mrr data source](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/data-sources-and-exports/data-source-reference/order-mrr-data-source), the [MRR Trend export](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/data-sources-and-exports/data-exports/mrr-trend-export) and [Order Delta Mrr](https://knowledgecenter.zuora.com/Zuora_Billing/Manage_subscription_transactions/Orders/Order_Delta_Metrics_and_Order_Metrics/Order_Delta_Mrr) (all accessed November 2026). Definitions can differ between tenant versions, so confirm them in your own Zuora before reporting numbers to anyone. ## The churn metrics Zuora defines ### In Zuora Analytics The [metric glossary](https://docs.zuora.com/en/zuora-platform/data/analytics-quick-reference/analytics-metric-glossary) defines: | Metric | What it counts | |---|---| | Subscriber churn rate | Accounts that had an effective rate plan charge last month but none this month, divided by accounts active at the end of last month. Accounts created in the current month are excluded. | | Churned subscriber count | Accounts with charges in the previous period and none at the end of the current one. An account that starts and churns within the same period is not counted. | | Net MRR changes | MRR movement split into expansion, contraction, churn and no change. Churn is an account going from more than 0 Net MRR to 0 Net MRR on a given day. | | Annual net retention | Ending cohort MRR divided by starting cohort MRR, based on Gross or Net MRR | Two things to notice: - These are **account-level** metrics. A customer who cancels one of two subscriptions is contraction, not churn. - **Gross vs Net MRR** matters. Zuora's Gross MRR excludes discounts and Net MRR includes them. The two can move differently when discounts start or end, so pick one and use it everywhere. ### In Zuora Reporting The [standard booking reports](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/reporting-quick-reference/standard-reports/standard-booking-reports) include: - **Cancelled subscriptions:** the number of subscriptions cancelled each month. This is a **subscription-level** count, so one account with three subscriptions can contribute three. - **Cancelled CMRR:** contracted MRR lost through cancellations. It only includes charges whose end date condition is "Align to Subscription End", so charges with other end-date settings are left out. - **MRR Changes Forecast:** future MRR movements by type, including churn MRR, one year ahead by default. Useful for seeing scheduled cancellations (for example, end-of-term cancellations already booked). - **Total MRR Changes (in last month):** last month's MRR changes, net of discounts, based on the Order Mrr data source. For custom reports, the **MRR Trend export** and the Order MRR data source give you the underlying rows. ### Order Metrics vs Order Delta Metrics If you build reports on order-level MRR, check which metrics your tenant has. According to Zuora's [Order Delta Mrr documentation](https://knowledgecenter.zuora.com/Zuora_Billing/Manage_subscription_transactions/Orders/Order_Delta_Metrics_and_Order_Metrics/Order_Delta_Mrr): - As of Zuora Billing Release 306, the older Order Metrics (Order MRR, TCV, TCB and Quantity) are deprecated; new customers onboarding on Orders do not get them, while existing users keep support. - The successors are **Order Delta Mrr**, **Order Delta Tcv** and **Order Delta Tcb**. Delta MRR stores the gross change in `GrossAmount` and the net-of-discount change in `NetAmount`, and is not generated for one-time or usage charges. - You can read them through Data Query (Order Delta Mrr joined to Order Action) or the preview order API. Moving from Order Metrics to Order Delta Metrics is requested through Zuora Global Support. Reports built on the old Order MRR data source and new reports built on Order Delta Mrr can disagree. Do not mix them in one dashboard. ## Four numbers worth tracking Zuora's metrics give you the raw material. These are the four numbers most subscription teams end up reporting, with how to get each from Zuora. For the general formulas, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). 1. **Customer (logo) churn rate.** Use Zuora Analytics' subscriber churn rate as is, or recompute it from your own export with the same definition. State that it is account-level. 2. **Gross MRR churn rate.** Churned MRR plus contraction MRR in the month, divided by MRR at the start of the month. Take churn and contraction from Net MRR changes (or Gross, consistently). 3. **Net MRR retention.** Starting MRR minus churn and contraction plus expansion, divided by starting MRR. Zuora's annual net retention gives the yearly cohort view. 4. **Involuntary share of churn.** The part of churn caused by failed payments rather than a customer decision. Zuora does not split this for you; see below. ## Splitting voluntary from involuntary churn This split decides what you work on. Voluntary churn is a product, pricing or onboarding problem; involuntary churn is a payments problem, and usually the faster one to fix. Background in [what involuntary churn is](/blog/involuntary-churn/). Zuora records that a subscription was cancelled, not why. To split the two: 1. **Tag cancellations at the source.** Cancellations triggered by the end of your failed-payment process should carry a marker your reports can read, for example a custom field on the subscription or a distinct reason in your own system. Customer-initiated cancellations get the reason from your cancel flow. 2. **Join with payment data.** For untagged history, look at whether the account had failed payments in the period before cancellation. Zuora's payment retry setup (see [recovering failed payments in Zuora](/blog/zuora-payment-retries/)) and the Payment Declined events tell you which invoices were in retry. 3. **Report both rates separately,** with the same denominator, so they add up to total churn. ## Checks before you trust the numbers - **Same level everywhere.** Account-level churn and subscription-level cancellations answer different questions. Label every chart. - **Gross or Net MRR, not both.** Discounts make the two diverge. - **End-date settings.** If some charges are not aligned to subscription end, Cancelled CMRR undercounts. - **Scheduled vs effective cancellations.** A cancellation booked today with an end-of-term date reduces MRR at the term end, not today. The MRR Changes Forecast shows what is coming. - **Order Metrics vs Order Delta Metrics.** Know which your reports are built on. - **Test accounts.** Exclude internal and test accounts from every churn report. ## Turning measurement into action A churn number on its own does not change anything. Pair each metric with an owner and a lever: | Metric moves | Look at | Lever | |---|---|---| | Involuntary churn up | Decline reasons, expiring cards, retry settings | Retries, card updater, recovery emails | | Voluntary churn up in one plan | Cancel reasons for that plan | Pricing, plan design, cancel flow offers | | Contraction up | Which charges were removed | Packaging, usage alerts | | Net retention down while churn is flat | Expansion | Upsell paths | ## Doing this with NoChurn Zuora stays your system of record for subscriptions, invoices and MRR reporting. NoChurn reads accounts, subscriptions, invoices and payment failures from Zuora, records the reason behind each voluntary cancellation through its cancel flow, and gives each customer a churn score from 0 to 100. You can also send your own customer attributes by API and see them on the same customer record. See [NoChurn + Zuora](/integrations/zuora/). --- # How to handle expiring cards in Zuora Source: https://www.nochurn.sh/blog/zuora-expiring-cards/ Expired cards are the most predictable failed payments there are. You know the expiry date months in advance, yet many renewals still fail on cards that ran out last month. Zuora gives you two complementary tools against this: an automatic updater that fetches new card details from the card networks, and expiration events that let you ask the customer before anything fails. This guide explains both, then gives you a setup you can apply. It sticks to Zuora's own documentation: [Payment Method Updater](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-method-updater), the [Payment Method Updater overview](https://knowledgecenter.zuora.com/Zuora_Payments/Configure_payment_orchestration/Payment_Method_Updater/A_Overview_of_Payment_Method_Updater), [Set up Chase Payment Method Updater](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-method-updater/set-up-payment-method-updater/configure-chase-payment-method-updater/set-up-chase-payment-method-updater), [Support for Real Time Account Updater (Adyen)](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/set-up-payment-gateway-integrations/adyen-payment-gateway/overview-of-adyen-integration-v2.0/support-for-real-time-account-updater), [Standard events for Zuora Payments](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/standard-events/standard-events-for-zuora-payments) and [How do I allow customers to modify their stored payment methods?](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/define-and-set-up-payment-methods/how-do-i-allow-customers-to-modify-their-stored-payment-methods) (all accessed November 2026). For the general background on updaters and network tokens, see [network tokens and card account updaters](/blog/network-tokens-card-account-updater/). ## Why expired cards still fail Banks replace cards for many reasons: expiry, loss, fraud, a new card design. The customer gets a new card and updates the places they remember; subscriptions they set up long ago are not on the list. When the renewal runs on the old card, it declines. If nobody intervenes, a customer who never meant to leave churns. There are two ways to fix this: 1. **Get the new details from the network,** without involving the customer. This is what account updater services do. 2. **Ask the customer** to update their card, ideally before the old one expires. You want both, because updaters only cover participating issuers and some card types. ## Payment Method Updater (batch) Zuora's **Payment Method Updater** (PMU) sends card details in batches to the card networks' updater services and writes the results back to Zuora. According to the [PMU documentation](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-method-updater) and its [overview](https://knowledgecenter.zuora.com/Zuora_Payments/Configure_payment_orchestration/Payment_Method_Updater/A_Overview_of_Payment_Method_Updater): - It covers **Visa, Mastercard and American Express**, through the Visa Account Updater, Mastercard Automatic Billing Updater and American Express Card Refresher services. - It runs **before each bill cycle day**, so updated details are in place when the payment run charges the card. - Results can include a **new card number** (Zuora saves it as a new default payment method), a **new expiration date**, or a **closed account** flag. Cards marked closed are no longer used to process payments. - The service typically takes **2 to 5 days**, because each network's updater runs on its own schedule. ### Gateway support PMU is configured per gateway type. Zuora's docs list PMU support for gateways including Adyen, BlueSnap, Chase, Checkout.com, CyberSource, First Data, Merchant e-Solutions, Vantiv and Worldpay, and list Global Payments as not supported. Some updaters (CyberSource, and Zuora's American Express updater) work without a separate payment-processing contract with that gateway; the others require that you also process payments through it. One updater covers all payment methods of a gateway type; updating specific gateway instances is not supported. ### Timing the batch You configure how many days before the bill cycle day the service starts. The right lead time depends on the gateway: for Chase, Zuora recommends **10 days**, under Settings, Payments, Set Up Payment Method Updater ([Chase setup](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-method-updater/set-up-payment-method-updater/configure-chase-payment-method-updater/set-up-chase-payment-method-updater)). Starting too late means the update arrives after the payment run has already declined. ### When cards cannot be submitted Zuora's [troubleshooting guide](https://knowledgecenter.zuora.com/Zuora_Billing/Billing_and_Payments/L_Payment_Methods/D_Payment_Method_Updater/1_Troubleshooting_the_Payment_Method_Updater) notes that invalid card data shows with a Warning status and a NotApprovedForSubmitted update type, which you can export from Reporting, Data Sources. Those cards will never be updated automatically, so they go straight to customer outreach. ## Real-time updaters Some gateways update card details at the moment of payment instead of in a batch. Zuora documents real-time account updater support for **Adyen** ([Adyen RTAU](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/set-up-payment-gateway-integrations/adyen-payment-gateway/overview-of-adyen-integration-v2.0/support-for-real-time-account-updater)), limited to Visa and Mastercard cards issued in the US and Canada, and a separate page for a [Stripe real-time account updater](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/set-up-payment-gateway-integrations/stripe-payment-gateway/stripe-realtime-account-updater). Check the conditions on those pages for your account before relying on them. ## Expiration events: ask before it fails Zuora's [standard events for payments](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/standard-events/standard-events-for-zuora-payments) include two expiration warnings tied to the Payment Method Expiration event: | Event | When it fires | |---|---| | 30 Day Warning | The account's default payment method expires within 30 days | | 15 Day Warning | The account's default payment method expires within 15 days | Details from Zuora's docs: - A card's expiration date is the **last day of its expiry month**. - A scheduled job evaluates these events daily (at 5:15 am UTC for EU and US Cloud Data Center 1 tenants, 5:15 am Los Angeles time for US Cloud Data Center 2). - The warnings still go out for a **closed** payment method; Zuora advises not leaving a closed method as the account default. - They only concern the **default** payment method. Each warning can be delivered by email or as a callout to your system. Because PMU may refresh the card in the meantime, have your email or callout handler re-check the expiry on the account before sending anything to the customer. ## Giving the customer a way to update When the updater cannot help, the customer has to enter a new card. Zuora's [guide on modifying stored payment methods](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/define-and-set-up-payment-methods/how-do-i-allow-customers-to-modify-their-stored-payment-methods) describes the options: - The **hosted payment page** (Payment Pages 2.0), loaded with the existing payment method ID (`pmId`) so the customer can update card information. This keeps card data off your servers. - The **Update a payment method** API, which Zuora recommends against for card data in favour of Payment Pages 2.0. - The Zuora UI, for support agents. Link your expiration emails straight to a page that loads the hosted payment form for that account. After the new card is saved as the default, the next payment run uses it. ## A setup plan 1. **Enable PMU** for each gateway type you use, with a lead time that fits the gateway (10 days for Chase, per Zuora). 2. **Check real-time updater options** if you process through Adyen or Stripe. 3. **Turn on the 30 and 15 day warnings** with a callout to your system. 4. **Re-check before sending.** If PMU already updated the card, skip the email. 5. **Send the 30-day email** with a link to the hosted payment page. Keep it short: which card, when it expires, one button. 6. **Send the 15-day reminder** only if the card is still unchanged. 7. **Export NotApprovedForSubmitted cards** monthly and contact those customers directly. 8. **Keep a failed-payment fallback.** Some cards will still fail; see [how to recover failed payments in Zuora](/blog/zuora-payment-retries/). ## Doing this with NoChurn Zuora's Payment Method Updater, expiration events and payment runs stay in Zuora. NoChurn reads the payment method type and expiry from Zuora and adds AI-written emails that you review before they go out, with a link for the customer to update the payment method, plus recovery emails when a renewal still fails. Each customer also gets a churn score from 0 to 100. See [NoChurn + Zuora](/integrations/zuora/). --- # How to recover failed payments in Zuora Source: https://www.nochurn.sh/blog/zuora-payment-retries/ Zuora gives you a lot of control over payment collection, which also means a lot of settings to get right. Failed payments in Zuora touch at least four areas: payment runs, retry rules, notifications, and the way customers update their payment method. This guide walks through each one and ends with a practical setup plan. It sticks to Zuora's own documentation: [Payment runs](https://docs.zuora.com/en/zuora-payments/process-payments/process-payments/process-payments-with-payment-runs/payment-runs), [Configure payment retry rules](https://docs.zuora.com/en/zuora-payments/process-payments/payments-settings-overview/configure-payment-retry-rules), [Payment Retry](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-retry), [Configurable Payment Retry](https://docs.zuora.com/zuora-payments/payment-orchestration/payment-retry/configurable-payment-retry), [Payment attempts and retry rules](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-retry/configurable-payment-retry/configure-configurable-payment-retry/edit-retry-rules-for-a-customer-group/edit-existing-retry-rules/payment-attempts-and-retry-rules), [Standard events for Zuora Payments](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/standard-events/standard-events-for-zuora-payments) and [How do I allow customers to modify their stored payment methods?](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/define-and-set-up-payment-methods/how-do-i-allow-customers-to-modify-their-stored-payment-methods) (all accessed November 2026). Field names can vary with your tenant's version, so check them in your own settings. ## Step 1: understand payment runs In Zuora, automatic collection happens through **payment runs**. A payment run collects open invoices using electronic payment methods such as cards or ACH. According to the [payment runs documentation](https://docs.zuora.com/en/zuora-payments/process-payments/process-payments/process-payments-with-payment-runs/payment-runs): - A run can process up to 200,000 invoices. - There are **ad hoc** runs, which you start by hand, and **recurring** runs, which execute on a daily, weekly or monthly schedule. - Runs only collect from accounts with **auto-pay** enabled. Auto-pay is set on each customer account, so an account without it will never be charged by a run, and its invoices will simply sit open. - When an invoice is being processed by a payment, it is locked, and any other payment against it fails. Zuora recommends deciding which invoices are collected by which method (payment run, payment page, API) so they do not collide. The first thing to check when "Zuora is not retrying" is often not retries at all: it is whether the account has auto-pay on and a default electronic payment method. ## Step 2: choose your retry mechanism Zuora has two ways to retry a failed electronic payment. Zuora advises against running both at the same time. ### Tenant-level payment retry rules The built-in rules, described in [Configure payment retry rules](https://docs.zuora.com/en/zuora-payments/process-payments/payments-settings-overview/configure-payment-retry-rules), apply to failed payment processing by default when payment retry is enabled in your tenant. You set: - the maximum number of consecutive times a failed payment method is retried; - a minimum interval since the last failed attempt (for example, with 8 hours, no automated retry happens if the last failure was less than 8 hours ago); - a time period during which payments are not retried. You can override these per payment method. These rules are simple and predictable, but the same rules apply to every decline, whatever its reason. ### Configurable Payment Retry (CPR) [Configurable Payment Retry](https://docs.zuora.com/zuora-payments/payment-orchestration/payment-retry/configurable-payment-retry) is Zuora's more flexible option. It lets you set retry logic per **customer group** and per **gateway response code**, mapping codes to categories such as hard, medium and soft declines. Key points from the docs: | Setting or behaviour | What Zuora documents | |---|---| | Retry window | Days from entering retry until the last attempt, maximum 90 days | | Number of attempts | Maximum 20; the payment run makes the first attempt, CPR makes the rest | | Smart Retry | An optional machine learning model that picks retry times from subscriber and transaction characteristics | | Hard declines | A Stop Retry On Hard Declines option ends the cycle on a hard decline | | Timing | Attempts run in batches on the hour, so retries cannot be more frequent than hourly | | Payment methods | Card payments only, not direct debit such as ACH or SEPA | | Rule changes | Apply to future attempts only; concluded cycles are not restarted | Two behaviours from the CPR [best practices](https://docs.zuora.com/zuora-payments/payment-orchestration/payment-retry/configurable-payment-retry/configurable-payment-retry-best-practices/best-practices-for-implementing-cpr) are easy to miss: - CPR turns auto-pay off while a retry cycle runs, so the regular payment run does not charge the invoice again. According to the [auto-pay settings page](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-retry/configurable-payment-retry/use-configurable-payment-retry/auto-pay-settings), what changes depends on the retry level: at invoice level only the invoice's auto-pay flag is turned off; at account level the account's auto-pay is turned off and turned back on only once payment is collected. Zuora recommends invoice-level retry, which keeps the account eligible for future payment runs. An older best-practices page describes both flags being set to false, so check which level your tenant uses. - To stop retries immediately (for example, the customer paid by bank transfer), you end the retry cycle manually, which you can do through the CPR APIs. If you are unsure how to classify a response code, Zuora suggests mapping it as a soft decline and monitoring the results. Zuora also documents [a way to test Smart Retry against your existing logic](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-retry/configurable-payment-retry/configure-configurable-payment-retry/set-up-a-test-to-compare-smart-retry-and-your-existing-retry-logic) before switching everything over. ## Step 3: tell the customer, with notifications and callouts Retries recover temporary declines. Expired, replaced or blocked cards need the customer. Zuora's [standard events for payments](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/standard-events/standard-events-for-zuora-payments) give you the hooks: - **Payment Declined:** fires when the gateway declines an electronic payment. A "Sequence of failed attempt" setting controls on which consecutive failure the notification fires; it is compared with the payment method's `NumConsecutiveFailures` and defaults to 1. External payments do not trigger these notifications. - **Card expiration warnings:** events 15 and 30 days before the default card expires (the expiration date is the last day of the expiry month). These let you ask for a new card before anything fails. - **Payment Method Updated:** fires when the default payment method changes, which is your signal to stop reminders. Each notification can be delivered as an email or as a **callout**, an HTTP request to your endpoint, configured in the notification definition. Use callouts to update your own app (banner, access) and to trigger any messaging you run outside Zuora. Zuora Workflow can also react to these events and send templated emails or call external APIs if you prefer to keep the logic inside Zuora. A simple notification plan: | Trigger | Message | Channel | |---|---|---| | Card expires in 30 days | "Your card expires soon, update it here" | Email | | First declined payment | "Your payment did not go through", with the update link | Email and in-app | | Third consecutive failure | Reminder with the date access is affected | Email | | Payment method updated | Confirmation, no further reminders | Email | ## Step 4: let the customer update their payment method The update link in those emails needs somewhere to land. Zuora documents three ways to change a stored payment method in [its guide on modifying stored payment methods](https://docs.zuora.com/en/zuora-payments/manage-payment-gateway-integrations-and-payment-methods/define-and-set-up-payment-methods/how-do-i-allow-customers-to-modify-their-stored-payment-methods): 1. The **hosted payment method page** for credit cards, passing the existing payment method ID (`pmId`) so the customer can update card information. This is the route that keeps card data off your servers; Zuora recommends Payment Pages 2.0 over handling card details through the API. 2. The **Update a payment method** REST operation. Zuora's [API reference](https://developer.zuora.com/other-api/quickstart-api/operation/updatePaymentMethod/) strongly recommends Payment Pages 2.0 instead of calling it directly, and sending a card number through it puts your own systems in PCI scope. 3. The Zuora UI, in the Electronic Payment Methods section of the customer account, for support agents. After a new default payment method is saved, make sure the open invoice is actually collected, either by the next payment run (check auto-pay, which CPR may have switched off) or by an immediate payment. Remember the invoice lock: do not let a payment page and a payment run charge the same invoice at the same time. ## A recovery checklist for Zuora 1. **Audit auto-pay** on every active subscription account and confirm a default electronic payment method exists. 2. **Pick one retry mechanism:** tenant rules for simplicity, CPR for decline-aware logic and customer groups. Not both. 3. **Map response codes** in CPR and turn on Stop Retry On Hard Declines, so a stolen card is not retried for weeks. 4. **Keep the retry window shorter than the billing period** for monthly plans. 5. **Turn on card expiration warnings** at 30 and 15 days, and look at [Payment Method Updater](https://docs.zuora.com/en/zuora-payments/payment-orchestration/payment-method-updater), which asks the Visa, Mastercard and American Express updater services for new card details before the bill cycle day on supported gateways. 6. **Set up the Payment Declined notification** with a link to a hosted payment page, plus a callout to your app. 7. **Collect after an update:** confirm the invoice is charged once a new card is saved. 8. **Review declines monthly** by response code and customer group. ## Doing this with NoChurn Zuora stays in charge of invoicing, payment runs, retries and your gateway. NoChurn connects through a Zuora OAuth client, imports accounts and subscriptions, receives Zuora notifications and adds AI-written recovery emails that you review before they go out, with a link to update the payment method. It also adds cancel flows with reasons, offers (a discount or a plan change on the Zuora subscription) and a one-click cancel that is always visible, win-back emails at day 30, 60 and 90 based on the cancel reason, and a churn score from 0 to 100. Disputes come from the gateway behind Zuora; with Stripe or Braintree, NoChurn gathers the evidence and drafts a reply for you to review. See [NoChurn + Zuora](/integrations/zuora/). --- # How to win back churned customers on Zuora Source: https://www.nochurn.sh/blog/zuora-win-back/ Customers who cancelled are some of the cheapest customers to bring back. They already know the product, they have an account in your billing system, and many left for reasons that change over time: budget, timing, a missing feature you have since shipped. Zuora holds most of what a win-back campaign needs, but it does not send win-back campaigns itself. This guide covers how to find churned customers in Zuora, what Zuora lets you do when they come back, and a campaign structure you can run with any email tool. Zuora details come from its own documentation: [Subscription statuses](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/common-subscription-information/subscriptions-view-through-the-zuora-ui/subscription-information/subscription-statuses), [Subscriptions resumption](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/subscribe-and-amend/amend-subscriptions/subscriptions-resumption), [Customer accounts cancelation and deletion](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-customer-accounts/view-customer-accounts/customer-accounts-cancelation-and-deletion), [Cancel subscriptions (developer tutorial)](https://developer.zuora.com/docs/get-started/tutorials/cancel-subscription), [Zuora custom events for Orders](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/zuora-custom-events/zuora-custom-events-for-orders), [Analytics metric glossary](https://docs.zuora.com/en/zuora-platform/data/analytics-quick-reference/analytics-metric-glossary) and [Standard booking reports](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/reporting-quick-reference/standard-reports/standard-booking-reports) (all accessed November 2026). ## Step 1: know who churned, and when A win-back campaign starts with a reliable list of cancellations and their dates. Zuora gives you three ways to get it. ### Events, as they happen Zuora's **Cancel Subscription** event, one of the [custom events for Orders](https://docs.zuora.com/en/zuora-platform/extensibility/events-and-notifications/zuora-custom-events/zuora-custom-events-for-orders) tied to Order Action Processed, fires when a subscription is cancelled. Zuora's docs say enabling Orders and these events goes through Zuora Global Support. Attach a notification with callout delivery so your system records each cancellation the day it happens. This is the best trigger for a win-back sequence, because the timing of the first email depends on the cancellation date. ### Reports, for the backlog Zuora's [standard booking reports](https://docs.zuora.com/en/zuora-platform/data/zuora-reporting/reporting-quick-reference/standard-reports/standard-booking-reports) include a **Cancelled subscriptions** report (subscriptions cancelled each month) and **Cancelled CMRR** (contracted MRR lost to cancellations). Use them to build your first list of past churners before the event-driven flow is live. Note that Cancelled CMRR only counts charges whose end date is aligned to the subscription end. ### Analytics, for account-level churn The Zuora Analytics [metric glossary](https://docs.zuora.com/en/zuora-platform/data/analytics-quick-reference/analytics-metric-glossary) defines a **churned subscriber** as an account that had an effective rate plan charge in the previous period and has none at the end of the current one. That is a different, account-level view: a customer who cancels one of two subscriptions is not churned by this definition. For win-back, you usually want the account-level view: people with no active subscription at all. ## Step 2: record why they left Win-back emails work far better when they answer the reason the customer gave. Zuora's cancel operation records the dates and policy of a cancellation; the reason is something you need to capture yourself, typically in your cancel flow, and store against the Zuora account and subscription numbers. If cancellations also happen through support or sales, give those teams the same short list of reasons. See [how to add a cancel flow to Zuora](/blog/zuora-cancel-flow/) for the flow itself. Also distinguish voluntary cancellations from subscriptions cancelled after failed payments. Customers who churned because a card failed need a "your card failed, here is how to restart" message, not a "here is what is new" message. ## Step 3: understand what Zuora can reopen This matters for the "come back" button in your emails. - **Resume is for suspended subscriptions.** Zuora's [resumption docs](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-subscription-transactions/subscribe-and-amend/amend-subscriptions/subscriptions-resumption) describe returning a *suspended* subscription to active status. Cancelled is a separate status. - **Cancelled accounts can be reactivated.** Zuora's [account documentation](https://docs.zuora.com/en/zuora-billing/manage-accounts-subscriptions-and-non-subscriptions/manage-customer-accounts/view-customer-accounts/customer-accounts-cancelation-and-deletion) says a customer account that has been cancelled can be reactivated if needed. That is the billing account, not a subscription. - **Cancellation is per subscription,** as the [developer tutorial](https://developer.zuora.com/docs/get-started/tutorials/cancel-subscription) points out; there is no account-level cancellation. The Zuora pages we reviewed do not describe reopening a cancelled subscription. The safe design is to treat a returning customer as a **new subscription on the existing account**, created through an order. That keeps the customer's history, payment methods and account number, and gives you a clean start date for the new term. Confirm with Zuora support if your tenant offers another path. Before creating the subscription, check that the account has a usable default payment method. A card stored months ago may have expired; see [how to handle expiring cards in Zuora](/blog/zuora-expiring-cards/). If it has, send the customer through a hosted payment page to add a new one first. ## Step 4: choose the return offer Zuora's discount charges can back a return offer, added to the new subscription through the order (rate plan or subscription scope; see [discount scope](https://docs.zuora.com/en/zuora-billing/set-up-zuora-billing/build-product-and-prices/charge-models---configure-any-pricing/discount-pricing/discount-charge-models/specify-the-discount-scope)). Keep offers simple and tied to the reason: | Cancel reason | Win-back angle | Offer | |---|---|---| | Too expensive | A cheaper plan or a limited discount | Discount for the first months back, or a smaller plan | | Not using it enough | What changed, how others use it | Usually none; a guided restart | | Missing feature | The feature now exists | None needed if it shipped | | Moved to a competitor | Specific improvements since they left | Optional discount | | Payment failed | Easy restart, same plan | None; fix the payment method | | Business closed or project ended | Nothing | Do not email | Create a dedicated win-back discount in your product catalog, so revenue from returning customers can be reported separately from new sales. ## Step 5: time the sequence Space emails out so they arrive when circumstances may have changed. A simple, reason-based schedule: 1. **Day 30:** a short note tied to the cancel reason. No hard sell. 2. **Day 60:** what is new since they left, especially anything related to their reason. 3. **Day 90:** the offer, if there is one, with a clear end date. Stop the sequence as soon as a new subscription is created on the account, and suppress it entirely for customers who said they closed their business or asked not to be contacted. For copy ideas, see [win-back email examples](/blog/win-back-email-examples/). ## Step 6: measure what came back Track, per cancel reason and per email: - how many churned accounts got a new subscription within 120 days of cancelling; - the MRR of those subscriptions, net of win-back discounts; - how many returning customers are still active three months later. Zuora's [Net MRR changes](https://docs.zuora.com/en/zuora-platform/data/analytics-quick-reference/analytics-metric-glossary) in Analytics separate expansion, contraction and churn; tagging win-back subscriptions with their own rate plan or discount makes them easy to isolate. For a full measurement setup, see [how to measure churn in Zuora](/blog/zuora-churn-metrics/). ## Common mistakes - **Emailing everyone the same day.** A customer who left last week and one who left last year need different messages. - **Sending payment-failure churners a marketing email.** They did not choose to leave. - **A "come back" link that leads to a generic sign-up.** It should land on a page that knows the account and only asks for what is missing. - **Discounts that never end.** Set a duration on every win-back discount. ## Doing this with NoChurn Zuora keeps the account, the new subscription, invoicing and payment runs. NoChurn follows Zuora notifications, records the reason from its cancel flow, and sends win-back emails at day 30, 60 and 90 written from that reason, with a link to come back. Recovery emails for failed payments and a churn score from 0 to 100 sit on the same customer record. See [NoChurn + Zuora](/integrations/zuora/). --- # Annual plan renewals: reminders, notice rules and how to keep customers Source: https://www.nochurn.sh/blog/annual-plan-renewal-reminders/ Annual plans are good for retention on paper: the customer commits for a year, and there is only one renewal to get through instead of twelve. But that single renewal is a large charge, on a card the customer may not have used with you for twelve months, for a product some of them have stopped thinking about. When it goes wrong, it goes wrong in one of three ways: the payment fails, the customer disputes a charge they forgot about, or they ask for a refund and leave. Most of this is avoidable with a reminder sent at the right time, which in several places is also a legal or card network requirement. This guide covers the rules we could verify, Stripe's built-in tools, and a practical renewal sequence. **This is not legal advice.** The rules below are summarized as of November 3, 2026, for the jurisdictions named. Laws differ by state and country and change often; check with a lawyer for your situation. ## Why annual renewals are fragile Compared with a monthly renewal, an annual one has a few specific risks: - **The card is old.** A card saved twelve months ago is more likely to have expired or been replaced. See [expiring cards](/blog/expiring-cards/) and [network tokens and card updater](/blog/network-tokens-card-account-updater/). - **The amount is large.** A charge of ten or twelve months' price is more likely to hit a spending limit or a fraud check, and a soft decline like `insufficient_funds` or `card_velocity_exceeded` is more likely. See [Stripe decline codes explained](/blog/stripe-decline-codes/). - **The customer forgot.** A surprise charge is a refund request or a dispute waiting to happen. - **The person changed.** In B2B, the person who bought the plan may have left, and the card may belong to someone who never heard of you. A reminder before the renewal addresses all four: it prompts a card update, warns about the amount, reminds the customer, and reaches whoever now owns the account. ## The rules we could verify ### California California's Automatic Renewal Law (Cal. Bus. & Prof. Code sections 17600 and following) has specific timing rules. From the text of [section 17602](https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=17602) (accessed November 2026): - For an automatic renewal with an **initial term of one year or longer**, the business must send a notice **at least 15 days and not more than 45 days** before the renewal. - For a **free trial or promotional price** lasting more than 31 days, a notice is due **at least 3 and at most 21 days** before the trial or promotion ends. [AB 2863](https://leginfo.legislature.ca.gov/faces/billTextClient.xhtml?bill_id=202320240AB2863) (Chapter 515, Statutes of 2024) added further requirements, with most changes taking effect July 1, 2025 according to law firm summaries such as [Davis Wright Tremaine's](https://dwt.com/insights/2024/10/ab-2863-updates-california-automatic-renewal-law). They include an **annual reminder** of the subscription terms (what it is, what it costs, how to cancel), and notice **7 to 30 days before a price change** under an existing renewal. The law protects consumers in California. Our [click-to-cancel rules overview](/blog/click-to-cancel-rules/) covers the cancellation side. ### Germany For consumer contracts concluded since March 1, 2022, the German "fair consumer contracts" law changed section 309 no. 9 of the Civil Code (BGB): standard terms can no longer tacitly extend a contract by a fixed year. After the initial term, a tacitly extended contract must be cancellable at any time with at most one month's notice ([IHK Köln summary, in German](https://www.ihk.de/koeln/hauptnavigation/recht-steuern/faire-verbrauchervertraege-5329466)). This does not require a reminder, but it changes what "annual renewal" means for German consumers: after year one, the customer can leave with a month's notice. Germany also requires a cancellation button for consumer contracts concluded online (section 312k BGB, see our [click-to-cancel overview](/blog/click-to-cancel-rules/)). ### United Kingdom The Digital Markets, Competition and Consumers Act 2024 includes a subscription contracts regime with reminder notices before renewals and before the end of free or discounted trials. As of this writing it is not in force; the government announced a start in January 2027, with secondary legislation still pending ([Wiggin tracker](https://www.wiggin.co.uk/insight/digital-markets-competition-and-consumer-act-tracker/)). If you sell to UK consumers, plan for renewal reminders now. ### Other places Many US states have their own automatic renewal laws with different notice windows, and some cover B2B contracts too. We could not verify a current, complete list from primary sources, so we do not reproduce one here. If you sell nationally in the US, a common approach is to design to the strictest rule you are subject to and apply it to everyone. ## Card network rules Card networks have their own requirements, which apply regardless of the customer's location and to B2B as well as B2C. According to Stripe's [guidance on Mastercard recurring billing requirements](https://support.stripe.com/questions/guidance-for-mastercard-recurring-billing-compliance-updates) (accessed November 2026), merchants must send an email or other electronic reminder before charging subscriptions billed **six or more months apart**, such as annual plans. Stripe recommends configuring an upcoming renewal event **between 7 and 30 days** before renewal for billing periods longer than 180 days. The same page covers a written confirmation when a subscription is cancelled. Visa's [trial subscription rules](https://usa.visa.com/dam/VCOM/global/support-legal/documents/visa-new-subscription-rules-flier.pdf) require a reminder with a link to cancel at least seven days before charging at the end of a trial or promotional period. That is about trials, but the same logic applies if your annual plan starts with a discounted first year. ## A timing that satisfies the strictest rules above If you want one schedule for everyone, the overlap of the rules above gives you a window: | Rule | Window before an annual renewal | |---|---| | California, initial term of one year or longer | 15 to 45 days | | Mastercard, via Stripe's guidance | Reminder required; Stripe suggests 7 to 30 days | | Overlap | **15 to 30 days** | A practical sequence: | When | Message | Purpose | |---|---|---| | 30 days before | Renewal reminder: date, amount, plan, how to change or cancel, card on file (brand and last four) | Compliance, and time to update the card | | 7 days before | Short reminder, only if the card expires before the renewal date or was removed | Prevent a failed payment | | Renewal day | Receipt | Reduce "what is this charge?" disputes | | If it fails | Your normal [dunning sequence](/blog/dunning-email-templates/) | Recover the payment | Check the dates against your own markets. If a law you are subject to requires a different window, it wins. ## What the reminder should contain Write it like a useful notice, not a marketing email. - **Subject:** "Your [Product] plan renews on [date]" - **The facts:** plan name, renewal date, exact amount including tax, billing interval. - **The card:** "We'll charge your Visa ending in 4242." If the card expires before the renewal date, say so and link to the update page. - **What they got:** one or two lines on usage over the year, only if you have real numbers for this customer. - **Choices:** a link to switch plans (monthly, a smaller plan) and a link to cancel. Both should work online and quickly. - **Who to contact:** a reply address that reaches a person. Do not hide the cancel link, and do not make it harder to cancel than to renew. Besides the legal risk, a customer who could not find the exit is the one who files a dispute. ### Example > Subject: Your Planwise plan renews on March 14 > > Hi Sam, > > Your Planwise Team plan (annual) renews on March 14, 2027. We'll charge $1,188.00 to your Visa ending in 4242. > > Nothing to do if you'd like to continue. If you'd rather switch to monthly billing, change plans, or cancel, you can do it here: [Manage subscription] > > Questions? Just reply to this email. ## Setting it up in Stripe Stripe has the building blocks: - **Renewal reminder emails.** In the [customer emails settings](https://docs.stripe.com/billing/revenue-recovery/customer-emails), turn on emails about upcoming renewals. Stripe documents that these are not sent for subscriptions with `collection_method` set to `send_invoice`. - **The lead time.** The "upcoming renewal events" setting controls how many days before renewal Stripe sends the `invoice.upcoming` [webhook](https://docs.stripe.com/billing/subscriptions/webhooks) and the reminder. For existing subscriptions, a change takes effect from the next billing period. - **Your own email.** If you want custom content, listen to `invoice.upcoming` and send your own message, and turn Stripe's reminder off to avoid sending two. - **Card checks.** On `invoice.upcoming`, compare the card's expiry with the renewal date, and check that a default payment method still exists. Stripe's reminder setting is account-wide. If monthly plans should not get reminders but annual plans should, filter on the price interval in your own handler. ## Reducing churn at renewal, honestly A reminder will make some customers cancel who would otherwise have renewed without noticing. That is the point of the rules, and those customers were likely to dispute or ask for a refund anyway. You can still keep many of them with a fair offer: - **Offer monthly billing.** Some customers are not leaving the product, they are leaving the commitment. - **Offer a smaller plan.** Seat counts and usage often shrink over a year. - **Offer a pause** if the customer's need is seasonal. See [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). - **Ask why** when they cancel, with a short reasons list. See [cancel flow best practices](/blog/cancel-flow-best-practices/). Measure the renewal rate of annual plans by cohort, and separate failed payments from cancellations. They have different fixes. ## Pre-renewal checklist - [ ] Annual renewals get a reminder 15 to 30 days before (or the window your rules require). - [ ] The reminder shows date, amount, card and how to cancel. - [ ] Customers whose card expires before renewal get a separate card update request. - [ ] Customers without a default payment method are flagged before renewal. - [ ] Price changes trigger a notice in the required window. - [ ] Cancellation works online, in a few clicks. - [ ] A receipt goes out on renewal day. - [ ] Failed annual renewals enter a dunning sequence the same day. - [ ] B2B reminders go to the billing contact, not only the original signup. ## How NoChurn helps NoChurn watches for the problems that make renewals fail. Each customer gets a churn score at signup, partly based on the payment method, and customers who remove their card before renewal are flagged so you can reach them before the payment fails. If a renewal fails anyway, NoChurn retries at better times and sends AI-written recovery emails, reviewed before sending, with a hosted card update page. Customers who cancel go through a cancel flow with one relevant offer and a cancel button that is always visible, and win-back emails follow at 30, 60 and 90 days. It connects to Stripe in one click, and pricing depends only on MRR. See [the churn score](/#score), [cancel flows](/#cancel) and [pricing](/pricing/). --- # Cancel flow best practices: examples without dark patterns Source: https://www.nochurn.sh/blog/cancel-flow-best-practices/ A cancel flow is the short sequence a customer sees between clicking "Cancel subscription" and the subscription actually ending. Done well, it answers one question ("why are you leaving?") and makes one relevant offer. Done badly, it becomes a maze of guilt-trip screens, hidden buttons and phone-only cancellation, which annoys customers and, increasingly, regulators. This guide covers how to build the first kind: what to ask, what to offer, how to write the copy, and how to measure whether it works. ## The principle: one question, one offer, always an exit A good cancel flow has three steps at most: 1. **Reason.** Ask why the customer is leaving, with a short list of options. 2. **Offer.** Show one offer that matches that reason, or none if nothing fits. 3. **Confirm.** Confirm the cancellation and state exactly what happens next (end date, data retention, how to come back). On every step, a "Cancel now" button stays visible and works in one click. The customer should never have to accept or decline an offer to reach the exit. This is not only good manners. California's updated automatic renewal law, in force since July 1, 2025, allows a business to present a save offer to consumers who cancel online only if it also shows a clear, continuously displayed way to cancel ([Davis Wright Tremaine summary of AB 2863](https://dwt.com/insights/2024/10/ab-2863-updates-california-automatic-renewal-law)). The FTC has also named obstructive cancellation as a dark pattern in its 2022 staff report [Bringing Dark Patterns to Light](https://www.ftc.gov/reports/bringing-dark-patterns-light). See our [click-to-cancel rules overview](/blog/click-to-cancel-rules/) for the legal detail. ## Step 1: the reasons list The reasons list does two jobs: it routes the customer to the right offer, and it gives you data. Both get worse when the list is long. ### Keep it to five to seven options Pick reasons you can act on. A typical B2B SaaS list: | Reason (customer-facing) | Internal code | What you can do about it | |---|---|---| | It's too expensive | `price` | Discount, downgrade | | I'm not using it enough | `low_usage` | Pause, onboarding help | | It's missing a feature I need | `missing_feature` | Roadmap info, call | | I switched to another tool | `competitor` | Ask which one, call | | It was too hard to set up or use | `too_complex` | Setup call | | My project or company ended | `no_need` | Pause, or no offer | | Something else | `other` | Free text, no offer | ### Rules for the list - **Use the customer's words, not yours.** "I'm not using it enough" beats "Low engagement." - **One choice, not checkboxes.** You need one primary reason to pick one offer. Add an optional free-text field for detail. - **Make the question skippable.** If the customer wants out, "Skip and cancel" should work. - **Shuffle the order (except "Other")** if you want cleaner data; the first option gets picked more often by people in a hurry. - **Keep internal codes stable.** If you rename a reason later, keep the code so your historical data stays comparable. ## Step 2: one offer per reason The worst cancel flows show every offer to everyone: a discount, then a pause, then a downgrade, then a "talk to us" screen. The customer has to decline four times. Instead, map each reason to at most one offer. | Reason | Offer that fits | Why | |---|---|---| | Too expensive | Downgrade to a cheaper plan, or a time-limited discount | Addresses cost directly | | Not using it enough | Pause for one to three months | The need may come back; a discount on something unused does not help | | Missing a feature | A short call, or a link to the roadmap item | You might solve it, or at least learn | | Switched to a competitor | A call, or no offer | Discounts rarely win back someone who has already migrated | | Too hard to use | A setup call | The problem is effort, not price | | No longer needed | No offer | Respect it; make coming back easy | Two things are worth noticing. First, "no offer" is a valid answer: pushing a discount on someone whose company shut down wastes their time and your margin. Second, a discount is the right answer less often than people assume. Our guide to [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/) goes deeper on when each one fits. ### Offer guardrails - **Limit repeat offers.** A customer who took a discount last quarter should not see the same discount again. Otherwise you train customers to start cancelling to get a lower price. - **Make the terms explicit.** "50% off for your next 3 months, then back to $49/month" is honest. "Special price!" is not. - **Make acceptance instant.** If the customer clicks "Accept," apply the coupon, pause or plan change right away and show confirmation. No "our team will be in touch." ## Step 3: confirmation The confirmation screen is part of the flow, not an afterthought. It should state: - The exact date access ends (often the end of the paid period). - What happens to their data, and for how long it is kept. - That no further charges will be made. - How to restart, in one line. Send the same information by email. A customer who is unsure whether cancellation went through is a customer who files a chargeback. ## Copy examples Good cancel copy is short, specific and neutral. Here are original examples for each screen. ### Reason screen > **Before you go, what's the main reason?** > Your answer helps us improve. You can skip this and cancel right away. > > [Cancel now] ### Offer screen (reason: too expensive) > **Would a smaller plan work?** > The Basic plan is $19/month and keeps your projects and history. You'd lose team seats beyond 3. > > [Switch to Basic] [No thanks, cancel now] ### Offer screen (reason: not using it enough) > **Want to pause instead?** > We'll stop billing for up to 3 months and keep everything as it is. You can resume any time, and we'll remind you a week before billing restarts. > > [Pause for 1 month] [Pause for 3 months] [Cancel now] ### Offer screen (reason: missing a feature) > **Which feature were you missing?** > If it's on our roadmap, we'll tell you where it stands. If you'd rather talk it through, book 15 minutes with the product team. > > [Book a call] [Cancel now] ### Confirmation screen > **Your subscription is cancelled.** > You have access until December 14, 2026. You won't be charged again. We keep your data for 90 days, then delete it. To restart, sign in and choose a plan. ### Copy to avoid | Pattern | Example | Why it's a problem | |---|---|---| | Confirmshaming | "No thanks, I don't care about growing my business" | Guilt instead of information | | Hidden exit | A grey "cancel" link below the fold | Obstruction; risky under state law | | Fake urgency | "This offer expires in 2:00 minutes" | Manipulative, usually untrue | | Forced contact | "Call us to cancel" when signup was online | Restricted by California for online signups | | Endless loop | Offer after offer after offer | Wears people down instead of helping | | Ambiguous buttons | "Continue" (to what?) | Customer can't tell which button cancels | ## Design checklist Use this before shipping a cancel flow: - [ ] "Cancel now" is visible and works in one click on every screen. - [ ] Three screens or fewer from "Cancel" to confirmation. - [ ] Reason question is optional. - [ ] At most one offer, and it matches the reason. - [ ] Offer terms (amount, duration, what happens after) are stated in full. - [ ] Accepting the offer applies it immediately. - [ ] Customers who already used an offer recently don't see it again. - [ ] Confirmation shows end date, data retention and no further charges. - [ ] Confirmation email is sent. - [ ] Flow works with keyboard only and with a screen reader. - [ ] Flow is available wherever signup was (web, iOS, Android, desktop). - [ ] Legal review done for your markets (US states, EU, UK). ## Measuring a cancel flow A cancel flow is only worth keeping if it changes outcomes without creating new problems. Track these per reason, not just overall. | Metric | Definition | What to watch for | |---|---|---| | Flow starts | Customers who clicked "Cancel" | Baseline volume | | Offer acceptance rate | Accepted offers / flows that showed an offer | Low rate means the offer doesn't fit the reason | | Save rate | Customers still subscribed N days after accepting / flow starts | Use 30, 60 and 90 days, not just "accepted" | | Saved revenue | MRR still active N days after a save | Subtract the discount cost | | Re-cancel rate | Saved customers who cancel later | High rate means you're delaying churn, not preventing it | | Complaints and chargebacks | Support tickets and disputes about cancellation | Should not go up | A few measurement rules: - **Count a save only if it lasts.** A customer who accepts a discount and cancels a month later was not saved. Stripe's own retention reporting, for example, counts a save only if the customer stays subscribed for at least 7 days after accepting an offer ([Stripe docs](https://docs.stripe.com/billing/retention/performance)); for SaaS, a longer window is more telling. - **Price in the offer.** A 50% discount for three months on a $100/month plan costs $150. If the customer stays for only four months, the save was worth $250 in revenue, not $400. - **Keep a holdout.** Show a small random group the flow without the offer (reason question and confirmation only). Comparing the two groups is the only way to know how many saves the offer actually caused, since some of those customers would have stayed anyway. - **Read the free text.** The "Other" answers are where you find reasons you didn't list. ## Where to build it You have three options. Stripe's customer portal includes a basic cancellation page with a fixed reasons list and a retention coupon, and it is enough for many early-stage products ([our comparison](/blog/stripe-customer-portal-cancellation/)). You can build the flow yourself, which gives full control but means maintaining offers, eligibility rules and analytics. Or you can use a dedicated tool. ## How NoChurn helps NoChurn's [cancel flows](/#cancel) follow the structure in this guide: reason, then one matching offer (a discount through a Stripe coupon, a pause, a downgrade or a call), then confirmation. A one-click "Cancel now" button is visible on every step. You can use the hosted modal (themes, colors, fonts, borders, logo, custom CSS and a visual editor) or the headless API to build the flow in your own design on web, desktop, iOS and Android. Cancel reasons feed the [win-back emails](/#winback) sent at 30, 60 and 90 days. Every feature is on every plan, and the price depends only on your MRR ([pricing](/pricing/)). --- # Churn survey questions: a cancellation reasons list you can act on Source: https://www.nochurn.sh/blog/cancellation-reasons-survey/ Every cancel flow asks some version of "why are you leaving?". Most teams then do very little with the answers. The list was written in a hurry, half the responses are "Other", the categories overlap, and when someone finally opens the spreadsheet a year later, the options have changed twice and nothing is comparable. A cancellation survey is a small piece of data design. Get the taxonomy right once, and it pays off in routing (which offer to show), in product decisions (what to build or fix), and in analysis (which customers leave for which reasons). This guide covers how to build it. ## What the survey is for A cancellation survey has three jobs, in this order: 1. **Route the customer.** The answer decides which offer, if any, the customer sees next. See [cancel flow best practices](/blog/cancel-flow-best-practices/). 2. **Record a reason you can count.** One primary reason per cancellation, from a fixed list, stored with a stable code. 3. **Collect detail for later.** An optional free-text field for the customer's own words. It is not a research interview. The customer is leaving. Ask one question, maybe one follow-up, and let them go. The cancel button stays visible throughout, as the [click-to-cancel rules](/blog/click-to-cancel-rules/) increasingly require. ## A reasons taxonomy Good reason lists are short, mutually exclusive, written in the customer's words, and mapped to something you can do. Here is a starting taxonomy for a SaaS product, with two levels: a **category** for reporting, and the **reason** the customer sees. | Category | Customer-facing reason | Code | What you can do | |---|---|---|---| | Price | It's too expensive | `price` | Downgrade, discount, monthly billing | | Value | I'm not using it enough | `low_usage` | Pause, onboarding help | | Product | It's missing a feature I need | `missing_feature` | Roadmap info, call | | Product | It's too hard to set up or use | `too_complex` | Setup call, guides | | Product | It's not working reliably for me | `quality` | Support contact, bug follow-up | | Competition | I'm switching to another tool | `competitor` | Ask which one; call | | Service | Support didn't meet my expectations | `service` | Escalate to a manager | | Circumstance | My project or company ended | `no_need` | Pause, or no offer | | Circumstance | It was only for a temporary need | `temporary` | Pause | | Other | Something else | `other` | Free text, no offer | That is ten options, which is at the upper limit. For most products, pick the six or seven that actually come up and fold the rest into "Something else". You can add one later if "Other" keeps containing the same answer. ### Rules for the list - **One choice.** Checkboxes give you nicer-looking data and worse decisions: you cannot route on three reasons. Ask for the main one. - **Customer language.** "I'm not using it enough" rather than "Low engagement". "It's too expensive" rather than "Pricing concerns". - **No overlaps.** "Too expensive" and "Not worth the price" are the same answer to a customer and two answers in your data. Pick one. - **Stable codes.** You will reword reasons. Keep the code so history stays comparable. - **Randomize the order, except "Something else" at the end**, if you care about clean data. People in a hurry pick the first option more often. - **Make it skippable.** "Skip and cancel" must work. A skipped answer is data too. ## Matching Stripe's feedback codes If you use Stripe, its subscriptions already have a place for this. The subscription's `cancellation_details` has a `feedback` field and a free-text `comment`, documented in the [cancel subscription API reference](https://docs.stripe.com/api/subscriptions/cancel) (accessed November 2026). The `feedback` values are: | Stripe `feedback` value | Closest reason above | |---|---| | `too_expensive` | `price` | | `unused` | `low_usage`, `no_need`, `temporary` | | `missing_features` | `missing_feature` | | `too_complex` | `too_complex` | | `low_quality` | `quality` | | `switched_service` | `competitor` | | `customer_service` | `service` | | `other` | `other` | Stripe's [customer portal cancellation page](https://docs.stripe.com/customer-management/cancellation-page) uses the same set of reasons. Stripe documents that `cancellation_details` can still be updated after a subscription is cancelled, so you can write the reason there from your own flow. Our suggestion: keep your own, more specific codes as the primary record (Stripe's `unused` merges "I don't use it" with "I don't need it anymore", which call for different actions), and also write the closest Stripe value to `cancellation_details.feedback`. That keeps Stripe's own reporting and any tool reading from Stripe consistent. ## Follow-up questions One follow-up, shown only for some reasons, can add a lot. Keep it optional. | Reason | Follow-up question | Format | |---|---|---| | Too expensive | "What would feel like a fair price for you?" | Short text or a few ranges | | Missing a feature | "Which feature do you need?" | Short text | | Switching tools | "Which tool are you moving to?" | Short text or list | | Too hard to use | "Where did you get stuck?" | Short text | | Not working reliably | "What went wrong?" | Short text | | Something else | "Tell us more, if you'd like" | Short text | Do not ask for a follow-up when the reason is "My company closed". There is nothing to learn that justifies the extra step. ### Questions to avoid - **"How likely are you to recommend us?"** at cancellation. The answer is predictable and the moment is wrong. - **Leading questions.** "Did you know we have a cheaper plan?" is an offer dressed as a question. Show the offer as an offer. - **Multiple pages of questions.** Every extra screen is friction between the customer and the exit. - **Mandatory free text.** People type "x" to get through, and you learn nothing. ## Handling free text The free-text answers are the most useful part of the survey and the hardest to use. A few practices: - **Read them.** Every week, someone should read every comment. It takes minutes at most stages. - **Tag them.** When a comment says more than the reason chosen, add a secondary tag (a feature name, a competitor, a bug). - **Treat them as customer data.** Comments can contain names, emails and other personal details. Store them with the same care as the rest of your customer data, and do not paste them into logs. - **Re-classify "Other" monthly.** If several "Other" comments say the same thing, that is a missing reason. AI can help summarise and tag comments at volume, as long as you check a sample by hand and treat the comment text as data, not instructions. ## Analysing the answers Reasons are only useful when you can compare them across segments and over time. ### The basic report Each month, count cancellations by category and reason, and compute each as a share of cancellations that answered. Report the skip rate separately. | Reason | Cancellations | Share of answers | |---|---|---| | Too expensive | n | n / answered | | Not using it enough | n | n / answered | | ... | | | | Skipped | n | (shown separately) | ### Cut it by segment The same reason means different things in different segments. Useful cuts: - **Plan and price point.** "Too expensive" on your cheapest plan is a different problem from "too expensive" on the top plan. - **Tenure.** Reasons in the first 60 days usually point to onboarding and expectations; reasons after a year point to value and competition. - **Acquisition source.** If customers from one channel leave for "not what I expected", the channel is setting the wrong expectations. - **Activation.** Customers who never activated and say "too expensive" are often telling you they never saw the value. Our guide to [finding what predicts churn with your own data](/blog/predict-churn-with-customer-data/) covers how to compare segments properly, including sample sizes. ### Connect reasons to outcomes The reason is also the input to your offers and win-back emails: - **Offer acceptance by reason**: which offer works for which reason, measured against a holdout. See [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). - **Saved customers still active at 30, 60 and 90 days**, by reason. - **Win-back rate by reason**: customers who left for "missing feature" are the ones to email when you ship it. See [win-back email examples](/blog/win-back-email-examples/). ### Caveats Stated reasons are what customers chose to tell you in a hurry. "Too expensive" is sometimes the polite version of "not worth it to me". Use reasons alongside behaviour (usage, support tickets, payment history), not instead of it, and expect some noise. ## Changing the list without breaking history You will want to change the list. Do it carefully: 1. **Never reuse a code** for a different meaning. 2. **Retire codes** rather than deleting them; keep them in your data dictionary. 3. **Log the list version** with each answer, so you know what options the customer saw. 4. **Map old codes to new categories** in your reporting, so year-over-year charts still work. 5. **Change one thing at a time** and note the date, so a jump in a reason's share is not mistaken for a real trend. ## Checklist - [ ] Six to eight reasons, in customer language, mutually exclusive. - [ ] One primary reason, single choice, skippable. - [ ] Stable internal codes, mapped to Stripe's `feedback` values. - [ ] At most one optional follow-up, only where it helps. - [ ] Each reason mapped to one offer, or none. - [ ] Free text read weekly and treated as customer data. - [ ] Monthly report by reason, with the skip rate. - [ ] Reasons cut by plan, tenure, source and activation. - [ ] List version logged with each answer. ## How NoChurn helps NoChurn's cancel flows ask for a reason, show one matching offer, and keep a one-click cancel button visible at every step. The reasons, offers and texts are yours to edit, per language, or you can run the flow headless through the API in your own UI. Each answer is stored with the customer, used to choose the right win-back email at 30, 60 and 90 days, and available for analysis alongside the custom attributes you send, so you can see which customer attributes correlate with churn. It connects to Stripe in one click, and pricing depends only on MRR. See [cancel flows](/#cancel), [custom data](/#insights) and [pricing](/pricing/). --- # Click-to-cancel rules for SaaS: where things stand in November 2026 Source: https://www.nochurn.sh/blog/click-to-cancel-rules/ "Click to cancel" is shorthand for a simple idea: if a customer can sign up online, they should be able to cancel online, without a phone call or an obstacle course. In the US, the FTC tried to make that a nationwide rule in 2024; a federal court threw the rule out in 2025, and the FTC started over in 2026. Meanwhile, state laws, an older federal statute and European rules already require much of the same thing. This article summarizes the situation as of **November 3, 2026**, with links to the sources we relied on. Laws in this area are moving, so check the dates on everything you read, including this. **This is not legal advice.** It is a starting point for a conversation with a lawyer who knows your markets and your business model. ## Summary table | Jurisdiction | Rule | Status on November 3, 2026 | Applies to | |---|---|---|---| | US (federal) | FTC "Click-to-Cancel" amendments to the Negative Option Rule (2024) | Vacated by the Eighth Circuit, July 8, 2025 | Not in force | | US (federal) | New FTC rulemaking on negative option marketing | Advance notice published March 2026; no proposed rule text found | Not in force | | US (federal) | Restore Online Shoppers' Confidence Act (ROSCA) | In force; actively enforced | Online negative option sales to consumers | | California | Automatic Renewal Law, as amended by AB 2863 | Amendments in force since July 1, 2025 | Consumers in California | | EU | Withdrawal function (Directive 2023/2673) | Applies from June 19, 2026, subject to national transposition | Online consumer contracts with a right of withdrawal | | EU | Digital Fairness Act | Proposal expected but not published as of this date | Not in force | | Germany | Cancellation button, BGB section 312k | In force since July 1, 2022 | Consumer contracts for ongoing services concluded online | | UK | DMCC Act 2024, subscription contracts regime | Not yet in force; start announced for January 2027 | Consumer subscriptions | ## United States: the FTC rule that didn't happen ### What the 2024 rule said In October 2024, the FTC finalized amendments to its 1973 Negative Option Rule. Among other things, they required sellers to make cancellation at least as easy as signup, and to offer an online cancellation method when the customer signed up online. Most provisions were due to take effect on July 14, 2025. ### What the court did in July 2025 On July 8, 2025, the US Court of Appeals for the Eighth Circuit vacated the amendments in *Custom Communications, Inc. v. FTC* (No. 24-3137). The court held that the FTC Act required the agency to prepare a preliminary regulatory analysis once the rule's expected economic impact passed $100 million, and that the FTC had skipped that step. The court decided the case on that procedural ground and did not rule on the challengers' other arguments, such as whether the FTC exceeded its authority ([Mayer Brown](https://www.mayerbrown.com/en/insights/publications/2025/07/click-to-cancelled-eighth-circuit-vacates-federal-trade-commissions-revised-negative-option-rule); [Bass, Berry & Sims](https://www.bassberry.com/news/eighth-circuit-vacates-ftcs-click-to-cancel-rule/)). Practical effect: the July 14, 2025 compliance deadline disappeared, and the 2024 amendments are not law. The original 1973 rule, which is narrower, remains. ### The 2026 restart On March 11, 2026, the FTC announced an advance notice of proposed rulemaking (ANPRM) on negative option marketing, published in the Federal Register on March 13, with comments due April 13, 2026 ([FTC press release](https://www.ftc.gov/news-events/news/press-releases/2026/03/ftc-seeks-public-comment-response-advance-notice-proposed-rulemaking-regarding-negative-option); [Covington](https://www.cov.com/en/news-and-insights/insights/2026/03/ftc-launches-new-rulemaking-on-the-negative-option-rule); [Greenberg Traurig](https://www.gtlaw.com/en/insights/2026/3/ftc-seeks-comment-on-potential-updates-to-negative-option-rule)). The notice asks whether to keep the existing rule, adopt provisions similar to the vacated 2024 amendments, write new ones, or rely on alternatives such as education. An ANPRM is an early step. The FTC would still need to publish a proposed rule, take comments, and issue a final rule. As of this writing we found no published proposed rule. Treat any article that says "click-to-cancel is the law nationwide" as out of date, and any article that says "the issue is dead" as equally wrong. ### What still applies federally: ROSCA The [Restore Online Shoppers' Confidence Act](https://www.law.cornell.edu/uscode/text/15/8403) (15 U.S.C. 8403) has applied to online negative option sales since 2010. In short, it requires sellers to: 1. Clearly disclose all material terms before collecting billing information. 2. Get the consumer's express informed consent before charging. 3. Provide "simple mechanisms" for the consumer to stop recurring charges. The third point is the federal hook for easy cancellation, and the FTC uses it. Recent examples: - **Amazon (Prime).** In September 2025, Amazon agreed to pay $2.5 billion ($1 billion civil penalty and up to $1.5 billion in refunds) to settle FTC claims under the FTC Act and ROSCA about Prime enrollment and cancellation; Amazon did not admit wrongdoing ([Goodwin](https://www.goodwinlaw.com/en/insights/blogs/2025/09/ftc-settles-with-amazon-over-enrollment-and-cancellation-processes-for-prime-memberships); [Alston & Bird](https://www.alston.com/en/insights/publications/2025/10/ftc-settlement-prime-subscription-practices)). - **Chegg.** In September 2025, Chegg agreed to pay $7.5 million to settle FTC allegations about its cancellation practices ([Hogan Lovells](https://hlc.com/en/publications/ftc-orders-chegg-to-pay-75-million-over-subscription-cancellation-practices)). - **Uber (Uber One).** The FTC's lawsuit, first filed in 2025, was amended in December 2025 to add 21 states and the District of Columbia as co-plaintiffs; the case is pending and the allegations are unproven ([Goodwin](https://www.goodwinlaw.com/en/insights/publications/2026/02/alerts-practices-ba-ftcs-click-to-cancel-rule-gets-new-life)). ROSCA is written for consumers. Whether and how it reaches a business-to-business sale depends on the facts; ask counsel if your customers are mostly companies. ## US states: California as the reference point Many states have their own automatic renewal laws. California's is the one most SaaS teams design around, because it is detailed and widely copied. California's Automatic Renewal Law (Cal. Bus. & Prof. Code sections 17600 and following) was amended by [AB 2863](https://calmatters.digitaldemocracy.org/bills/ca_202320240ab2863), signed in September 2024, with changes effective **July 1, 2025**. According to law firm summaries ([Davis Wright Tremaine](https://dwt.com/insights/2024/10/ab-2863-updates-california-automatic-renewal-law); [Venable](https://www.venable.com/insights/publications/2024/09/california-amends-autorenewal-law-with-stricter); [Kilpatrick](https://ktslaw.com/en/Insights/Alert/2024/10/California-Latest-Automatic-Renewal-Law-Amendments-Take-Effect-in-July-2025)), the amended law includes: - **Express affirmative consent** to the automatic renewal terms, kept on record. - **Online cancellation** for customers who signed up online, without unnecessary steps or delay. - **A limited save attempt.** When a consumer cancels online, the business may present a save offer only if it also shows a prominent, continuously displayed option to cancel. Summaries differ on details, so read the statute text. - **Prompt processing** of cancellation requests, including those made by phone or voicemail. - **Annual reminders** of the auto-renewal terms, and notice before certain price changes. The law protects consumers in California, so a US-wide consumer product will usually follow it everywhere rather than run a separate flow per state. Other states have their own laws with different notice periods and triggers. We don't list them here because the details differ and change; a lawyer or a maintained state law tracker is the right source. ## European Union ### No general "cancel as easily as you subscribed" rule yet EU consumer law already prohibits unfair commercial practices and requires clear pre-contract information, but as of this writing there is no EU-wide rule that cancelling a subscription must be as easy as signing up ([Covington's Inside Privacy, DFA series](https://www.insideprivacy.com/consumer-protection/digital-fairness-act-series-topic-4-digital-subscriptions/)). ### The withdrawal function (from June 19, 2026) [Directive (EU) 2023/2673](https://eur-lex.europa.eu/eli/dir/2023/2673/oj) adds Article 11a to the Consumer Rights Directive. For distance contracts concluded through an online interface that carry a right of withdrawal, traders must provide a clearly labeled, easy-to-find **withdrawal function**, with a confirmation step and an automatic acknowledgment on a durable medium such as email. Member states had to transpose the directive by December 19, 2025, with the rules applying from June 19, 2026 ([Greenberg Traurig](https://www.gtlaw.com/en/insights/2026/5/eu-consumer-law-new-withdrawal-button-requirements-for-online-contracts); [iubenda](https://www.iubenda.com/en/blog/the-new-online-withdrawal-function-what-eu-directive-2023-2673-means-for-your-business/)). Some member states were reported to be late with transposition ([Van Bael & Bellis](https://vbb.com/wp-content/uploads/2026/06/8-06-26-The-online-withdrawal-button.pdf)). Note the difference: **withdrawal** is the consumer's right to back out of a new contract, usually within 14 days. **Cancellation** is ending an ongoing subscription later. The withdrawal function covers the first, not the second. For a subscription sold to EU consumers, it still matters in the first two weeks. ### The Digital Fairness Act (expected) The European Commission is preparing a Digital Fairness Act that is expected to address subscription traps, including easier cancellation and renewal reminders. As of November 3, 2026, the proposal has not been published; reports point to a release in the coming weeks, and it would then go through the Parliament and Council ([CMS](https://cms.law/en/gbr/legal-updates/inside-the-eu-s-planned-digital-fairness-act-digital-design-subscription-traps-and-influencer-marketing); [AKD](https://www.akd.eu/insights/the-digital-fairness-act-what-to-expect-from-the-forthcoming-eu-legislative-proposal-on-strengthening-consumer-protection-rules-for-the-digital-age/)). Don't plan around specific requirements until there is a text. ### Germany: the cancellation button Germany already has a specific rule. Since July 1, 2022, [section 312k of the German Civil Code (BGB)](https://www.gesetze-im-internet.de/bgb/__312k.html) requires businesses that let consumers enter ongoing contracts through a website to provide a clearly labeled cancellation button (for example "Verträge hier kündigen") that leads to a confirmation page. If you sell subscriptions to German consumers, you need this regardless of what the EU does next. ## United Kingdom The [Digital Markets, Competition and Consumers Act 2024](https://www.legislation.gov.uk/ukpga/2024/13/contents) includes a subscription contracts regime: clearer pre-contract information, reminder notices, a cooling-off period, and an easy way to end the contract. That part of the Act is not yet in force. In April 2026, the government said it would start in spring 2027 ([Taylor Wessing](https://www.taylorwessing.com/en/insights-and-events/insights/2026/04/subscription-contracts)); in August 2026, the start was brought forward to January 2027 ([TLT](https://www.tlt.com/insights-and-events/insight/dmcc-act-subscription-contracts-regime-brought-forward-by-the-pm-what-do-businesses-need-to-know); [Latham & Watkins](https://www.lw.com/en/insights/new-requirements-accelerated-for-uk-consumer-subscription-contracts)). Commentators noted that secondary legislation and guidance were still pending ([Wiggin](https://www.wiggin.co.uk/insight/digital-markets-competition-and-consumer-act-tracker/)). Check gov.uk for the final commencement regulations. ## B2B vs B2C Most of the rules above protect **consumers**. A SaaS company that only sells to businesses under negotiated contracts may fall outside many of them. But the line is not always clean: self-serve plans bought with a personal card, sole traders and freelancers can look a lot like consumers. Many B2B SaaS teams choose to meet consumer standards anyway, because it is simpler than maintaining two flows and because customers expect it. ## A practical baseline If you sell subscriptions online and want one flow that holds up in most markets, a reasonable baseline is: - [ ] Customers who signed up online can cancel online, in the same channel (web, app). - [ ] A clear "Cancel" control is easy to find in account settings. - [ ] Any save offer is shown alongside a visible, working cancel button. - [ ] One save attempt, not a series. - [ ] Cancellation takes effect without requiring a call, chat or email. - [ ] Confirmation on screen and by email, with the end date. - [ ] Renewal terms and price disclosed clearly before the first charge, with recorded consent. - [ ] Renewal reminders where required (for example annual plans in California). - [ ] For EU consumers: a withdrawal function for the first 14 days; for Germany, the cancellation button. - [ ] A lawyer has reviewed the flow for your actual markets. Our [cancel flow best practices](/blog/cancel-flow-best-practices/) guide covers the design side of this checklist. ## How NoChurn helps NoChurn's [cancel flows](/#cancel) are built around the baseline above: a reason, at most one matching offer (discount through a Stripe coupon, pause, downgrade or call), and a one-click "Cancel now" button visible on every step. The flow works as a hosted modal or through the headless API on web, desktop, iOS and Android, so cancellation can live in the same channel as signup. NoChurn does not make your business compliant on its own; your terms, disclosures, reminders and legal review remain your responsibility. See [pricing](/pricing/) and the [docs](/docs/) for details. --- # Dunning email templates: ready-to-use examples for day 0, 3, 7 and 14 Source: https://www.nochurn.sh/blog/dunning-email-templates/ When a subscription payment fails, the email you send next does most of the recovery work that retries cannot. A good dunning email is short, specific and easy to act on. A bad one reads like a collections notice and sends a loyal customer looking for the cancel button. Below are four original templates for a standard 14-day sequence, plus subject lines, a hard-decline variant, and guidance on adjusting tone for new versus long-time customers. Copy them, change the bracketed parts, and test them against your own numbers. ## The sequence at a glance The timing below assumes monthly billing and a retry window of about two weeks, which matches the default recommended in [Stripe's Smart Retries settings](https://docs.stripe.com/billing/revenue-recovery/smart-retries). If your window is different, keep the same shape and stretch or compress the days. | Day | Purpose | Length | Call to action | |---|---|---|---| | 0 | Inform: the payment failed | 60–90 words | Update payment method | | 3 | Remind and reassure | 60–90 words | Update payment method | | 7 | Set a clear deadline | 70–100 words | Update payment method | | 14 | Final notice | 60–90 words | Update payment method, or reply | Every email has the same single button. Repetition is fine; customers do not read the sequence as a whole, they read whichever email they open. ## Rules that apply to every email 1. **Send from a name.** "Maya at Acme" or "Acme Billing", with a reply-to address someone reads. 2. **Say exactly what happened.** Amount, plan name, card brand and last four digits. 3. **One button, one link.** It goes straight to a card update page that does not require a password. 4. **No blame.** "Your payment didn't go through", not "You failed to pay". 5. **No scare tactics.** State consequences once, factually, with a date. 6. **Plain formatting.** Short paragraphs, little or no imagery. Plain emails tend to look personal and load fast on phones. 7. **Do not reveal sensitive decline reasons.** Stripe's [decline codes reference](https://docs.stripe.com/declines/codes) advises showing a generic message for codes like `fraudulent` or `lost_card`. ## Day 0: the first notice Send this within an hour of the first failure. Its job is to inform, not to pressure. Many customers simply have not noticed that their card changed. **Subject line options** - Your payment for [Product] didn't go through - Quick fix needed for your [Product] subscription - We couldn't charge your [Card brand] ending [1234] ```text Hi [First name], We tried to charge [Amount] for your [Plan] plan on [Date], but the payment on your [Card brand] ending [1234] didn't go through. This happens for lots of reasons: a new card, a spending limit, or a bank being cautious. Nothing is wrong with your account. You can update your payment details here in about a minute: [Update payment method] We'll also try the card again automatically over the next few days. Thanks, [Sender name] [Product] ``` ## Day 3: the friendly reminder By day 3, at least one retry has usually run. This email reminds without escalating, and answers the question customers tend to have: "What do I actually need to do?" **Subject line options** - Reminder: your [Product] payment is still pending - Still having trouble with your card? - Your [Plan] plan: one small thing to fix ```text Hi [First name], Just a reminder that your [Amount] payment for [Product] is still pending. We tried your [Card brand] ending [1234] again, without success. The quickest fix is to add a new card or a different payment method: [Update payment method] If the card should work, your bank may be blocking the charge. A quick call to them usually sorts it out. Have a question? Just reply to this email. [Sender name] ``` ## Day 7: the clear deadline This is the email where you state the consequence and the date. Stay factual. Customers respond better to a specific date than to vague warnings. **Subject line options** - Action needed: your [Product] access changes on [Date] - Your [Product] subscription will pause on [Date] - Keep your [Plan] plan active: update your card by [Date] ```text Hi [First name], We still haven't been able to collect [Amount] for your [Plan] plan. To avoid any interruption, please update your payment method before [Date]. After that, your account will [be paused / move to the free plan / lose access to X]. [Update payment method] Your data and settings are safe. Once the payment goes through, everything works exactly as before. If something has changed and you need a different plan, reply and we'll help. [Sender name] ``` Replace the bracketed consequence with what actually happens in your product. Never threaten something you will not do. ## Day 14: the final notice This is the last email before the subscription is canceled, marked unpaid, or downgraded, depending on what you set in your billing tool. Keep it short and respectful. Leave the door open. **Subject line options** - Final notice: your [Product] subscription ends today - Last chance to keep your [Product] account active - We'll pause your [Product] account tomorrow ```text Hi [First name], This is our last reminder about the [Amount] payment for your [Plan] plan. Unless the payment goes through, your subscription will [end / be paused] on [Date]. [Update payment method] If you meant to cancel, no action is needed, and thank you for being a customer. If not, updating your card takes about a minute. [Sender name] ``` ## Variant: hard declines and expired cards When the decline code shows the card cannot be charged again (for example `expired_card`, `lost_card` or `incorrect_number`), retries will not help, so skip the "we'll try again" line and ask for a new card on day 0. **Subject line:** Your card on file for [Product] needs updating ```text Hi [First name], The card we have on file for [Product] can no longer be charged, so your [Amount] payment on [Date] didn't go through. Please add a new card or another payment method to keep your [Plan] plan running: [Update payment method] It takes about a minute, and your account stays exactly as it is. [Sender name] ``` ## Variant: authentication required In the EU and UK, banks may ask the customer to confirm a payment with 3D Secure. Stripe returns `authentication_required` in that case. The email should send customers to a page where they confirm the payment, not to a card form. **Subject line:** Please confirm your [Product] payment ```text Hi [First name], Your bank asked for a quick confirmation before approving your [Amount] payment for [Product]. [Confirm payment] It usually takes a few seconds in your banking app. [Sender name] ``` ## Adjusting tone by customer tenure The same template does not fit everyone. A customer in their second month and a customer in their third year have different relationships with you. | Tenure | What they need | Tone adjustments | |---|---|---| | First 1–3 months | Reassurance the product is worth keeping | Remind them of one thing they set up or used; keep it light | | 3–12 months | A low-effort fix | Standard templates work; emphasize "about a minute" | | 1 year or more | Recognition | Thank them for being a customer; offer a personal reply; consider a longer grace period | | Annual plans | Clarity on a larger amount | State the amount and period clearly; offer to split or switch to monthly if that is an option you actually provide | ### Example: a long-time customer, day 3 ```text Hi [First name], You've been with [Product] since [Month Year], so we wanted to reach out personally. Your [Amount] payment didn't go through this month, probably because of a card change. [Update payment method] If anything about your plan needs to change, just reply. I read every response. [Sender name], [Role] ``` ### Example: a new customer, day 0 ```text Hi [First name], Your first renewal for [Product] didn't go through on your [Card brand] ending [1234]. You've already [set up X / imported Y], so updating your card keeps all of that in place: [Update payment method] [Sender name] ``` Only reference usage you can actually pull from your data. A personalization line that is wrong reads worse than none. ## Subject line checklist - States the product name, so the email is recognized in a busy inbox. - Says what happened or what to do, in under about 50 characters where possible. - Avoids all caps, exclamation marks and words like "urgent" in the first emails. - Matches the email body. Do not promise "a quick fix" and then send a wall of text. - Has been tested. If you can, A/B test two subject lines on day 0, where volume is highest. ## Common mistakes - **Linking to a login page.** Customers who forgot their password drop off. Use a link that opens the update page directly. - **Sending the same email four times.** Each email should add something: reassurance, a tip, a date, a final notice. - **Ignoring replies.** Replies such as "I've changed banks" or "please cancel" need a human or a fast, accurate answer. - **Sending in the wrong language.** If your customer signed up in German, the dunning email should be in German. - **Not stopping the sequence.** As soon as the invoice is paid, the remaining emails must stop. Test this. - **Over-relying on Stripe's default emails.** Stripe can send [failed payment and expiring card emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails), which is a good baseline, but the copy is generic and not tied to decline reasons or tenure. For the rest of the recovery process (retries, decline codes, card update pages and measurement), see the [complete guide to recovering failed payments on Stripe](/blog/recover-failed-payments-stripe/). If the customer cancels anyway, the next step is a [win-back sequence](/blog/win-back-email-examples/). ## How NoChurn helps NoChurn sends recovery emails on day 0, 3, 7 and 14 by default. They are written by AI in the customer's language (English, German, French, Italian or Portuguese) and reviewed before sending. Each one links to a hosted card update page where card data stays with Stripe; NoChurn never sees card numbers. Replies are read, sorted, and either answered or sent to your team. It connects to Stripe in one click, or works through the REST API if you run your own billing. See [how failed payment recovery works](/#dunning) and [pricing](/pricing/). --- # Expiring cards: how to stop them from ending your subscriptions Source: https://www.nochurn.sh/blog/expiring-cards/ Every card has an expiry date, and every subscription that outlives a card will eventually hit it. When it does, the renewal fails, often for a customer who has no intention of leaving. Expiring cards are one of the most predictable causes of failed payments, which makes them one of the easiest to handle ahead of time. This guide covers what Stripe does automatically, what it cannot do, and the simple process that catches the rest: find cards about to expire, email the customer before the renewal, and make updating the card take one minute. ## What happens when a saved card expires When you charge a card after its expiry date, the issuer declines it, typically with the `expired_card` decline code ([Stripe decline codes](https://docs.stripe.com/declines/codes)). Retrying the same card details will not help. Either the card details get updated, or the customer has to provide a new payment method. There are two ways to get new details: 1. **The card network sends them**, through automatic card updates (also called a card account updater). 2. **The customer enters them**, after you ask. You want as many cards as possible handled by the first path, and a smooth second path for the rest. ## Stripe automatic card updates Stripe's [cards overview](https://docs.stripe.com/payments/cards/overview) explains how automatic card updates work. When a customer's bank issues a replacement card (because the old one expired, or was reported lost or stolen), participating issuers share the new details through the card networks, and Stripe updates the saved card for you. Key points from Stripe's documentation: - **It depends on the issuer.** Only issuers that participate in the networks' updater programs send updates. - **Coverage varies by country.** In the US, Stripe can update most American Express, Visa, Mastercard and Discover cards. Outside the US, support varies. - **You cannot tell in advance which cards will be updated.** Stripe says it is not possible to identify which cards support automatic updates. - **You can track updates.** Stripe sends a `payment_method.automatically_updated` webhook when a card is updated by the network, including the new expiry date and last four digits. If the card number changed, the card's fingerprint changes too. Stripe has also announced [expanded network tokens and card account updater coverage](https://stripe.com/newsroom/news/network-tokens-card-account-updater), including real-time updates for some networks and regions. Check the announcement and the docs for the current scope in your markets. ### What automatic updates miss Even with good coverage, some expiring cards will not be updated: - The issuer does not participate, or not in that country. - The customer closed the account or switched banks; there is no "new card" to send. - The card was a prepaid or single-use virtual card that is not reissued. - The update arrives after the renewal attempt. So plan for automatic updates to reduce the problem, not to solve it. ## Step 1: find cards that are about to expire Every saved card on Stripe has `exp_month` and `exp_year` on the PaymentMethod's `card` object. A daily or weekly job can list customers whose default card expires before their next renewal. A simple rule: ```text Flag a subscription when: the default payment method is a card, and the card expires before the next invoice date, and no automatic update has been received for that card ``` Remember that a card is usually valid through the last day of its expiry month. A card marked 11/2026 should still work on November 20, 2026, and fail on a December renewal. Listen to `payment_method.automatically_updated` and remove a card from your list as soon as the network updates it. There is no reason to email a customer whose card has already been fixed. ### Example timing | Renewal date | Card expiry | Status | Action | |---|---|---|---| | Dec 5 | 11/2026 | Will fail | Email in mid November | | Nov 20 | 11/2026 | Still valid | Check again before next renewal | | Jan 3 | 12/2026 | Will fail | Email in mid December | | Dec 5 | 11/2026, updated by network | Fixed | No action | These rows are hypothetical examples for illustration. ## Step 2: email the customer before the renewal Stripe can do part of this for you. In the [customer emails settings](https://docs.stripe.com/billing/revenue-recovery/customer-emails), you can turn on emails about expiring cards. That is a reasonable baseline. If you want to control timing, wording, language, or skip customers whose cards were already updated, send your own. A pre-expiry sequence that works well for monthly plans: | When | Email | Notes | |---|---|---| | About 2–3 weeks before renewal | "Your card expires soon" | Main email | | About 3 days before renewal | Short reminder | Only if not updated | | Renewal day | Normal failed payment flow | If the charge fails | For annual plans, start earlier (for example 30 days before renewal) and include the renewal amount, since it is larger. ### Template: card expiring soon ```text Subject: Your card for [Product] expires soon Hi [First name], The [Card brand] ending [1234] that you use for [Product] expires at the end of [Month]. Your next payment of [Amount] is on [Renewal date]. To avoid any interruption, you can add your new card here: [Update payment method] If you've already received a replacement card from your bank, it may have been updated automatically. You can check on the same page. Thanks, [Sender name] ``` ### Template: short reminder ```text Subject: Reminder: update your card before [Renewal date] Hi [First name], Quick reminder: your [Card brand] ending [1234] expires before your next [Product] payment on [Renewal date]. [Update payment method] It takes about a minute. [Sender name] ``` Keep these emails plain and short. They are not urgent yet, and the tone should reflect that. ## Step 3: make the card update page effortless The email is only as good as the page it links to. On Stripe, you can use the [customer portal](https://docs.stripe.com/customer-management), which lets customers manage their payment methods, or build your own page with Stripe Elements. Checklist for the page: - [ ] Opens from the email without asking for a password. - [ ] Shows the card currently on file (brand, last four digits, expiry) so the customer knows what they are replacing. - [ ] Works on a phone. - [ ] Offers wallets such as Apple Pay, Google Pay or Stripe Link where available. - [ ] Sets the new card as the default for the subscription, not just as an extra card. - [ ] Confirms success in plain words. The fourth item is a common bug. If the new card is saved to the customer but the subscription still points to the old default, the renewal fails anyway. ## Step 4: if the renewal still fails Some customers will not act before the renewal. Treat the `expired_card` failure as a hard decline: skip the "we'll retry" language and ask for a new card on day 0. Then follow your normal [dunning email sequence](/blog/dunning-email-templates/). The full process is in the [complete guide to recovering failed payments on Stripe](/blog/recover-failed-payments-stripe/). ## Measuring how well you handle expiring cards Track these each month: | Metric | How to compute | |---|---| | Cards expiring before renewal | Count of flagged subscriptions | | Updated automatically | Flagged cards that received a network update | | Updated by the customer before renewal | Flagged cards replaced after your email | | Failed at renewal with `expired_card` | Renewals that failed for this reason | | Recovered after failure | Of those, how many were paid later | If many renewals still fail with `expired_card`, look at email timing (too late?), deliverability (are emails landing in spam?), and the update page (is there a password wall?). ## Common mistakes - **Emailing customers whose cards were already updated.** It is confusing and erodes trust. Check for automatic updates first. - **Sending only after the failure.** By then the customer has a failed payment notice instead of a friendly heads-up. - **Forgetting other payment methods.** Expiry applies to cards. Bank debits like SEPA Direct Debit do not expire the same way, which is one reason to offer them. - **Not updating the subscription's default payment method.** - **Ignoring annual plans.** One expired card on an annual plan can be a large invoice. ## How NoChurn helps NoChurn connects to Stripe in one click and handles failed payments end to end: smart retries (or Stripe Smart Retries if you prefer), AI-written recovery emails on day 0, 3, 7 and 14 in the customer's language, reviewed before sending, and a hosted card update page where card data stays with Stripe. NoChurn never sees card numbers. It also flags customers who remove their card before renewal and starts a save flow before the payment fails. See [how failed payment recovery works](/#dunning) and [pricing](/pricing/). --- # How to calculate churn rate: customer, gross and net revenue churn Source: https://www.nochurn.sh/blog/how-to-calculate-churn-rate/ "What's our churn?" sounds like a simple question, but it has at least three correct answers depending on what you count. Customer churn, gross revenue churn and net revenue churn can tell very different stories about the same month. This guide gives the formulas, works through each with an example, shows how to convert monthly churn to annual churn correctly, and lists the mistakes that most often distort the numbers. All examples use hypothetical numbers. ## The three churn rates | Metric | What it measures | Counts | |---|---|---| | Customer churn (logo churn) | Share of customers who left | Customers | | Gross revenue churn | Share of recurring revenue lost | Cancellations and downgrades | | Net revenue churn | Revenue lost after expansion from remaining customers | Cancellations, downgrades and upgrades | Use customer churn to understand how many relationships you keep. Use revenue churn to understand the money. Most subscription businesses track all three. ## Customer churn rate ### Formula ```text customer churn rate = customers lost during the period ÷ customers at the start of the period ``` Only count customers who were there at the start. New customers who sign up during the period are not in the denominator, so they should not be in the numerator either (see the mistakes section). ### Example A company has 400 customers on March 1. During March, 20 of them cancel or are lost to failed payments, and 30 new customers sign up. On March 31 it has 410 customers. ```text customer churn = 20 ÷ 400 = 5.0% ``` The 30 new customers do not change the churn rate. They change growth, which is a different metric. ### Variant: average customers Some teams divide by the average number of customers over the period instead of the starting count: ```text average customers = (400 + 410) ÷ 2 = 405 customer churn = 20 ÷ 405 = 4.9% ``` This variant is useful when the customer base grows quickly within the period. Either method is fine; pick one and use it consistently. ## Gross revenue churn Revenue churn uses monthly recurring revenue (MRR). Annual plans are counted as one twelfth of their annual price per month. ### Formula ```text gross revenue churn = (MRR lost to cancellations + MRR lost to downgrades) ÷ MRR at the start of the period ``` Gross revenue churn never includes upgrades or new customers. It can never be negative. ### Example The same company starts March with $40,000 MRR. During the month: - Cancellations remove $2,000 MRR. - Downgrades (customers moving to a cheaper plan) remove $600 MRR. - Upgrades from existing customers add $1,800 MRR. - New customers add $3,000 MRR. ```text gross revenue churn = (2,000 + 600) ÷ 40,000 = 6.5% ``` ## Net revenue churn ### Formula ```text net revenue churn = (MRR lost to cancellations + MRR lost to downgrades − MRR gained from upgrades of existing customers) ÷ MRR at the start of the period ``` New customers are still excluded. Only expansion from customers who were already there at the start counts. ### Example Using the same numbers: ```text net revenue churn = (2,000 + 600 − 1,800) ÷ 40,000 = 800 ÷ 40,000 = 2.0% ``` If upgrades had been larger than losses, for example $3,000 of expansion, net revenue churn would be negative: ```text (2,000 + 600 − 3,000) ÷ 40,000 = −1.0% ``` Negative net revenue churn means the existing customer base grew in revenue even before adding new customers. ### Net revenue retention Many teams report the same information as net revenue retention (NRR): ```text NRR = (starting MRR − cancellations − downgrades + upgrades) ÷ starting MRR = (40,000 − 2,000 − 600 + 1,800) ÷ 40,000 = 39,200 ÷ 40,000 = 98% ``` Net revenue churn of 2% and NRR of 98% describe the same month. ## When customer churn and revenue churn disagree Suppose a hypothetical company with $50,000 MRR loses, in one month: - **Scenario A:** 20 small customers paying $50 each. That is $1,000 MRR. - **Scenario B:** 1 large customer paying $2,000. If it has 500 customers at the start, scenario A is 4% customer churn and 2% revenue churn. Scenario B is 0.2% customer churn and 4% revenue churn. Neither number alone tells the full story. Report both. ## Splitting voluntary and involuntary churn Churn has two sources: customers who decide to cancel (voluntary) and customers lost because a payment could not be collected (involuntary). Splitting them matters because the fixes are completely different: product and cancel flows for the first, payment recovery for the second. ```text voluntary churn = customers who canceled ÷ customers at start involuntary churn = customers lost to failed payments ÷ customers at start ``` In the March example, if 14 of the 20 lost customers canceled and 6 were lost to failed payments, voluntary churn is 3.5% and involuntary churn is 1.5%. More on this in [what involuntary churn is and how to reduce it](/blog/involuntary-churn/). For context, [Recurly's churn benchmarks](https://recurly.com/research/churn-rate-benchmarks/) (accessed November 2026) report an average monthly churn rate of 3.60% across industries, split into 2.34% voluntary and 1.25% involuntary. Benchmarks vary a lot by industry, price point and method, so compare against your own history first. ## Converting monthly churn to annual churn A common mistake is multiplying monthly churn by 12. Churn compounds: each month you lose a percentage of a smaller base. ```text annual churn = 1 − (1 − monthly churn) ^ 12 ``` With 5% monthly customer churn: ```text 1 − (0.95) ^ 12 = 1 − 0.540 = 46.0% ``` Not 60%. The difference grows as churn rises. | Monthly churn | Multiplied by 12 (wrong) | Compounded (right) | |---|---|---| | 1% | 12% | 11.4% | | 2% | 24% | 21.5% | | 3% | 36% | 30.6% | | 5% | 60% | 46.0% | This conversion assumes the monthly rate stays constant and applies to the same cohort, which is a simplification. For annual plans, measure annual churn directly at renewal. ## Cohort churn Overall churn mixes customers of all ages. New customers usually churn faster than long-time ones, so a month with many new signups can look worse even if nothing changed. Cohort analysis groups customers by signup month and tracks what share is still active after 1, 2, 3 months and so on. | Signup cohort | Customers | Month 1 | Month 2 | Month 3 | |---|---|---|---|---| | January | 100 | 88 | 81 | 77 | | February | 120 | 104 | 96 | | | March | 90 | 81 | | | These are hypothetical numbers. Reading down a column shows whether recent cohorts retain better or worse than older ones, which is the clearest way to see if product or onboarding changes worked. ## Common mistakes 1. **Including new customers in the numerator.** If a customer signs up and cancels in the same month, they were not in the starting count. Either track them separately (often called first-month churn) or use the average-customers method consistently. 2. **Including new revenue in net revenue churn.** Only expansion from existing customers belongs there. New customer MRR is growth. 3. **Annualizing by multiplying by 12.** Use the compounding formula. 4. **Mixing monthly and annual plans without normalizing.** Convert all plans to MRR before calculating revenue churn. 5. **Counting failed payments as churn too early, or never.** A failed payment is not churn until the subscription ends. But if past-due subscriptions stay "active" indefinitely, involuntary churn disappears from your reports. Set a rule, such as counting the customer as lost when the subscription is canceled or 30 days after the final retry. 6. **Counting paused subscriptions as churned (or as active) without saying so.** Decide how pauses are treated and document it. 7. **Changing the definition between reports.** A churn rate is only useful as a trend. Write the definition down and keep it. 8. **Reporting averages across very different segments.** Monthly consumer plans and annual B2B contracts churn differently. Report by segment where it matters. 9. **Ignoring sample size.** With 40 customers, two cancellations move churn by five points. Look at multi-month trends. ## A simple monthly churn report | Metric | Value | |---|---| | Customers at start | | | Customers lost (voluntary / involuntary) | | | Customer churn | | | MRR at start | | | MRR lost to cancellations | | | MRR lost to downgrades | | | MRR from upgrades | | | Gross revenue churn | | | Net revenue churn / NRR | | | Failed payment recovery rate | | Fill it in the same way every month, and add a short note on anything unusual, such as a price change or a large customer leaving. To go further, see [how to find which customer attributes predict churn](/blog/predict-churn-with-customer-data/) and the [complete guide to recovering failed payments on Stripe](/blog/recover-failed-payments-stripe/). ## How NoChurn helps NoChurn works on both sides of churn. For involuntary churn, it recovers failed payments with smart retries, AI-written emails on day 0, 3, 7 and 14, and a hosted card update page. For voluntary churn, it runs cancel flows that match an offer to the cancel reason (discount, pause, downgrade or a call) with a one-click cancel always visible, and sends win-back emails at 30, 60 and 90 days. You can also send your own customer attributes and usage events. NoChurn computes which ones go with churn (relative risk, sample size, confidence) and AI explains the results. Correlation, not cause. See [custom data](/#insights), [cancel flows](/#cancel) and [pricing](/pricing/). --- # Involuntary churn: what it is, what causes it, and how to reduce it Source: https://www.nochurn.sh/blog/involuntary-churn/ Some customers cancel. Others never decide to leave at all: their card is declined, nobody fixes it, and the subscription ends. The second group is involuntary churn, and it is the easiest churn to reduce because the customer still wants your product. This article explains what counts as involuntary churn, the most common causes, how to measure it without fooling yourself, and what to do about it. ## Definition **Involuntary churn** is the loss of subscribers or revenue because a payment could not be collected, not because the customer chose to cancel. **Voluntary churn** is the opposite: the customer actively cancels or decides not to renew. The line is not always perfectly clean. A customer who sees a failed payment email and decides not to bother fixing it is somewhere in between. In practice, most teams classify churn by what ended the subscription: a cancellation request is voluntary; a subscription ended by failed payments is involuntary. ## How big is it? Involuntary churn is a meaningful share of churn for most subscription businesses. [Recurly's churn benchmarks](https://recurly.com/research/churn-rate-benchmarks/) (accessed November 2026) report an average monthly churn rate of 3.60% across industries, of which 1.25% is involuntary and 2.34% voluntary. Recurly also reports that involuntary churn falls sharply as the price per customer rises, so low-priced consumer subscriptions tend to feel it most. Your own number may be very different. Measure it before deciding how much effort it deserves. ## Common causes | Cause | What happens | Fixable by retries? | |---|---|---| | Insufficient funds | Not enough money or credit at the time of the charge | Often, if retried at a better time | | Expired card | The card on file passed its expiry date | No, unless the network sends updated details | | Replaced card (lost, stolen, reissued) | The old number no longer works | No; needs a new card or an automatic update | | Issuer declines without a reason | `do_not_honor`, `generic_decline` | Sometimes | | Authentication required | The bank asks the customer to confirm (3D Secure) | No; the customer must confirm | | Spending or velocity limits | The customer hit a card limit | Often, later | | Prepaid or single-use virtual cards | Balance runs out or the card is closed | Rarely | | Fraud filters | Your own or the issuer's rules block a legitimate payment | Sometimes | Stripe's [decline codes reference](https://docs.stripe.com/declines/codes) lists each code with a suggested next step. Stripe also lists the [hard decline codes it will not retry automatically](https://docs.stripe.com/billing/revenue-recovery/smart-retries), such as `lost_card`, `stolen_card` and `authentication_required`. Those need customer action, every time. ## How to measure involuntary churn ### The basic formulas **Involuntary customer churn rate** for a period: ```text customers lost to failed payments during the period ÷ customers at the start of the period ``` **Involuntary revenue churn rate**: ```text MRR lost to failed payments during the period ÷ MRR at the start of the period ``` **Share of churn that is involuntary**: ```text customers lost to failed payments ÷ all customers lost ``` ### A worked example These numbers are hypothetical. A company starts March with 400 customers and $20,000 MRR. - 14 customers cancel during March (voluntary), representing $650 MRR. - 6 customers' subscriptions end after all payment retries fail (involuntary), representing $330 MRR. Then: - Total customer churn: (14 + 6) / 400 = 5.0% - Involuntary customer churn: 6 / 400 = 1.5% - Voluntary customer churn: 14 / 400 = 3.5% - Share of churn that is involuntary: 6 / 20 = 30% - Involuntary revenue churn: $330 / $20,000 = 1.65% For the general churn formulas, including net revenue churn, see [how to calculate churn rate](/blog/how-to-calculate-churn-rate/). ### Measurement pitfalls - **Counting failures instead of losses.** A failed payment is not churn until the subscription actually ends. Many failures are recovered. - **Timing mismatch.** A payment that fails on March 28 may be recovered or lost in April. Attribute the loss to the month the subscription ends, and track failures as their own cohort. - **Status settings hide churn.** If your billing tool leaves subscriptions "past due" forever after retries fail, they never show up as churned. Decide when a past-due subscription counts as lost (for example, 30 days after the final retry). - **Mixing voluntary cancellations into dunning.** Some customers cancel while in dunning. Classify them consistently. - **Annual plans.** One lost annual renewal can move revenue churn a lot. Report annual and monthly plans separately if both matter. ### Metrics to track alongside - **Failed payment rate**: share of renewal charges that fail on the first attempt. - **Recovery rate**: share of failed invoices eventually paid, by count and by amount, within a fixed window. - **Time to recovery**: days from first failure to payment. - **Hard vs soft decline mix**: tells you whether to invest in retries or in getting new cards. ## How to reduce involuntary churn ### 1. Prevent failures before renewal - **Use automatic card updates.** Stripe can update saved card details when an issuer sends a new number or expiry date. Coverage depends on the issuer and the country; see [Stripe's cards overview](https://docs.stripe.com/payments/cards/overview). - **Email before cards expire.** Stripe can send [expiring card emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails), or you can send your own. More in our [guide to expiring cards](/blog/expiring-cards/). - **Watch for removed cards.** A customer who deletes their only card a week before renewal is telling you something. - **Offer stable payment methods.** Wallets and bank debits can be a good fit for some customers. - **Look at payment method risk at signup.** Prepaid and single-use virtual cards are designed to stop working. See [prepaid and virtual cards and churn](/blog/prepaid-virtual-cards-churn/). ### 2. Retry intelligently Turn on [Stripe Smart Retries](/blog/stripe-smart-retries/) or a custom schedule. Make sure the retry window fits your billing cycle and that hard declines skip straight to asking for a new card. ### 3. Tell the customer, clearly and quickly Retries are invisible to the customer. Send an email on the first failure, then follow up. A standard sequence is day 0, 3, 7 and 14. We have [templates for each step](/blog/dunning-email-templates/). ### 4. Make the fix take one minute A direct link to a card update page, no password, mobile friendly, with wallets. Pay the open invoice as soon as the card is updated. ### 5. Handle authentication If you sell in the EU or UK, some renewals will need the customer to confirm the payment. Send a confirmation link instead of a "please update your card" email. ### 6. Choose what happens at the end, deliberately Canceling right after the last retry is clean but final. Pausing access or marking the subscription unpaid keeps the account ready to restore. Some teams give long-tenured customers a longer grace period. ### 7. Answer the replies Customers reply to dunning emails with useful information: "new card coming next week", "please switch me to annual", "I meant to cancel". Make sure those replies reach someone. ## Involuntary churn checklist - [ ] You can report involuntary churn separately from voluntary churn. - [ ] You know your failed payment rate and recovery rate for the last three months. - [ ] Automatic card updates are on and you track the updates. - [ ] Customers get a pre-expiry email. - [ ] Retries are configured, and hard declines trigger an immediate request for a new card. - [ ] A dunning email goes out on the first failure. - [ ] The card update page works on mobile without a password. - [ ] Authentication links are sent where needed. - [ ] The end-of-retries action is a deliberate choice. - [ ] Replies to billing emails reach a person. ## How NoChurn helps NoChurn focuses on involuntary churn first. It connects to Stripe in one click (or works through the REST API with your own billing), retries failed payments at times based on likely paydays and the customer's local time (or keeps Stripe Smart Retries), and sends AI-written recovery emails on day 0, 3, 7 and 14, reviewed before sending and in the customer's language. Emails link to a hosted card update page; card data stays with Stripe. It also gives each new customer a churn score at signup, based partly on the payment method, and flags customers who remove their card before renewal so you can act before the payment fails. See [failed payments](/#dunning), [the churn score](/#score) and [pricing](/pricing/). --- # Network tokens and card account updaters: what they fix and what they don't Source: https://www.nochurn.sh/blog/network-tokens-card-account-updater/ A subscription is a promise to charge the same card for months or years. Cards do not last that long. They expire, get replaced after a fraud alert, get reissued when a bank changes its card program, or are closed. Each of those events can turn a healthy customer into a failed renewal. Card networks have two mechanisms to soften this: **card account updaters** and **network tokens**. Stripe uses both for you, mostly without any setup. They are worth understanding, because they explain why some cards keep working after they "should" have failed, and why others still fail no matter what. This guide covers both, based on Stripe's and the networks' own documentation (accessed November 2026). ## The problem they solve When you save a card for a subscription, Stripe stores the card number (the PAN) and expiry date, securely, on your behalf. If the customer's bank issues a new card with a new number or a new expiry date, the stored details go stale. The next charge fails, typically with `expired_card` or another decline. See [Stripe decline codes explained](/blog/stripe-decline-codes/). Both mechanisms aim to get the new details to you before that happens. ## Card account updaters ### How they work A card account updater is a service run by a card network. Issuers that participate report changes to their cards (new number, new expiry date, closed account), and merchants or their payment providers can receive those changes for cards they keep on file. The main ones: - **Visa Account Updater (VAU).** Visa's [developer documentation](https://developer.visa.com/capabilities/vau) describes it as a way for issuers, acquirers and qualified merchants to exchange updated account information for recurring and card-on-file payments, covering card numbers, expiry dates, closed accounts and "contact cardholder" advices. - **Mastercard Automatic Billing Updater (ABU).** Mastercard's [developer documentation](https://developer.mastercard.com/automatic-billing-updater/documentation/) describes a repository of account lifecycle events: issuers tell ABU when an account is created, updated or closed. For a closed account, Mastercard's guidance is that the merchant should use another payment method for future transactions. ### What Stripe does You do not integrate with these services yourself. Stripe's [cards overview](https://docs.stripe.com/payments/cards/overview) explains that Stripe automatically attempts to update saved card details when a customer receives a new card, using the networks' updater programs. Key points from Stripe's docs: - **Coverage depends on the issuer** and varies by country; it is strongest in the US. - **You cannot know in advance** which cards will be updated. - **You can see updates as they happen.** Stripe sends the `payment_method.automatically_updated` webhook with the new expiry date and last four digits. If the number changed, the card's fingerprint changes too. Stripe has also announced [expanded network token and card account updater coverage](https://stripe.com/newsroom/news/network-tokens-card-account-updater), including real-time updates in some cases. Check the announcement for the current scope in your markets. ## Network tokens ### How they work A network token is a substitute for the card number, issued by the card network (for example through the Visa Token Service), and tied to a specific merchant or payment provider. Instead of charging the raw card number, the payment provider charges the token. The useful property for subscriptions: the token is linked to the cardholder's account at the network, not to one physical card. When the issuer replaces the card, the network can update what sits behind the token. Visa's [token service documentation](https://developer.visa.com/capabilities/token-service-provisioning) describes how issuers manage a token's lifecycle (activate, suspend, resume, delete), and how Visa can pull updated card data from VAU to keep tokens current when the underlying card number or expiry date changes. ### What Stripe does Stripe's [guide to network tokens](https://stripe.com/guides/understanding-benefits-of-network-tokens) explains that Stripe tokenizes saved cards with the major networks where available, and decides for each payment whether to use the network token or the card number. If a payment on the network token fails, Stripe can retry it with the card number. Stripe's guide also notes two trade-offs: using a network token often requires fetching a one-time cryptogram from the network, which can add latency, and some networks charge fees related to token use. For most subscription businesses, none of this requires code. It is part of how Stripe processes saved cards. ## Updaters vs tokens | | Card account updater | Network token | |---|---|---| | What it is | A feed of card changes from issuers | A substitute card number issued by the network | | How the new details arrive | Stripe receives the update and changes the saved card | The network updates what the token points to | | Visible to you | Yes, `payment_method.automatically_updated` webhook | Mostly not; the card keeps working | | Depends on | Issuer participation, country | Network and issuer support | | Covers expired and replaced cards | Yes, where the issuer reports them | Yes, where supported | | Covers closed accounts | Can report the closure, so you know to ask for a new card | The token stops working | In practice they overlap, and Stripe combines them. You do not choose between them. ## What they do not fix This is the important part. Updaters and tokens solve one problem, stale card details, and only where issuers participate. They do nothing for the rest: | Failure | Fixed by updaters or tokens? | What does fix it | |---|---|---| | Card expired, issuer sent the new expiry | Yes | Nothing else needed | | Card replaced, issuer sent the new number | Yes | Nothing else needed | | Card expired, issuer does not participate | No | Pre-expiry email, card update page | | Account closed | No (at best, you learn about it) | Ask for a new payment method | | `insufficient_funds` | No | Retry at a better time; email | | Generic decline, bank block | No | Retry; email; customer calls the bank | | `authentication_required` | No | Customer confirms the payment | | Customer switched banks entirely | No | Ask for a new card | | Customer removed the card on purpose | No | Talk to the customer | That last row deserves attention. When a customer removes their saved card before a renewal, it is often a sign they intend to leave or dispute the next charge. It is a churn signal, not a payment problem, and it should be handled as one. ## What to do on your side Even with good coverage, you need a process for the cards that are not updated. The full approach is in [expiring cards](/blog/expiring-cards/); in short: ### 1. Listen to the updates Subscribe to `payment_method.automatically_updated`. Log each update (old expiry, new expiry, whether the number changed). It tells you how much of your base the networks are covering, and it lets you cancel any "your card is expiring" email you were about to send. ### 2. Find cards that will not be updated in time Before each renewal, check whether the card on file expires before the renewal date. If it does, and no update has arrived by a week or two before the renewal, email the customer. ### 3. Watch for closures and removals A closure report or a removed card means the next charge will fail. Ask for a new payment method right away, instead of waiting for the renewal to fail. ### 4. Keep dunning for the rest Most failed payments are not about stale card details. Retries and clear [dunning emails](/blog/dunning-email-templates/) still do most of the recovery work. See [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). ### 5. Prefer payment methods that last Some payment methods are better suited to recurring billing than others. Prepaid and virtual cards, for example, carry their own renewal risks, which updaters and tokens do not address. See [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ## Measuring coverage Track these monthly: - **Automatic updates received**: count of `payment_method.automatically_updated` events, split by "expiry only" and "new number". - **Expiring cards not updated**: cards with an expiry before their next renewal and no update by a set date. - **`expired_card` failures**: how many renewals still fail with an expired card. If this is high, your pre-expiry emails need work. - **Share by card country and brand**: coverage varies, so a high failure rate in one country may point to issuer participation rather than your process. ## Checklist - [ ] `payment_method.automatically_updated` is logged. - [ ] Pre-expiry emails are skipped for cards that were already updated. - [ ] Cards expiring before the next renewal are flagged. - [ ] Removed cards and closed accounts trigger an immediate request for a new payment method. - [ ] Failures are reported by decline code, so you can see what updaters do not cover. - [ ] Dunning handles everything else. ## How NoChurn helps NoChurn works alongside Stripe's updaters and tokens and covers what they leave. It flags customers who remove their card before renewal, raising their churn score so you can reach them before the payment fails. When a renewal fails, it reads the decline code, retries soft declines at better times, and sends AI-written recovery emails, reviewed before sending, with a hosted card update page. Card data stays with Stripe; NoChurn only sees details like brand, last four digits, expiry and funding type. It connects to Stripe in one click, and pricing depends only on MRR. See [failed payments](/#dunning), [the churn score](/#score) and [pricing](/pricing/). --- # Pause vs discount vs downgrade: choosing the right retention offer Source: https://www.nochurn.sh/blog/pause-vs-discount-retention-offers/ Most SaaS cancel flows reach for a discount first. It's the easiest offer to build, and it feels generous. But a discount only solves one problem, price, and it can create others: lower margin, customers who learn that cancelling gets them a better deal, and saves that quietly fall apart when the discount ends. There are four common retention offers: a **pause**, a **discount**, a **downgrade** and a **call**. Each fits a different reason for leaving. This guide covers when to use each, what can go wrong, and how to test whether an offer works. ## The four offers at a glance | Offer | Solves | Best for | Main risk | Cost to you | |---|---|---|---|---| | Pause | Temporary lack of need | Seasonal use, project gaps, budget freezes | Pause turns into silent churn | Lost revenue during the pause | | Discount | Price | Customers who value the product but feel it costs too much | Discount addiction, margin erosion | The discount amount | | Downgrade | Price, over-buying | Customers using a fraction of their plan | Permanent lower revenue | Difference between plans | | Call | Confusion, missing features, setup trouble | Higher-value accounts, complex products | Staff time; friction if forced | Team hours | The rule underneath the table: **match the offer to the reason**. A discount doesn't help someone who isn't using the product. A pause doesn't help someone who found it too expensive. Your [cancel flow](/blog/cancel-flow-best-practices/) should ask the reason first and then show the one offer that fits. ## Pause ### When it fits A pause is the right offer when the need is real but temporary: - "I'm not using it enough right now." - "Our project ended; the next one starts in a few months." - "We're freezing spend this quarter." - Seasonal businesses (tax, events, education). The appeal for the customer is that nothing is lost: settings, data and history stay, and billing stops. For you, a paused customer is far easier to bring back than a cancelled one, because restarting needs no new decision. ### Risks - **Pause as delayed churn.** Some customers will pause and never return. Track what share of paused customers resume and stay. - **Endless pauses.** Cap the duration (for example one to three months) and the number of pauses per year. - **Surprise charges at resume.** Remind customers by email before billing restarts. An unexpected charge after a pause is a classic source of refunds and disputes. ### How it works in Stripe Stripe lets you stop collecting payment on a subscription with `pause_collection`, choosing what happens to invoices during the pause (keep them as drafts, mark them uncollectible, or void them) and optionally a date to resume ([Stripe docs: pause subscriptions](https://docs.stripe.com/billing/subscriptions/pause)). Note that Stripe's customer portal does not offer a pause option to customers ([Stripe support](https://support.stripe.com/questions/billing-customer-portal)), so a pause offer needs your own flow or a dedicated tool. You also need to decide what "paused" means in your product: read-only access, no access, or full access. ## Discount ### When it fits A discount fits when the customer says the price is the problem **and** they are getting value. Signs that a discount may work: - They use the product regularly. - They chose "too expensive" rather than "not using it." - They're on a plan that matches their usage (otherwise, downgrade first). ### Risks - **Discount addiction.** If every cancellation attempt produces a discount, some customers will learn to cancel every few months to get a lower price. Limit retention discounts to once per customer, or once per year. Stripe's own retention rules, for instance, restrict retention discount coupons to a single use per customer ([Stripe docs](https://docs.stripe.com/billing/retention/rules)). - **Margin.** A 30% discount on a customer who would have stayed anyway is pure lost revenue. You only know how many would have stayed with a holdout test (see below). - **The cliff.** When a three-month discount ends, the customer faces the original price again, often with the same objection. Measure retention after the discount period, not just at acceptance. - **Fairness.** Long-term customers paying full price may notice that leavers pay less. Keep retention discounts modest and time-limited. ### Designing a discount offer - **Time-limit it.** "40% off your next 3 months" is easier to justify than a permanent discount. In Stripe, coupons can last once, for a set number of months, or forever ([Stripe docs: coupons](https://docs.stripe.com/billing/subscriptions/coupons)). - **State the full terms.** "Then $49/month from March" in the same sentence. - **Pick a number you can afford.** Calculate the cost before launching: discount percent times monthly price times months. ## Downgrade ### When it fits A downgrade fits when the customer is paying for more than they use: - Seats they no longer fill. - Usage limits well above their actual usage. - Features on a higher tier they never touched. For these customers, a downgrade is often a better answer than a discount: the price drop is permanent and honest, and the customer stays on a plan that matches their needs, which makes them less likely to leave later. ### Risks - **Lower revenue for good.** Unlike a discount, a downgrade doesn't expire. That's the point, but count it as reduced MRR, not saved MRR. - **Missing features.** Make sure the cheaper plan really covers what they use. Show them what they'd lose before they confirm. - **Plan design debt.** If many customers downgrade, your pricing may be wrong. Treat a high downgrade rate as a pricing signal. ### Showing the right plan Don't show a list of all plans. Recommend one plan based on actual usage ("You used 3 of your 10 seats last month; the 5-seat plan is $29/month") and make it one click. ## Call ### When it fits A call fits when the problem is information or effort, and the account is worth the time: - "It's missing a feature" (maybe it isn't, or there's a workaround). - "Too hard to set up or use." - "Switched to a competitor" (you may learn something, even if you don't save them). - High-value or annual accounts. ### Risks - **Forced calls are obstruction.** Offering a call is fine. Requiring one to cancel is not, and laws such as California's automatic renewal law restrict this for customers who signed up online. See our [click-to-cancel rules overview](/blog/click-to-cancel-rules/). - **Team time.** Limit call offers to accounts above an MRR threshold, or to reasons where a call can actually help. - **No-shows.** Let the cancellation go through or wait, at the customer's choice; never hold it hostage to a meeting. ## Choosing by reason | Cancel reason | First choice | Alternative | Usually avoid | |---|---|---|---| | Too expensive | Downgrade if over-buying, else discount | Annual billing if cheaper | Pause | | Not using it enough | Pause | Downgrade | Discount | | Missing a feature | Call or roadmap info | None | Discount | | Too hard to use | Call | Pause while they get help | Discount | | Switched to competitor | Call (to learn) | None | Large discount | | No longer needed | None | Pause, if it might come back | Any pushy offer | | Other | None | Read the free text | Guessing | ## How to test offers Retention offers are easy to fool yourself with. An offer that is "accepted" 30% of the time can still lose money if most of those customers would have stayed, or leave a month later. A few rules keep the test honest. ### Use a holdout group Randomly assign a share of customers who start the cancel flow to a group that sees no offer (just the reason question and confirmation). Compare the groups. The difference in retention is what the offer caused. Without a holdout, you are measuring acceptance, not impact. ### Measure at 30, 60 and 90 days Count a customer as saved only if they are still paying at each checkpoint. For discounts, include a checkpoint after the discount ends. ### Measure revenue, not just customers For each group, compare the revenue retained over 90 days (or longer), net of discounts and downgrades. An offer that saves more customers but less revenue may still be right, but you should know. ### Test one thing at a time, per reason Change one offer for one reason at a time. "Pause vs no offer for 'not using it'" is a clean test. Changing three offers at once tells you nothing about which one mattered. ### Wait for enough data Small cancel flows produce small numbers. If only a few dozen customers per month pick a given reason, a test can take months to tell you anything. Decide on the sample size before you start, and don't stop the test the first time the numbers look good; early results swing widely. Our guide to [predicting churn with your own data](/blog/predict-churn-with-customer-data/) covers sample size and confidence in more detail. ### Testing checklist - [ ] One reason, one offer change per test. - [ ] Random holdout with no offer. - [ ] Sample size decided in advance. - [ ] Saves measured at 30, 60 and 90 days. - [ ] Revenue measured net of discount. - [ ] Repeat offers limited per customer. - [ ] Results recorded, including tests that failed. ## How NoChurn helps In NoChurn's [cancel flows](/#cancel), each cancel reason maps to one offer: a discount through a Stripe coupon, a pause, a downgrade or a call. A one-click "Cancel now" button stays visible on every step. You can run the flow as a hosted modal or build your own interface on the headless API. Customers who leave anyway get [win-back emails](/#winback) at 30, 60 and 90 days, written from their reason. Every feature is on every plan, priced by MRR only ([pricing](/pricing/)). --- # How to find what predicts churn with your own customer data Source: https://www.nochurn.sh/blog/predict-churn-with-customer-data/ Every subscription business has a theory about why customers leave. "Customers from paid ads churn more." "Teams that don't invite a second user never stick." Some of these theories are right. Many are not, and the only way to tell is to check them against your own data. This guide covers what to collect, how to compare groups with cohort and relative-risk analysis, how to avoid the statistical traps that make random noise look like insight, and how to use AI to explain the results without letting it make up numbers. ## Step 1: decide what "churn" means Before any analysis, write down a definition. For example: - **Churned:** subscription cancelled or ended unpaid, and not reactivated within 30 days. - **Observation window:** the customer's first 90 days, or a calendar period. - **Who counts:** paying customers only, or trials too (analyze them separately; trial conversion is a different question). Separate **voluntary** churn (the customer cancelled) from **involuntary** churn (a payment failed and was never recovered). They have different causes. A prepaid card and a disappointed user are not the same problem. Our article on [involuntary churn](/blog/involuntary-churn/) covers the payment side. ## Step 2: collect the right attributes and events You want data that existed **before** the customer churned and that you could act on. A good starting set: | Field | Type | Example values | Why it matters | |---|---|---|---| | `signup_date` | Attribute | 2026-06-12 | Cohorts; seasonality | | `signup_source` | Attribute | `google_ads`, `facebook_ads`, `organic`, `referral` | Channel quality, not just volume | | `plan` | Attribute | `starter`, `team` | Fit between plan and need | | `seats` | Attribute | 1, 5, 20 | Single-seat accounts often behave differently | | `company_size` / `country` / `industry` | Attribute | `11-50`, `DE`, `agency` | Segment fit | | `trial_length_days` | Attribute | 7, 14 | Whether longer trials help | | `coupon_at_signup` | Attribute | `LAUNCH50`, none | Discount-acquired customers | | `payment_method` | Attribute | `card_credit`, `card_prepaid`, `sepa`, `link` | Involuntary churn risk | | `activated_at` | Event / date | 2026-06-14 | Did they reach the first value moment? | | `last_active_at` | Attribute | 2026-09-30 | Recency of use | | `key_feature_used` | Event count | `reports_created: 4` | Depth of use | | `support_tickets` | Count | 0, 3 | Friction | | `nps_score` | Attribute | 0 to 10 | Stated satisfaction | Some notes on getting this right: - **Define activation concretely.** "Created a first project and invited one teammate within 7 days" is measurable. "Got value" isn't. - **Record values as of a point in time.** If you compare churned customers' `last_active_at` to active customers', the churned group will look inactive because they churned. That tells you nothing. Use a fixed point, such as activity in the first 14 days. - **Keep categories coarse.** Twenty signup sources with three customers each can't be analyzed. Group them (paid search, paid social, organic, referral, other). - **Payment method data from Stripe.** Card objects in Stripe include a `funding` field (credit, debit, prepaid or unknown) ([Stripe API reference](https://docs.stripe.com/api/payment_methods/object)), which you can use without handling card numbers. - **Mind privacy.** Collect what you need, document why, and follow your privacy policy and local law. ## Step 3: build cohorts and compare churn rates The simplest useful analysis compares churn rates between groups that differ in one attribute. Take everyone who signed up in a period long enough for churn to show up (for example, signed up in Q1, observed for 90 days). For each value of an attribute, count customers and churned customers. **Illustrative example (not real data):** | Signup source | Customers | Churned in 90 days | Churn rate | |---|---|---|---| | Organic | 400 | 60 | 15% | | Paid social | 200 | 50 | 25% | | Referral | 100 | 10 | 10% | ### Relative risk Relative risk (RR) compares each group's churn rate to a baseline. Using organic as the baseline: - Paid social: 25% / 15% = **RR 1.67**. Customers from paid social churned about 1.7 times as often. - Referral: 10% / 15% = **RR 0.67**. Referral customers churned about a third less. Relative risk is easy to explain to anyone in the company, which is its main advantage over more complex models. See [relative risk](https://en.wikipedia.org/wiki/Relative_risk) for the formal definition. ## Step 4: check whether the difference is real A difference in a table is not automatically a finding. With small groups, chance alone produces large differences. ### Sample size Look at the counts, not just the percentages. If paid social had 20 customers and 5 churned, its 25% rate could easily be 10% or 45% with another month of signups. A practical rule: be skeptical of any group with fewer than a few dozen customers or fewer than about ten churn events, and say so in the report. ### Confidence intervals Report a range, not just a number. A 95% confidence interval for a relative risk tells you the range of values consistent with your data. With the illustrative table above, the interval for paid social comes out at roughly 1.2 to 2.3, so the higher risk is fairly clear. If it's 0.8 to 3.4, you don't know whether paid social is worse at all. The standard method uses the log of the relative risk; most statistics libraries compute it for you. A quick version in Python, for one comparison: ```python def relative_risk(a_churn, a_total, b_churn, b_total, z=1.96): rr = (a_churn / a_total) / (b_churn / b_total) se = math.sqrt(1/a_churn - 1/a_total + 1/b_churn - 1/b_total) low = math.exp(math.log(rr) - z * se) high = math.exp(math.log(rr) + z * se) return rr, low, high # Paid social vs organic, illustrative numbers from the table above print(relative_risk(50, 200, 60, 400)) # about (1.67, 1.19, 2.33) ``` ### Multiple comparisons This is the trap most dashboards fall into. If you test 40 attributes at a 5% significance level, you should expect about 2 of them to look "significant" by pure chance, even if none of them matter. The more you slice, the more false findings you get. Ways to handle it: - **Decide on a short list of hypotheses first**, and treat everything else as exploration. - **Adjust for the number of tests.** The [Bonferroni correction](https://en.wikipedia.org/wiki/Bonferroni_correction) (divide your significance threshold by the number of tests) is simple and strict. The [Benjamini-Hochberg procedure](https://en.wikipedia.org/wiki/False_discovery_rate#Benjamini%E2%80%93Hochberg_procedure) controls the false discovery rate and is less conservative. - **Confirm on new data.** Find a pattern in Q1 signups, then check whether it holds for Q2. A finding that replicates is worth acting on. ## Step 5: correlation, not causation Even a solid, replicated relative risk tells you that an attribute goes together with churn. It doesn't tell you the attribute causes churn. Common ways this goes wrong: - **Confounding.** Paid social customers might churn more because they're mostly solo freelancers, and solo freelancers churn more regardless of channel. Check the relationship within segments (paid social vs organic, among single-seat accounts only). - **Reverse causation.** Customers who file many support tickets might churn more, or customers who are already failing to get value file more tickets. - **Selection.** Customers who chose the annual plan are already more committed. Annual billing may not cause retention; committed customers may choose annual billing. The way to establish cause is an experiment: change one thing for a random group and compare. For example, if activation looks like it predicts retention, test an onboarding change that increases activation for a random half of new signups and see whether retention follows. Our guide to [testing retention offers](/blog/pause-vs-discount-retention-offers/) covers the same holdout logic for cancel flow offers. ## Step 6: turn findings into actions | Finding (example) | Possible action | How to verify | |---|---|---| | Paid social signups churn more | Change targeting or landing page; compare cohorts | Next quarter's paid social cohort | | Single-seat accounts churn more | Prompt inviting a teammate during onboarding | A/B test the prompt | | Not activated by day 7 churns more | Day 3 and 5 nudges, setup help | A/B test the nudges | | Prepaid cards fail renewals more | Ask for a backup payment method, earlier reminders | Compare renewal failure rate | | Low NPS precedes cancellation | Follow up on low scores within a week | Compare churn for followed-up vs not | ## Using AI to explain results, safely Language models are good at turning a table of results into a clear summary and a list of ideas. They are bad at arithmetic and will produce plausible-looking numbers that are wrong. The safe split is: 1. **Compute every number in code.** Churn rates, relative risks, intervals, sample sizes and adjusted p-values come from a deterministic script or SQL query. 2. **Give the model only the computed results**, as structured data, and ask it to explain them. 3. **Forbid new numbers.** Instruct the model to use only figures present in the input, and check the output: every number in the summary should match a number in the results. 4. **Require caveats.** Ask it to flag small samples, wide intervals and that the findings are correlations. 5. **Keep a human in the loop** for anything that changes pricing, targeting or product. A short prompt structure that works: ```text You are given churn analysis results as JSON. Each row has an attribute, a value, customers, churned, relative_risk, ci_low, ci_high and adjusted_p. Explain the three strongest findings for a non-technical founder. Use only numbers that appear in the JSON. Mention sample size for each finding. Say these are correlations, not causes. Suggest one experiment per finding. ``` ## Checklist - [ ] Churn defined in writing, voluntary and involuntary separated. - [ ] Attributes recorded as of a fixed point in time. - [ ] Categories grouped so each has enough customers. - [ ] Relative risk with confidence intervals for each comparison. - [ ] Sample sizes shown next to every result. - [ ] Correction for multiple comparisons, or results confirmed on new data. - [ ] Confounders checked within segments. - [ ] AI summaries use only computed numbers. - [ ] Top findings turned into experiments. ## How NoChurn helps With NoChurn's [custom data](/#insights), you send any customer attribute or usage event through the API, in batches, by CSV or with the SDK. NoChurn computes the statistics in code (relative risk, sample size and confidence) to find which attributes go with churn, then uses AI to explain the results and suggest actions, labeled as correlation, not cause. The same data, along with payment method and signup source, feeds the [churn score](/#score) given to each customer at signup. See the [API reference](/docs/api/) and [pricing](/pricing/). --- # Prepaid and virtual cards: how to detect them and reduce churn risk Source: https://www.nochurn.sh/blog/prepaid-virtual-cards-churn/ Some cards are designed to work once, or only up to a set amount. That is a feature for the cardholder: it protects them from unwanted charges and forgotten trials. For a subscription business, it means the first payment succeeds and the renewal may not. This article covers what prepaid and virtual cards are, what Stripe actually tells you about a card, why these cards carry more renewal risk, and what you can reasonably do at signup without turning away good customers. ## The card types, briefly | Type | What it is | Why it matters for renewals | |---|---|---| | Prepaid card | Loaded with a balance in advance | Renewal fails if the balance is not topped up | | Single-use virtual card | A card number that works for one transaction | Designed to decline the next charge | | Merchant-locked virtual card | A number that only works with one merchant | Can renew fine, but the customer can pause or close it at any time | | Virtual card from a bank or neobank | A digital card linked to a regular account | Behaves mostly like a normal card | | Regular debit or credit card | A physical or digital bank card | Standard renewal behavior | Services such as [Privacy.com](https://privacy.com/blog/virtual-card-companies) describe single-use cards that close after the first transaction, merchant-locked cards, spending limits, and the ability to pause or close a card at any time. People use them precisely to control recurring charges. That is legitimate, and worth respecting in how you design your signup and billing. ## What Stripe tells you about a card ### The `funding` field Every card PaymentMethod on Stripe has a `card.funding` field. According to the [Stripe API reference](https://docs.stripe.com/api/payment_methods/object), its possible values are `credit`, `debit`, `prepaid` and `unknown`. You get it without asking the customer anything. You can read it right after the customer adds a card: ```json { "id": "pm_123", "type": "card", "card": { "brand": "visa", "country": "US", "funding": "prepaid", "exp_month": 8, "exp_year": 2028, "last4": "4242", "fingerprint": "Xt5EWLLDS7FJjR1c" } } ``` This is an illustrative, shortened object. Field values are made up. A few things to keep in mind: - `unknown` means the network did not say. Do not treat it as prepaid. - The value depends on the card data Stripe receives. Treat it as a strong hint, not a guarantee. - The same field is available as `:card_funding:` in [Stripe Radar rules](https://docs.stripe.com/radar/rules/supported-attributes), so you can review or block prepaid cards at payment time if you use Radar. ### What Stripe does not tell you As far as Stripe's public API reference shows, there is no field that marks a card as virtual or single-use. A single-use virtual card may simply appear as a `credit` or `debit` card from its issuer. That means you cannot reliably detect disposable virtual cards from card data alone. What you can use instead: - **Behavior over time.** A card that is paused or closed shortly after the first charge will show up as declines on renewal. You learn from your own history which issuers and card types behave this way. - **The card `fingerprint`.** Stripe gives each card number a fingerprint, which you can use to check whether two customers are using the same card number. If the same fingerprint signs up for several free trials, you have a pattern worth looking at. A disposable card will produce a new fingerprint each time, which is also a pattern: many short-lived cards with no repeat use. - **Card removal.** A customer who deletes their only card soon before renewal is a signal, whatever the card type. ## Why risk is higher The reasons are mechanical, not moral: 1. **Prepaid balances run out.** If the card holds exactly the first payment, the renewal declines with insufficient funds. 2. **Single-use cards stop working by design.** The next charge is declined no matter when you retry. 3. **Customers can pause or close virtual cards at will.** That makes canceling as easy as flipping a switch, without going through your cancel flow, so you never learn why they left. 4. **Retries do not help much.** Retries work for temporary problems. A closed card is not temporary. None of this means people using these cards are bad customers. Many are careful with money and simply want control. Some will happily keep paying if the value is clear and they trust you not to make cancellation hard. We have not found a reliable public statistic for how much more often prepaid or virtual cards churn, and we would rather not make one up. Measure it in your own data: compare renewal failure rates by `card.funding` value over a few months. ## What to do at signup ### 1. Measure before you act Store the funding type (and the payment method type: card, wallet, bank debit) for every new subscription. After two or three renewal cycles, compare: | Payment method group | New subscriptions | First renewal failed | Churned within 90 days | |---|---|---|---| | Credit | [your data] | [your data] | [your data] | | Debit | [your data] | [your data] | [your data] | | Prepaid | [your data] | [your data] | [your data] | | Unknown | [your data] | [your data] | [your data] | | Wallets / bank debit | [your data] | [your data] | [your data] | If prepaid cards do not behave differently for you, there is nothing to fix. ### 2. Do not block by default Blocking all prepaid cards turns away customers who would have paid, including people who do not have access to a credit card. Start with softer measures and only block if your data shows a clear problem, for example abuse of free trials. ### 3. Match the trial to the risk The highest-risk combination is usually a free trial plus a card that will not work on day 31. Options: - Ask for payment up front, with a refund window, instead of a free trial for higher-risk signups. - Offer a shorter trial for prepaid cards. - Offer the trial without a card, and ask for payment at conversion, when the customer has seen the value. Whichever you choose, be transparent. Hidden rules feel unfair when customers notice them. ### 4. Offer better payment methods Some customers will happily use a wallet (Apple Pay, Google Pay, Stripe Link) or a bank debit such as SEPA Direct Debit if you offer it. Make these options visible at checkout. ### 5. Communicate before renewal For subscriptions on prepaid cards, a reminder a few days before renewal ("Your plan renews on [date] for [amount]") gives the customer time to top up or switch cards. It also builds trust, which is the opposite of what people using these cards expect. ### 6. Make cancellation honest People who use virtual cards to protect themselves from hard-to-cancel subscriptions will close the card if they cannot find the cancel button. A clear, one-click cancel option, ideally with a relevant offer first, keeps the conversation inside your product. See [cancel flow best practices](/blog/cancel-flow-best-practices/). ### 7. Use Radar rules carefully If you use Stripe Radar and see real abuse, rules on `:card_funding:` can send prepaid cards to manual review or block them for specific products such as free trials. Review the results regularly so you do not block legitimate customers. ## A signup checklist - [ ] `card.funding` and payment method type are stored for every new subscription. - [ ] Renewal failure and 90-day churn are compared by payment method group. - [ ] Trial rules are adjusted only where your data shows higher risk. - [ ] Wallets and bank debits are offered at checkout. - [ ] High-risk subscriptions get a reminder before the first renewal. - [ ] Cancellation is easy and visible. - [ ] Repeated fingerprints across free trials are reviewed. - [ ] Customers who remove their card before renewal are flagged. For the full failed payment process, see the [complete guide to recovering failed payments on Stripe](/blog/recover-failed-payments-stripe/) and [what involuntary churn is and how to reduce it](/blog/involuntary-churn/). ## How NoChurn helps NoChurn gives every new customer a churn score from 0 to 100 at signup. Payment method is one of the inputs: prepaid and disposable virtual cards start as high risk, neobank cards as medium, and Stripe Link, Apple Pay, Google Pay, bank cards and SEPA as low. Those levels are then learned from your own account's history, so the score reflects how your customers actually behave. Signup source and any custom data you send also feed into it. NoChurn also flags customers who remove their card before renewal and starts a save flow before the payment fails. It connects to Stripe in one click, and pricing depends only on MRR. See [the churn score](/#score), [custom data](/#insights) and [pricing](/pricing/). --- # How to recover failed payments on Stripe: a complete guide Source: https://www.nochurn.sh/blog/recover-failed-payments-stripe/ A failed subscription payment is not a lost customer yet. Most of the time the customer still wants the product; the card was declined for a reason they may not even know about. What happens in the next two weeks decides whether that invoice gets paid or the subscription quietly ends. This guide walks through the full recovery process on Stripe: reading decline codes, setting up retries, writing the emails, giving customers an easy way to update their card, and measuring what you actually recover. Everything Stripe-specific links to [Stripe's documentation](https://docs.stripe.com/billing/revenue-recovery) so you can check the current settings in your own account. ## Why failed payments matter more than they look Failed payments cause what is called involuntary churn: the customer did not choose to leave, the payment simply did not go through. [Recurly's churn benchmarks](https://recurly.com/research/churn-rate-benchmarks/) (accessed November 2026) put average monthly involuntary churn across industries at 1.25%, against 3.60% total churn. That is roughly a third of all churn, and it is the part you can fix without changing your product or your pricing. If you want the definitions and the math, see [what involuntary churn is and how to measure it](/blog/involuntary-churn/). ## Step 1: read the decline code Every failed card charge on Stripe comes with a decline code on the charge or PaymentIntent. The code tells you what kind of problem you have, and the right response depends on it. Stripe publishes the full list with a suggested next step for each in its [decline codes reference](https://docs.stripe.com/declines/codes). ### Soft declines: retrying can work A soft decline is temporary. The card is valid, but the issuer said no this time. Typical causes: - `insufficient_funds`: not enough money or credit available right now. - `generic_decline` or `do_not_honor`: the issuer declined without giving a reason. - `try_again_later` or `processing_error`: a temporary problem on the issuer or network side. - `card_velocity_exceeded`: the customer hit a spending or transaction limit. These are the declines where retry timing matters. A card that fails on the 28th of the month for insufficient funds may go through on the 1st. ### Hard declines: retrying alone will not work A hard decline means the card cannot be charged again as is. The customer needs to give you a new payment method. Stripe's [Smart Retries documentation](https://docs.stripe.com/billing/revenue-recovery/smart-retries) lists the hard decline codes it will not retry on its own: `incorrect_number`, `lost_card`, `pickup_card`, `stolen_card`, `revocation_of_authorization`, `revocation_of_all_authorizations`, `authentication_required`, `highest_risk_level` and `transaction_not_allowed`. For these, scheduled retries still appear on the invoice, but a payment only runs once a new payment method is attached. Expired cards (`expired_card`) also need customer action unless the card network sends Stripe the new details. We cover that case in [the guide to expiring cards](/blog/expiring-cards/). ### A quick triage table | Decline type | Example codes | What to do | |---|---|---| | Temporary, funds | `insufficient_funds` | Retry at a better time; email the customer | | Temporary, unclear | `generic_decline`, `do_not_honor` | Retry a few times; email; suggest contacting the bank | | Needs authentication | `authentication_required` | Send a link so the customer can confirm the payment | | Card unusable | `lost_card`, `stolen_card`, `incorrect_number` | Do not retry; ask for a new card right away | | Card expired | `expired_card` | Ask for a new card; check whether the card was auto-updated | One caution from Stripe's own docs: for codes such as `fraudulent` or `lost_card`, do not tell the customer the specific reason. Show a generic "your payment was declined" message instead. ## Step 2: set up retries Stripe Billing can retry failed invoice payments automatically. You configure this in the Dashboard under the revenue recovery settings. You have two options, according to [Stripe's docs](https://docs.stripe.com/billing/revenue-recovery/smart-retries): - **Smart Retries**: Stripe's model picks the retry times using time-dependent, dynamic signals. Stripe's recommended default is 8 tries within 2 weeks, and you can choose a longer or shorter window. - **A custom schedule**: up to three retries, each a set number of days after the previous attempt. You also choose what happens to the subscription when the last retry fails: cancel it, mark it unpaid, or leave it past due. For most businesses, Smart Retries is the right starting point. The cases where a custom schedule makes sense (payday-heavy customer bases, B2B invoices, very short windows) are covered in [how Stripe Smart Retries work](/blog/stripe-smart-retries/). ### Retry checklist - Retries are enabled for subscription invoices with automatic collection. - The retry window matches your billing cycle (a 2-month window on a monthly plan means the next invoice arrives before the last one is settled). - The end-of-retries action is a deliberate choice, not the default you never looked at. - Hard declines trigger an immediate email, not a wait for the next retry. ## Step 3: email the customer Retries recover what the bank lets through. Emails recover the rest: the expired cards, the cards that were replaced, the customers who need to move money or call their bank. Stripe can send basic emails for you. In the [customer emails settings](https://docs.stripe.com/billing/revenue-recovery/customer-emails), you can turn on emails when card payments fail, emails about expiring cards and reminders about upcoming renewals. These are a reasonable baseline. Their limits are that the copy is generic and they are not timed around your retry schedule or the decline reason. A solid dunning sequence usually looks like this: | When | Goal | Tone | |---|---|---| | Day 0 (first failure) | Tell the customer, give the update link | Neutral, short, no blame | | Day 3 | Remind, explain what happens next | Helpful | | Day 7 | Make the deadline clear | Direct | | Day 14 (last retry) | Final notice before access changes | Clear and respectful | Good dunning emails share a few traits: 1. **One action.** A single button to the card update page. No extra links. 2. **Plain sender and subject.** From a person or your product name, with a subject that says what happened ("Your payment for Acme didn't go through"). 3. **The facts.** Amount, plan, card brand and last four digits, and the date service changes. 4. **No blame.** Cards fail for reasons outside the customer's control. 5. **A real reply-to address.** Some customers will answer with a question. Someone should read it. We wrote ready-to-use templates for each step in [dunning email templates for days 0, 3, 7 and 14](/blog/dunning-email-templates/). ## Step 4: make updating the card effortless The email gets the click. The card update page gets the payment. Every extra step on that page loses people. On Stripe you have three common options: - **The hosted invoice page.** Each invoice has a Stripe-hosted page where the customer can pay with a new card. - **The [customer portal](https://docs.stripe.com/customer-management).** A Stripe-hosted page where customers manage payment methods, invoices and subscriptions. - **Your own page** built with Stripe Elements or Checkout in setup mode. Whichever you use, check these: - The link logs the customer in or works without a password. Asking a customer to remember a password to fix a failed payment is a common drop-off point. - The page works well on a phone. Many dunning emails are opened on mobile. - Wallets such as Apple Pay, Google Pay and Stripe Link are offered where available, so the customer does not have to type a card number. - After the update, the open invoice is paid right away instead of waiting for the next retry. - The page confirms success in plain words ("You're all set. We charged $49 to your Visa ending 4242."). ## Step 5: handle authentication Some failures are not declines at all. In regions with Strong Customer Authentication, such as the EU and UK, the bank may require the customer to confirm a payment with 3D Secure. Stripe returns `authentication_required` in that case. The fix is to send the customer a link where they can complete the authentication. Stripe's customer email settings include an option for this. Make sure it is on if you sell to European customers. ## Step 6: measure recovery properly You cannot improve what you do not measure, and recovery numbers are easy to get wrong. Track these: | Metric | Formula | Notes | |---|---|---| | Failed payment rate | Failed invoices / invoices attempted | Per month; split by first attempt only | | Recovery rate (count) | Invoices recovered / invoices that failed | Use a fixed window, e.g. within 30 days | | Recovery rate (revenue) | Amount recovered / amount that failed | Weighs larger plans more | | Time to recover | Days from first failure to payment | Shorter means less disruption for customers | | Recovered by channel | Retries vs email click vs support reply | Tells you where to invest | A few rules keep the numbers honest: - **Use cohorts.** Count failures in a given month and track whether those specific invoices were paid, not "payments recovered this month" against "failures this month". - **Exclude what would have been paid anyway.** If you compare tools or settings, run them on comparable groups of failures. - **Separate hard and soft declines.** A rise in recovery may just mean fewer hard declines that month. - **Watch what happens next.** A customer who pays after a dunning email and cancels the following week was not truly saved. ### Example Here is a hypothetical example, not real data. A company bills 1,000 subscription invoices in March. 60 fail on the first attempt, for a total of $3,000. Within 30 days, 25 are paid after retries alone and 14 after the customer updated their card from an email. The other 21 end in cancellation. - Failed payment rate: 60 / 1,000 = 6% - Recovery rate (count): 39 / 60 = 65% - If the recovered invoices total $1,900, recovery rate (revenue): $1,900 / $3,000 = 63% Those numbers tell this company that emails matter: more than a third of recovered invoices needed a customer action. ## Step 7: prevent the next failure The cheapest failed payment is the one that never happens. - **Turn on automatic card updates.** Stripe can update saved cards when the issuer sends new details (see [how cards work](https://docs.stripe.com/payments/cards/overview)). - **Email before cards expire**, not after the renewal fails. - **Look at payment methods at signup.** Prepaid and single-use virtual cards behave differently from bank cards. See [prepaid and virtual cards and churn](/blog/prepaid-virtual-cards-churn/). - **Offer stable payment methods.** Bank debits such as SEPA Direct Debit or wallets can be a better fit for some customers. ## Full recovery checklist - [ ] Decline codes are logged and grouped into soft, hard and authentication. - [ ] Smart Retries or a custom schedule is enabled, with a window that fits your billing cycle. - [ ] The end-of-retries action is set on purpose. - [ ] Customers get an email on the first failure, with one clear link. - [ ] Hard declines trigger an immediate request for a new card. - [ ] Authentication links are sent for `authentication_required`. - [ ] The card update page works on mobile, without a password, with wallets. - [ ] Replies to dunning emails reach a person. - [ ] Recovery is measured by cohort, by count and by revenue. - [ ] Expiring cards are handled before renewal. ## How NoChurn helps NoChurn connects to Stripe in one click and runs the recovery steps above. It retries failed payments at times based on likely paydays and the customer's local time, or you can keep Stripe Smart Retries. It sends recovery emails on day 0, 3, 7 and 14 by default, written by AI in the customer's language and reviewed before sending. Each email links to a hosted card update page; card data stays with Stripe and NoChurn never sees card numbers. Replies to those emails are read, sorted and answered, or sent to your team. Pricing depends only on your MRR, never on a share of recovered revenue, and it is free until $300 MRR. See [how failed payment recovery works](/#dunning) or [pricing](/pricing/). --- # SCA and 3D Secure on subscription renewals: handling authentication_required Source: https://www.nochurn.sh/blog/sca-authentication-required-renewals/ Most failed renewals are about money or cards: not enough funds, an expired card, a block at the bank. One kind is different. The card is fine and the money is there, but the bank wants the customer to confirm the payment. On Stripe, that shows up as the decline code `authentication_required`, or as an invoice waiting for customer action. No amount of retrying fixes it. The customer has to come back and approve the payment. This guide explains why it happens, what Stripe does for you, and how to get the customer through it quickly. It is based on Stripe's documentation and the EU rules behind it (sources accessed November 2026). **This is not legal advice.** Payment regulation is complex; check your setup with Stripe and, where needed, a specialist. ## Why renewals need authentication at all ### Strong Customer Authentication in brief Strong Customer Authentication (SCA) comes from the EU's second Payment Services Directive (PSD2). It requires payers to authenticate electronic payments with two of three factors: something they know, something they have, something they are. For cards, the usual way to do this online is 3D Secure, where the bank shows a confirmation step (a code, an app approval, a fingerprint). According to Stripe's [SCA guide](https://stripe.com/guides/strong-customer-authentication) and [help center](https://support.stripe.com/topics/strong-customer-authentication), SCA applies when both the business's payment provider and the cardholder's bank are in the European Economic Area. Stripe's [exemptions page](https://docs.stripe.com/payments/3d-secure/strong-customer-authentication-exemptions) also covers the UK and Switzerland. Payments where one side is outside the region ("one leg out") are out of scope, though banks may still ask for authentication. ### Recurring payments and merchant-initiated transactions A subscription renewal happens when the customer is not there. The rules accommodate this: - The EU's technical standards, [Commission Delegated Regulation (EU) 2018/389](https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX%3A32018R0389), require SCA when a payer creates, amends or first initiates a series of recurring transactions with the same amount and the same payee. Later payments in the series can be exempt (Article 14). - Card payments that the merchant initiates under an agreement with the customer are treated as merchant-initiated transactions (MITs). Stripe's [exemptions page](https://docs.stripe.com/payments/3d-secure/strong-customer-authentication-exemptions) explains that the card should be authenticated when it is saved, and that you need the customer's agreement (a mandate) to charge it later. Marking a payment as an MIT works much like requesting an exemption. So, in principle, one authentication at signup covers future renewals. ### Why it still fails In practice, the issuing bank has the final say. It can decline an exemption or an MIT and ask for authentication anyway. Common situations include a change in amount (an upgrade, a price increase, usage charges), a card that was saved without authentication, or simply the bank's own risk assessment. When that happens on an off-session renewal, nobody is there to complete 3D Secure, and the payment fails. Stripe's support article on [authentication_required declines](https://support.stripe.com/questions/authenticated-payment-declined-with-an-authentication-required-decline-code) adds one edge case: issuers sometimes return `authentication_required` even on payments that already passed 3D Secure. In that case, the customer needs to contact their bank. ## What Stripe does for subscriptions If you use Stripe Billing, Stripe handles most of the mechanics: - **Renewals are marked as off-session automatically.** Stripe's [on-session vs off-session article](https://support.stripe.com/questions/what-is-the-difference-between-on-session-and-off-session-and-why-is-it-important) says this flag is set for you on Billing renewals. - **Saved cards become MITs.** Per Stripe's [SCA readiness page](https://docs.stripe.com/strong-customer-authentication/sca-enforcement), when a card is saved through the Payment Intents or Setup Intents APIs, later off-session payments are flagged as merchant-initiated. - **The invoice tells you when action is needed.** Stripe sends the [`invoice.payment_action_required`](https://docs.stripe.com/api/events/types) event when an invoice payment needs further customer action. Stripe's [subscription webhooks guide](https://docs.stripe.com/billing/subscriptions/webhooks) says your app must then notify the customer. - **The hosted invoice page handles 3D Secure.** The [hosted invoice page](https://docs.stripe.com/invoicing/hosted-invoice-page) can run the authentication flow without extra work on your side. - **Stripe can send the email.** In the [customer emails settings](https://docs.stripe.com/billing/revenue-recovery/customer-emails), you can have Stripe send a link for customers to confirm payments when their bank requires it. On retries, note that Stripe's [Smart Retries page](https://docs.stripe.com/billing/revenue-recovery/smart-retries) lists `authentication_required` among the hard decline codes: Stripe will not retry it automatically without customer action. ## The two ways it shows up | Signal | What it means | What to do | |---|---|---| | `invoice.payment_action_required`, PaymentIntent in `requires_action` | The bank wants 3D Secure for this payment | Send the customer the hosted invoice link (or your own page) to confirm | | Decline code `authentication_required` on `invoice.payment_failed` | The issuer declined and asked for authentication | Same: bring the customer back on-session to confirm or re-enter the card | Stripe's [support article on off-session SCA failures](https://support.stripe.com/questions/manual-confirmation-for-off-session-payments-requiring-strong-customer-authentication-(sca)) notes that a failed off-session PaymentIntent can end up in `requires_payment_method` rather than `requires_action`. If you build your own confirmation page, handle both states: either confirm the existing payment method with 3D Secure, or collect a payment method again. ## Getting the customer to confirm The customer did nothing wrong, and they often do not know what "authentication" means. The message should be short, calm and specific. ### What the email should say - **Subject:** "Please confirm your [Product] payment" - **Why:** "Your bank asks you to confirm this payment. This is a standard security check, not a problem with your card." - **What:** the amount, the plan, the date. - **How:** one button, "Confirm payment", leading straight to the confirmation page. - **When:** "Your subscription stays active while you confirm. If we can't confirm by [date], it will be paused." Avoid "your payment failed" in the subject. It is not quite true, and it makes customers think they need a new card. ### Timing Send the first message as soon as the event arrives. Unlike soft declines, waiting does not help: the bank will not change its mind on its own. A short follow-up after two or three days, then a final notice before the end of your grace period, is enough. Our [dunning email templates](/blog/dunning-email-templates/) include an authentication variant. ### The confirmation page - Works on mobile without logging in (a signed link). - Shows the amount and the product before the bank step. - Opens the bank's 3D Secure step directly. - Offers "use another card" as a fallback, for customers whose bank keeps refusing. - Confirms success clearly, and stops all further emails on `invoice.paid`. ## Reducing authentication failures You cannot remove them entirely, because the bank decides. You can make them rarer. ### 1. Authenticate when the card is saved Collect the card with a SetupIntent (or the first PaymentIntent) and `setup_future_usage` set for off-session use, so that the card is authenticated with the mandate in place. Stripe's [SetupIntents docs](https://docs.stripe.com/payments/setup-intents) cover this. Stripe Checkout and the Payment Element do it for you on subscription signup. ### 2. Re-collect when you change the deal Upgrades, price changes and new add-ons change the amount. Where possible, make the customer confirm the change while they are in your app, so any authentication happens on-session rather than at 3 a.m. on renewal day. ### 3. Be careful with free trials If a trial starts without a charge, make sure the card is still saved through a SetupIntent with authentication. Otherwise the first real charge, after the trial, is the first time the bank sees the mandate. We cover trials in [trial-to-paid conversion](/blog/trial-to-paid-conversion/). ### 4. Handle India separately India has its own recurring payment rules. Stripe's [India recurring payments page](https://docs.stripe.com/india-recurring-payments) explains that cards need an e-mandate registered with additional factor authentication, that customers get a pre-debit notification at least 24 hours before each charge, and that recurring charges above INR 15,000 need authentication every time. If you have Indian customers, read that page; it works differently from SCA. ## Measuring it Track authentication separately from other failures. It behaves differently and has its own fix. - **Authentication requests per month**, by card country. - **Confirmation rate**: invoices with an authentication request that were paid within your grace period. - **Time to confirm**: from the event to `invoice.paid`. - **Fallback rate**: customers who confirmed by switching to a new card instead. If the confirmation rate is low, look at the email first (subject, clarity, a single button), then at the page on mobile. ## Checklist - [ ] Cards are saved with off-session authentication at signup. - [ ] `invoice.payment_action_required` and `authentication_required` both trigger a confirmation email. - [ ] Stripe's "confirm payment" emails are on, or your own emails replace them (not both). - [ ] The confirmation page works on mobile without a password. - [ ] Price changes and upgrades are confirmed on-session where possible. - [ ] Emails stop as soon as the invoice is paid. - [ ] Authentication is reported as its own category. - [ ] Indian customers are handled under the e-mandate rules. ## How NoChurn helps NoChurn treats authentication requests as their own case. When a renewal needs confirmation, it skips useless retries and sends an AI-written recovery email, reviewed before sending and in the customer's language, explaining that the bank wants a quick confirmation, with a link to confirm the payment and a hosted card update page as a fallback. Card data stays with Stripe. It connects to Stripe in one click, or works by API with your own billing. Pricing depends only on MRR, never on recovered revenue. See [failed payments](/#dunning) and [pricing](/pricing/). --- # Stripe customer portal cancellation: what it does and when it's enough Source: https://www.nochurn.sh/blog/stripe-customer-portal-cancellation/ If you bill with Stripe, you already have a cancel flow available: the [Stripe customer portal](https://docs.stripe.com/customer-management). It's a Stripe-hosted page where customers can update payment methods, see invoices, change plans and cancel. You turn features on in the Dashboard, link customers to it, and Stripe handles the rest. For many products, that's enough. For others, the portal's cancellation step is too limited. This article covers what the portal offers as of November 2026, according to Stripe's docs, where it falls short, and how to decide. ## What the portal's cancellation page does Stripe documents the cancellation features on its [cancellation page guide](https://docs.stripe.com/customer-management/cancellation-page) and [portal configuration guide](https://docs.stripe.com/customer-management/configure-portal). In summary: ### Cancel immediately or at period end You choose whether a cancellation in the portal ends the subscription right away or at the end of the current billing period. With period-end cancellation, the customer keeps access until the period ends and can reactivate before then ([Stripe docs: cancel subscriptions](https://docs.stripe.com/billing/subscriptions/cancel)). ### Cancellation reasons You can ask customers why they're cancelling. The portal uses a predefined list of reasons, and you pick which ones to show: - It's too expensive - I need more features - I found an alternative - I no longer need it - Customer service was less than expected - Ease of use was less than expected - Quality was less than expected - Other reason (with optional free text) Responses appear on the subscription in the Dashboard, in Stripe Sigma, and in the `customer.subscription.updated` webhook, so you can pipe them into your own analytics. ### Retention coupon The classic portal setting lets you choose **one coupon** to offer customers who try to cancel. If they accept, the coupon is applied to the subscription and the cancellation is stopped. The same coupon is shown to everyone who reaches the cancellation page, whatever reason they give. ### Retention rules (private preview) Stripe has also documented [retention rules](https://docs.stripe.com/billing/retention/rules), in private preview at the time of writing. They replace the single retention coupon (turning them on disables it) and let you show a targeted offer based on conditions such as: - The cancellation reason selected - Months subscribed and total billing spend - Subscription status - Subscription or customer metadata - The price the customer is on Each rule branch offers either a **discount** (percentage or fixed amount on future billing cycles, limited to one use per customer for retention coupons) or a **downgrade**, not both. Stripe also provides a [retention performance](https://docs.stripe.com/billing/retention/performance) view with revenue saved, where customers drop out of the cancellation flow, and reasons selected; a subscription counts as saved if it stays active at least 7 days after the customer accepts an offer. Because it's a preview, availability and behavior can change. Check the current docs before relying on it. ### Portal limits worth knowing - **No pause option.** The portal doesn't let customers pause a subscription; pausing needs the API or Dashboard ([Stripe support](https://support.stripe.com/questions/billing-customer-portal)). - **Some subscriptions can be cancelled but not updated.** Per Stripe's configuration guide, subscriptions with multiple products, usage-based billing, trial offers or certain payment methods can't be changed in the portal, though they can be cancelled. Subscriptions with a pending update from a subscription schedule can't be updated or cancelled there. - **Stripe's design.** You can set branding (logo, colors, icon), but the layout and steps are Stripe's. - **Web only.** It's a hosted web page. In a mobile app, you open it in a browser view. ## Portal vs a dedicated cancel flow | Capability | Stripe portal (classic) | Stripe portal with retention rules (preview) | Dedicated cancel flow | |---|---|---|---| | Cancel at period end or immediately | Yes | Yes | Yes | | Reason question | Fixed list, choose which to show | Fixed list plus custom reasons | Any reasons, your wording | | Offer per reason | No, one coupon for all | Yes | Yes | | Discount offer | Yes (one coupon) | Yes | Yes | | Downgrade offer | No (plan switching is separate) | Yes | Yes | | Pause offer | No | No | Usually yes | | Call / talk-to-us offer | No | No | Usually yes | | Eligibility (e.g., no repeat discounts) | Not documented | Conditions on tenure, spend, metadata; one use per customer for coupons | Yes | | Your own design | Branding only | Branding only | Full control, or headless API | | Inside your app (iOS, Android, desktop) | Browser view | Browser view | Native, via API | | Win-back emails after cancel | No | No | Depends on tool | | Analytics | Reasons in Dashboard, Sigma, webhooks | Retention performance view | Depends on tool | | Extra cost | Included with Stripe Billing | Preview; check terms | Tool or build cost | For pricing and fees of Stripe Billing itself, see Stripe's pricing page; we don't reproduce numbers here because they vary by plan and region. ## When the built-in portal is enough The portal is a sensible choice when: - **You're early.** With a handful of cancellations a month, there isn't enough volume to test offers anyway. Turn on reasons, pick period-end cancellation, and read every answer. - **Your product is simple.** One or two plans, one obvious objection (usually price). A single retention coupon covers it. - **You're web-only.** Customers manage billing in a browser. - **You want minimal engineering.** The portal takes configuration, not code, beyond creating a portal session. - **You can use retention rules.** If you have access to the preview, it covers reason-based discounts and downgrades, which is the core of a good flow. Even with the portal, apply the basics: keep the cancel action easy to reach from your account settings, state offer terms clearly, and don't offer the same discount repeatedly. Our [cancel flow best practices](/blog/cancel-flow-best-practices/) apply whatever tool you use. ## When you need more A dedicated cancel flow starts to pay off when: - **Reasons call for different offers that the portal can't make**, especially a pause for "not using it enough" or a call for "missing a feature." See [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/). - **You need cancellation inside your app.** Mobile and desktop apps that want a native screen, not a browser redirect, need an API. - **The flow must match your product's design**, or follow a specific copy and accessibility standard. - **You want what happens after the cancel**: win-back emails timed to the reason, a holdout test, revenue-based reporting. - **You bill outside Stripe**, or across several billing systems. - **Compliance needs specific handling** for your markets, such as clear exit options on every step. See our [click-to-cancel rules overview](/blog/click-to-cancel-rules/). ## Setting up the portal well If you start with the portal, a quick setup checklist: - [ ] Cancellation enabled, set to cancel at period end (usually kinder than immediate). - [ ] Cancellation reasons enabled; choose the reasons you'll act on. - [ ] Retention coupon (or retention rules) set with a time-limited discount, terms stated in the coupon name. - [ ] Branding set: logo, colors, business name, links to your terms and privacy policy. - [ ] A clear "Manage billing" or "Cancel subscription" link in your app's settings that opens a portal session. - [ ] A `customer.subscription.updated` and `customer.subscription.deleted` webhook handler that records reasons and updates access. - [ ] A monthly review of reasons and free-text answers. ## How NoChurn helps NoChurn connects to Stripe in one click and adds what the portal leaves out. Its [cancel flows](/#cancel) map each cancel reason to one offer (a discount through a Stripe coupon, a pause, a downgrade or a call), with a one-click "Cancel now" button visible on every step. You can use the hosted modal with your themes, fonts, colors, logo and custom CSS, or the headless API for a fully custom flow on web, desktop, iOS and Android. Cancelled customers get [win-back emails](/#winback) at 30, 60 and 90 days based on their reason. If you don't bill with Stripe, the same features work through the REST API. NoChurn's price depends only on your MRR, with every feature on every plan ([pricing](/pricing/)). For a detailed comparison with Stripe's own tools, see [NoChurn vs Stripe Billing](/compare/stripe-billing/). --- # Stripe decline codes explained: what to do for each one Source: https://www.nochurn.sh/blog/stripe-decline-codes/ When a renewal fails on Stripe, the charge comes back with a short string such as `insufficient_funds` or `do_not_honor`. That string is the most useful piece of information you get about the failure. It tells you whether retrying can work, whether the customer has to do something, and what you are allowed to tell them. This guide goes through the decline codes that matter most for subscriptions, grouped by what you should do about them. It sticks to what Stripe documents in its [decline codes reference](https://docs.stripe.com/declines/codes) and [card declines guide](https://docs.stripe.com/declines/card) (both accessed November 2026), and says so when Stripe's own pages leave room for interpretation. ## Where the codes live A failed card payment on Stripe can carry several fields. They answer different questions: | Field | What it tells you | Where to find it | |---|---|---| | `decline_code` | Stripe's normalized reason for the issuer decline, if the issuer gave one | On the error, and on `last_payment_error` of the PaymentIntent | | `advice_code` | What to do next: retry, do not retry, or check the card data | On the error, alongside the decline code | | `network_decline_code` | The raw code from the card network | On the charge outcome | | `network_advice_code` | The network's own advice (for Mastercard, its Merchant Advice Codes) | On the charge outcome | Stripe [added the network advice and decline code fields](https://docs.stripe.com/changelog/acacia/2024-12-18/network-advice-code-network-decline-code) to the API in December 2024. Stripe's docs warn that the meaning of a `network_decline_code` differs between card networks, so always read it together with the card brand. For subscriptions, you will usually read these from the `invoice.payment_failed` webhook: fetch the invoice's PaymentIntent and look at `last_payment_error`. ### Advice codes come first The `advice_code` is the simplest signal, and Stripe's [card declines guide](https://docs.stripe.com/declines/card) documents three values: - **`try_again_later`**: the issuer declined, but you may retry. If repeated retries fail, the customer needs to contact their issuer. - **`do_not_try_again`**: do not use this card again for this transaction. Look at the decline code for the reason. - **`confirm_card_data`**: the issuer declined because some card information was wrong. The customer needs to check their details. If an advice code is present, let it override any general rule of thumb. A `do_not_try_again` on what looks like a soft decline means stop. ## Soft vs hard declines Stripe does not label every code as soft or hard, but the distinction is useful and Stripe uses it in its retry documentation: - **Soft declines** are temporary. The card is valid; the issuer said no this time. Retrying later can work. - **Hard declines** mean the card cannot be charged as it is. Stripe's [Smart Retries page](https://docs.stripe.com/billing/revenue-recovery/smart-retries) lists the codes it will not retry without a new payment method: `incorrect_number`, `lost_card`, `pickup_card`, `stolen_card`, `revocation_of_authorization`, `revocation_of_all_authorizations`, `authentication_required`, `highest_risk_level` and `transaction_not_allowed`. For those hard decline codes, Stripe keeps scheduling retries on the invoice, but a charge only runs once a new payment method is attached. If nobody asks the customer, nothing will happen. We explain the retry side in detail in [how Stripe Smart Retries work](/blog/stripe-smart-retries/). ## The common codes, and what to do The table below covers the codes you will see most on subscription renewals. "Stripe's next step" paraphrases the [decline codes reference](https://docs.stripe.com/declines/codes); "For a subscription" is our practical reading. | Code | Stripe's description and next step | Retry? | For a subscription | |---|---|---|---| | `insufficient_funds` | Not enough funds; the customer should use another payment method | Yes, later | Retry at a better time (after a likely payday); email the customer with an update link | | `generic_decline` | Declined for an unknown reason, or blocked by Radar; customer contacts the issuer | A few times | Retry; email; suggest the customer call their bank or try another card | | `do_not_honor` | Generic issuer decline with no specific reason | A few times | Same as `generic_decline` | | `processing_error` | Error while processing the card; try again, then contact the issuer | Yes | Retry soon; email only if it keeps failing | | `card_velocity_exceeded` | Customer exceeded the balance, credit limit or transaction limit; contact the issuer | Yes, later | Retry later; mention a spending limit in the email | | `expired_card` | The card has expired; use another card | No | Check for an automatic card update first; otherwise ask for a new card | | `incorrect_cvc` | The CVC is incorrect; try again with the correct CVC | No | Ask the customer to re-enter their card on the update page | | `incorrect_number` | Card number is incorrect | No | Ask for a new card | | `lost_card`, `stolen_card` | Reported lost or stolen; present as a generic decline | No | Ask for a new card, without mentioning the reason | | `pickup_card` | The card cannot be used for this payment (possibly reported lost or stolen); contact the issuer | No | Ask for a new card | | `fraudulent` | Stripe suspects fraud; show the same message as a generic decline | No | Treat with care; do not reveal the reason | | `authentication_required` | The bank requires the customer to authenticate | Not without the customer | Send a link to confirm the payment; see [SCA on renewals](/blog/sca-authentication-required-renewals/) | | `revocation_of_authorization`, `stop_payment_order` | Stripe lists these with an unknown reason; customer contacts the issuer | No | Ask for a new payment method; check whether the customer meant to stop paying | | `transaction_not_allowed` | Not permitted on this card | No | Ask for another card or payment method | Two points are easy to miss: 1. **Some reasons must not be shown to the customer.** For `lost_card`, `stolen_card` and `fraudulent`, Stripe's reference says to present the decline as a generic decline. Your dunning email should say "your payment was declined", never "your card was reported stolen". 2. **"Contact your issuer" is a real instruction.** For generic declines, a call to the bank often resolves the block. It is fine to say so in the email, briefly. ## Retry limits are real Retrying is not free, even for soft declines. Card networks limit how often a merchant can retry a declined card, and issuers can treat excessive retries as a fraud signal. According to Stripe's support article on [payments blocked due to excessive retries](https://support.stripe.com/questions/payment-blocked-due-to-excessive-retries) (accessed November 2026), Visa's rules broadly prohibit more than 15 retries of a single payment over 30 days. For Visa transactions on integrated pricing, Stripe blocks retries after the 15th attempt when it judges the chance of success to be low. Stripe's own retry defaults (8 tries for Smart Retries) sit well under that, but custom retry logic outside Stripe can cross it if you are not careful. Mastercard's equivalent signal is the Merchant Advice Code, which Stripe exposes as `network_advice_code`. Processor documentation such as [Braintree's merchant advice codes reference](https://developer.paypal.com/braintree/docs/reference/general/merchant-responses/merchant-advice-codes) describes codes that mean "do not try again" and one that means the cardholder cancelled the recurring payment. When you see these, stop retrying that card. Practical rules: - Count every attempt per invoice, including ones your own code triggers. - Stop immediately on a hard decline or a `do_not_try_again` advice. - Do not retry the same card several times in one day "just in case". - Space soft-decline retries out, and align them with when money is likely to be available. ## What to tell the customer, by group Most teams send the same email for every failure. A few variations by decline group work better and are not much extra work. | Group | Codes | Email message | |---|---|---| | Funds or limits | `insufficient_funds`, `card_velocity_exceeded` | "We'll try again on [date]. If you'd rather use another card, update it here." | | Unclear | `generic_decline`, `do_not_honor`, `processing_error` | "Your bank declined the payment. It's often a temporary block; a quick call to your bank, or another card, usually fixes it." | | Card unusable | `expired_card`, `lost_card`, `stolen_card`, `pickup_card`, `incorrect_number` | "We need a new card to keep your subscription active." No reason given. | | Authentication | `authentication_required` | "Your bank asks you to confirm this payment. It takes a minute." | | Card details | `incorrect_cvc`, `confirm_card_data` advice | "Some card details didn't match. Please re-enter your card." | Ready-to-use emails for each step are in our [dunning email templates](/blog/dunning-email-templates/). ## Logging decline codes properly You cannot improve what you do not measure. For every failed renewal, store: - Invoice ID, customer ID, amount and currency. - Attempt number and date. - `decline_code`, `advice_code`, `network_decline_code`, `network_advice_code`. - Card brand, funding type (credit, debit, prepaid) and country. - Outcome: recovered (and how: retry, new card, authentication), or lost. With a few months of data, you can answer the questions that matter: which codes recover on retry and which only recover when the customer acts, whether prepaid cards fail more often (see [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/)), and whether your emails or your retries do most of the work. ### Grouping for reports Raw codes are too granular for a monthly report. Group them: | Report group | Codes | |---|---| | Soft: funds | `insufficient_funds`, `card_velocity_exceeded` | | Soft: unclear | `generic_decline`, `do_not_honor`, `processing_error`, `try_again_later` | | Hard: card | `expired_card`, `lost_card`, `stolen_card`, `pickup_card`, `incorrect_number`, `incorrect_cvc` | | Hard: authorization | `revocation_of_authorization`, `revocation_of_all_authorizations`, `stop_payment_order`, `transaction_not_allowed` | | Authentication | `authentication_required` | | Risk | `fraudulent`, `highest_risk_level` | Keep the raw code in your data so you can regroup later. Stripe adds and deprecates codes over time; Stripe's reference now marks some older codes as deprecated in favor of advice codes. ## Testing decline handling Stripe provides [test card numbers](https://docs.stripe.com/testing) that trigger specific decline codes. Before going live with any recovery logic, run each group through test mode: - [ ] A soft decline schedules a retry and sends the first email. - [ ] A hard decline sends a "new card needed" email and does not retry the same card. - [ ] `authentication_required` sends a confirmation link. - [ ] `lost_card` and `stolen_card` produce a generic message. - [ ] A successful payment (`invoice.paid`) stops all emails and retries. - [ ] Each attempt is logged with its codes. ## Common mistakes - **Treating every decline the same.** Retrying a stolen card eight times does not recover anything and can count against you with the network. - **Telling the customer the raw reason.** "Do not honor" means nothing to customers, and some reasons must not be disclosed at all. - **Ignoring advice codes.** They exist precisely to tell you whether to retry. - **Only reading the first failure.** The code can change between attempts; a card can go from `insufficient_funds` to `expired_card` across a long retry window. - **No exit for hard declines.** If the only path to recovery is a retry, hard declines are lost by design. For the full picture of failed payment recovery, from retries to emails to measurement, see [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). ## How NoChurn helps NoChurn reads the decline code on every failed renewal and handles each group differently. Soft declines are retried at times based on likely paydays and the customer's local time (or you keep Stripe Smart Retries). Hard declines and authentication requests skip pointless retries and go straight to an AI-written recovery email, reviewed before sending, with a link to a hosted card update page. Sensitive reasons are never shown to the customer, and every decision is logged with its code. It connects to Stripe in one click, and pricing depends only on MRR, with no share of recovered revenue. See [failed payments](/#dunning) and [pricing](/pricing/). --- # How Stripe Smart Retries work, and when to customize retry timing Source: https://www.nochurn.sh/blog/stripe-smart-retries/ When a subscription payment fails on Stripe Billing, Stripe can try the charge again automatically. Smart Retries is the setting that decides when. It is Stripe's recommended option, and many teams turn it on and never look at it again. That is mostly fine. But it helps to know what Smart Retries actually does, what it cannot do, and the few situations where you should change the defaults. This article sticks to what [Stripe's documentation](https://docs.stripe.com/billing/revenue-recovery/smart-retries) says, and points out where Stripe does not publish details. ## What Smart Retries is Smart Retries is Stripe's automatic retry logic for failed invoice payments. Instead of retrying on fixed days (for example 3, 5 and 7 days after the failure), Stripe uses a model to choose when each retry runs. Stripe's docs describe the model as using time-dependent, dynamic signals to pick the best times. What Stripe does not publish is the exact list of signals, their weights, or the intervals it will pick for a given payment. Treat Smart Retries as a black box with a few dials around it. ### Where it applies Smart Retries applies to invoices that Stripe collects automatically, which covers most subscription renewals. Invoices you send for manual payment (where the customer pays the invoice themselves) follow Stripe's [automatic collection](https://docs.stripe.com/invoicing/automatic-collection) rules instead, which is a different setup. Stripe also documents [Smart Retries for off-session payments](https://docs.stripe.com/payments/off-session-payments/smart-retries) outside of Billing. Check that page for availability in your account, as it may be limited. ## The settings you control In the Stripe Dashboard, the retry settings live in the revenue recovery section of Billing settings. The controls are: | Setting | Options | Stripe's recommendation | |---|---|---| | Retry policy | Smart Retries or a custom schedule | Smart Retries | | Number of retries (Smart Retries) | Configurable | 8 tries | | Retry window (Smart Retries) | 1 week, 2 weeks, 3 weeks, 1 month or 2 months | 2 weeks | | Custom schedule | Up to 3 retries, each a set number of days after the previous one | n/a | | After the last retry fails | Cancel the subscription, mark it unpaid, or leave it past due | Your choice | The "8 tries within 2 weeks" default comes from [Stripe's Smart Retries page](https://docs.stripe.com/billing/revenue-recovery/smart-retries). The labels in your Dashboard may differ slightly over time, so check the page directly. ### What the end-of-retries options mean - **Cancel the subscription.** The subscription ends. The customer has to start a new one to come back. - **Mark the subscription as unpaid.** The subscription stays in place, but Stripe stops attempting payment on new invoices until the situation is resolved. Useful if you want to keep the account and restore access once the customer pays. - **Leave the subscription past due.** The subscription keeps running and keeps generating invoices. This is the most lenient option, and it can pile up unpaid invoices if you do not act on it. Separately, you decide what happens to the unpaid invoice itself (for example, leaving it open or marking it uncollectible). Make both choices on purpose; they change how your MRR and churn numbers look. ## What Smart Retries will not do ### It will not retry hard declines on its own Some declines mean the card simply cannot be charged again. Stripe's docs list the hard decline codes for which it cannot retry automatically: - `incorrect_number` - `lost_card` - `pickup_card` - `stolen_card` - `revocation_of_authorization` - `revocation_of_all_authorizations` - `authentication_required` - `highest_risk_level` - `transaction_not_allowed` For these, Stripe keeps scheduling retries and the invoice's `attempt_count` keeps going up, but the charge only actually runs once a new payment method is attached. In other words, the retry schedule is waiting for the customer. If no one asks the customer for a new card, nothing happens. ### It does not talk to the customer Retries are silent. They do not tell the customer anything is wrong. Stripe can send separate [customer emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails) when card payments fail, and a link to confirm payments when the bank requires authentication. Those settings are independent of Smart Retries, so check they are turned on. ### It does not know your customers The model works on payment signals. It does not know that your customers are mostly teachers paid on the last working day of the month, that a customer just emailed support saying they changed banks, or that a B2B customer's finance team only pays on Tuesdays. That context lives in your systems, not in Stripe's. ## How to see what Smart Retries is doing You can follow retries in two places: - **In the Dashboard**, open the invoice. The timeline shows each attempt and its decline code, plus the next scheduled attempt. - **Through the API and webhooks.** The Invoice object has `attempt_count` and `next_payment_attempt` fields. Listen to `invoice.payment_failed` to react to each failure, and `invoice.paid` to stop any follow-up when it succeeds. A simple log of each failure (decline code, attempt number, amount, date, whether it was later paid) is enough to measure how retries perform for you. See the measurement section of the [complete guide to failed payments](/blog/recover-failed-payments-stripe/) for the formulas. ## When to customize retry timing Smart Retries is a good default. Here are the cases where it is worth reconsidering. ### 1. Your customers are paid on predictable dates If most of your customers are consumers in the same country, many soft declines will be `insufficient_funds` near the end of the month. A retry right after common paydays (for example the 1st, the 15th, or the last working day, depending on the country) may do better than a model trained on everyone. You cannot tell Smart Retries about paydays, so this means either a custom schedule or retry logic outside Stripe. ### 2. Your billing cycle is short On weekly plans, a 2-week retry window means the next invoice is created before the previous one is resolved. Shorten the window, or use a custom schedule with fewer, closer retries. ### 3. You sell to businesses B2B failures are more often about a card that was replaced, an expense limit, or a finance process, and less about timing. Fewer retries and earlier outreach to the right person (often not the user who signed up) tend to matter more than precise retry timing. ### 4. You need a predictable timeline A custom schedule makes it easy to align emails with retries ("we'll try again on Thursday") and to explain the process to support. Smart Retries is less predictable by design. ### 5. You want a longer grace period for valued customers Stripe's retry settings are account-wide. If you want a longer window for annual or long-tenured customers, you need logic of your own, such as pausing the default flow for those customers and handling them separately. ## Smart Retries vs a custom schedule | | Smart Retries | Custom schedule | |---|---|---| | Timing | Chosen by Stripe's model | Fixed days you set | | Number of retries | Configurable (8 recommended) | Up to 3 | | Window | 1 week to 2 months | Sum of your intervals | | Uses your customer data | No | No, but you choose dates with it in mind | | Predictable for emails and support | Less | Yes | | Effort | None | Low | If you build your own retry logic (for example, retries timed to the customer's local time and payday), you generally turn Stripe's automatic retries off for those invoices so the two do not compete. Test this carefully in test mode first. ## A practical setup for most SaaS teams 1. Keep Smart Retries on, with the recommended 8 tries in 2 weeks for monthly plans. 2. Set the end-of-retries action deliberately. "Mark unpaid" is a good middle ground if you want to keep the account and restore access on payment. 3. Turn on Stripe's failed payment emails at minimum, or better, run your own [dunning sequence for days 0, 3, 7 and 14](/blog/dunning-email-templates/). 4. Treat hard declines differently: ask for a new card immediately. 5. Turn on authentication emails if you sell in Europe. 6. Log every failure and measure recovery by cohort. 7. Revisit the settings once you have a few months of data. If most of your failures are end-of-month `insufficient_funds`, test payday-aligned timing. ## How NoChurn helps NoChurn works alongside Stripe. You can keep Stripe Smart Retries, or let NoChurn retry failed payments at times based on likely paydays and the customer's local time. Either way, it sends AI-written recovery emails (day 0, 3, 7 and 14 by default) in the customer's language, reviewed before sending, with a link to a hosted card update page. Card data stays with Stripe; NoChurn never sees card numbers. It connects to Stripe in one click. Pricing depends only on MRR, with every feature on every plan and no share of recovered revenue. See [failed payments](/#dunning) and [pricing](/pricing/). --- # Trial-to-paid conversion: card-required vs no-card trials, and how to measure them Source: https://www.nochurn.sh/blog/trial-to-paid-conversion/ The end of a free trial is the first renewal a customer goes through, and for many subscription products it is the biggest single drop in the customer lifecycle. It is also where two common decisions interact: whether to ask for a card upfront, and how to count what happens next. This guide covers how to measure trial conversion so the number means something, the honest trade-offs between card-required and no-card trials, how to set each up on Stripe, and the reminder rules that apply to trials. Stripe and card network details come from their documentation (accessed November 2026). ## Measuring conversion properly ### Stripe's definition Stripe's support article on [calculating trial conversion rate](https://support.stripe.com/questions/calculating-trial-conversion-rate-in-billing) defines a converted trial as one where the full trial period has ended, the subscription has not been cancelled, and the first invoice has been paid. Stripe computes the rate as conversions in the last 30 days divided by trials that ended (by conversion or cancellation) in the last 30 days. Two consequences worth knowing: - **A customer who pays once and cancels right after still counts as converted.** Stripe says so explicitly. - **The rate can exceed 100%** in Stripe's reports, when first invoices are paid more than 30 days after the trial ended. That is a reasonable operational metric. For decisions, you want something more robust. ### A cohort-based definition Group trials by the week or month they **started**, and follow each cohort: | Metric | Formula | |---|---| | Trial-to-paid rate | Trials that paid a first invoice / trials started in the cohort | | First-renewal retention | Customers who paid the second invoice / customers who paid the first | | Paid at day 90 | Customers still paying 90 days after trial start / trials started | The last line is the one that matters most. A trial setup that converts more people who then leave in month two has not helped much. It may even have hurt, through refunds and disputes. ### Count failed first payments separately When a trial ends and the first charge fails, the customer did not decide to leave. Report these apart from cancellations: - **Cancelled during trial**: an active decision. - **First payment failed, recovered**: count as converted, and note the recovery. - **First payment failed, not recovered**: involuntary churn at conversion. See [involuntary churn](/blog/involuntary-churn/). ## Card-required vs no-card trials There is no universal winner. The two models select different people and fail in different ways. | | Card required upfront | No card upfront | |---|---|---| | Signups | Fewer: the card form is a real barrier | More | | Who signs up | People with stronger intent | Curious visitors as well as serious buyers | | What converts them | Doing nothing (the charge happens automatically) | An active decision to enter a card | | Main failure at conversion | Forgotten trials, refund requests, disputes, failed first charges | Customers who never come back to enter a card | | Main work for you | Clear reminders, easy cancel, recovering failed first charges | Activation, then asking for the card at the right moment | | Compliance weight | Higher: trial reminder rules apply | Lower, until a card is added | We are deliberately not quoting conversion benchmarks here. Published figures vary widely with product, price and method, and the honest answer is to test with your own traffic. ### When card-required tends to fit - The product shows its value quickly, so a short trial is enough. - You want a smaller number of more serious trial users, for example because each one costs you support time or compute. - Your onboarding needs payment details anyway (usage-based billing, for instance). ### When no-card tends to fit - Value takes time to appear (setup, data import, team adoption). - You sell bottom-up, and the person trying the product is not the one who pays. - You have strong activation tracking and can ask for the card when the customer is clearly getting value. ### A middle path Some teams ask for a card only for certain plans, or only after a key action (an import finished, a teammate invited). This keeps signup friction low and asks for payment when intent is visible. ## Setting it up on Stripe ### Card-required trials Create the subscription with a trial period and a saved payment method. Collect the card through Checkout or a SetupIntent so it is authenticated for future off-session use; in Europe this avoids an authentication request on the first real charge. See [SCA on renewals](/blog/sca-authentication-required-renewals/). ### No-card trials Stripe's [free trials for Checkout](https://docs.stripe.com/payments/checkout/free-trials) let you start a trial without collecting a payment method by setting `payment_method_collection` to `if_required`. Then decide what happens if the trial ends with no card, using `trial_settings.end_behavior.missing_payment_method` ([Stripe trials docs](https://docs.stripe.com/billing/subscriptions/trials)): | Value | What happens at trial end | |---|---| | `create_invoice` (default) | An invoice is created; with no way to pay it, the subscription becomes past due | | `pause` | The subscription is paused, generates no invoices, and can be resumed once a payment method is added | | `cancel` | The subscription is cancelled | For no-card trials, `pause` is usually the cleanest: no unpaid invoices pile up, and the customer can resume by adding a card. `create_invoice` makes your past-due numbers look worse for customers who were never going to pay. ### The trial ending event Stripe sends `customer.subscription.trial_will_end` ahead of the trial end. The [subscription webhooks guide](https://docs.stripe.com/billing/subscriptions/webhooks) says the timing follows the "trial ending events" setting in the Dashboard, which defaults to 3 days before the end. Use it to send your own reminder, or to check that a valid card is on file. Stripe can also send a trial reminder email itself. Stripe's page on [trial compliance](https://docs.stripe.com/billing/subscriptions/trials/manage-trial-compliance) says it sends the reminder 7 days before the trial ends (or when the trial starts, if it is shorter than 7 days), with a link to update payment details and a cancellation link. ## Trial reminder rules If you collect a card and charge it automatically when the trial ends, rules apply. **This is not legal advice**; check the rules for your markets. - **Visa.** Visa's [trial subscription rules](https://usa.visa.com/dam/VCOM/global/support-legal/documents/visa-new-subscription-rules-flier.pdf) require, among other things, that merchants offering trials send a reminder with a link to an easy online cancellation at least 7 days before the first recurring charge, and that cardholders can cancel online. Stripe's [FAQ on the 2020 Visa rules](https://support.stripe.com/questions/2020-visa-trial-subscription-requirement-changes-faq) explains how they apply to Stripe users. - **Mastercard** has its own recurring billing requirements; Stripe summarizes them in its [Mastercard guidance](https://support.stripe.com/questions/guidance-for-mastercard-recurring-billing-compliance-updates). - **California.** The state's Automatic Renewal Law ([section 17602](https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=BPC§ionNum=17602)) requires, for free trials lasting more than 31 days, a notice at least 3 and at most 21 days before the trial ends, for consumers in California. - **UK.** The DMCC Act subscription regime includes reminders before the end of free or discounted trials; it is not in force yet, with a start announced for January 2027. See [click-to-cancel rules](/blog/click-to-cancel-rules/). A reminder 7 days before the end of the trial, with the date, the amount, and working links to cancel and to update the card, covers the card network rules above and fits inside California's window for long trials. Check whether anything stricter applies to you. Reminders cost a few conversions from people who forgot they had a trial. Those are the customers most likely to ask for a refund or dispute the charge, so the trade is usually worth it even before the rules. ## Improving conversion honestly The most reliable levers are on the product side and in the hand-off to payment: 1. **Activation first.** Define the one or two actions that predict conversion for your product and push trial users toward them. 2. **Ask for the card when value is visible** (no-card trials): after an import, a first report, a teammate joining. 3. **Make the end of the trial clear**, in the app and by email, with the date and the price. 4. **Offer a fit, not a trick**: a smaller plan or monthly billing for people who hesitate, never a hidden charge. 5. **Recover failed first charges** quickly: the customer has just decided to stay, and a fast, clear card update request keeps that decision from being undone by a decline. See [how to recover failed payments on Stripe](/blog/recover-failed-payments-stripe/). 6. **Look at who converts.** Payment method type, signup source and early usage often separate converters from non-converters. See [predict churn with your customer data](/blog/predict-churn-with-customer-data/) and [prepaid and virtual cards](/blog/prepaid-virtual-cards-churn/). ## Checklist - [ ] Trial conversion is measured by start cohort, with paid-at-day-90 alongside. - [ ] Failed first payments are reported separately from cancellations. - [ ] Cards are collected with off-session authentication (card-required trials). - [ ] `missing_payment_method` is set deliberately (no-card trials), usually to `pause`. - [ ] A reminder goes out 7 days before the trial ends, with date, amount, cancel link and card update link. - [ ] Cancellation during the trial works online in a few clicks. - [ ] `trial_will_end` triggers a check that a valid card is on file. - [ ] The first charge has a dunning sequence ready. ## How NoChurn helps NoChurn gives each new customer a churn score from 0 to 100 at signup, based on the payment method, the signup source and any custom data you send through the API, such as trial length or activation. You can see early which trial users are likely to leave, and the attributes that correlate with churn across your base. When the first charge fails, NoChurn retries at better times and sends AI-written recovery emails, reviewed before sending, with a hosted card update page. Customers who cancel go through a cancel flow with a one-click cancel button always visible. It connects to Stripe in one click, and pricing depends only on MRR, free until $300 MRR. See [the churn score](/#score), [custom data](/#insights) and [pricing](/pricing/). --- # Win-back email examples: what to send at 30, 60 and 90 days Source: https://www.nochurn.sh/blog/win-back-email-examples/ A win-back email goes to someone who has already cancelled. That changes everything about how it should read. The customer made a decision, so the email has to give them a new reason to reconsider: something changed, something fits better now, or the original problem has a fix. A generic "We miss you! Come back for 20% off" ignores why they left. The most useful input you have is the cancel reason. If your [cancel flow](/blog/cancel-flow-best-practices/) asked "what's the main reason?", you can write a different sequence for each answer. This guide gives a timing framework and original example emails for the most common reasons. ## Why 30, 60 and 90 days There is no universal best schedule, but a 30/60/90 cadence works as a default for monthly SaaS: | Day | Purpose | Tone | |---|---|---| | 30 | Check in after the dust settles. Address the cancel reason directly. | Helpful, low pressure | | 60 | Share what changed: new features, fixes, pricing options. | Informative | | 90 | Last message in the sequence. Make the offer, if any, and say you won't keep emailing. | Direct, respectful | Thirty days gives the customer time to try life without your product, or to try the alternative. By 90 days, most people have either settled into something else or are ready to reconsider. After the third email, stop. Add them to your regular product newsletter only if they opted in. Adjust for your billing cycle. For annual plans, the first useful moment may be closer to their old renewal date. For seasonal businesses, time the emails to the next season. ## Ground rules - **Respect consent.** Win-back emails are marketing in many jurisdictions. Check that you have the right to send them (for example, opt-in requirements for EU consumers under ePrivacy rules), and include a working unsubscribe link. - **Write from a person.** A named sender with a reply-to address that a human reads. - **One message, one action.** One link or button per email. - **Be specific about what changed.** "We've improved a lot" means nothing. "Bulk export to CSV shipped in October" means something. - **Don't fake scarcity.** No invented deadlines. - **Keep the data promise.** If you said you would delete their data after 90 days, don't promise in email 3 that "everything is still there." - **Stop when they come back.** Remove reactivated customers from the sequence immediately. ## Examples by cancel reason The examples below use a fictional project management tool called "Planwise" with a $49/month Team plan and a $19/month Basic plan. Replace the details with yours. ### Reason: too expensive The customer may still like the product. The question is whether there is a price that works. **Day 30** > **Subject:** A smaller Planwise plan > > Hi Dana, > > When you cancelled last month, you said Planwise was too expensive. That's fair feedback. > > In case it helps: the Basic plan is $19/month for up to 3 people, and it keeps boards, tasks and history. If your team is small, it may cover what you used. > > [Compare plans] > > Either way, thanks for trying Planwise. > Sam, Planwise **Day 60** > **Subject:** Annual billing is now 2 months free > > Hi Dana, > > One more option since you left: paying yearly now costs the same as 10 months. For the Team plan, that's $490/year instead of $588. > > [See annual pricing] > > Sam Only send this if the pricing change is real. If nothing changed, skip day 60 for this reason. **Day 90** > **Subject:** Last note from Planwise > > Hi Dana, > > This is the last email I'll send about coming back. If you'd like to restart, you can have 40% off your first 3 months on any plan. After that, it's the regular price. > > [Restart with 40% off] > > If not, no hard feelings. Good luck with the projects. > Sam ### Reason: not using it enough This reason often means the product didn't become a habit, or the project that needed it ended. **Day 30** > **Subject:** Starting a new project? > > Hi Marco, > > You cancelled because you weren't using Planwise much. If a new project comes up, you can restart in a minute and import from a spreadsheet. > > [Import a project] > > Sam **Day 60** > **Subject:** 3 templates for getting started fast > > Hi Marco, > > A lot of teams stop using a tool when setup takes too long. We added templates for product launches, client onboarding and content calendars. Each takes about five minutes to adapt. > > [Browse templates] > > Sam **Day 90** > **Subject:** Pause instead of cancel, next time > > Hi Marco, > > Last email from me. If you come back and your usage goes up and down, you can now pause your subscription for up to 3 months instead of cancelling. Billing stops, and your boards stay. > > [Restart Planwise] > > Sam ### Reason: missing a feature This is the best reason to have, because you can answer it precisely. Store the feature they named (from the free-text field or a follow-up question) and only email when it ships. **Day 30 (if the feature shipped)** > **Subject:** Gantt view is live > > Hi Priya, > > When you left, you mentioned Planwise didn't have a Gantt view. It shipped this week. Here's a 90-second video of how it works. > > [Watch the video] > > If you want to try it, your workspace is still available until March 2. > Sam **Day 30 (if it didn't ship)** > **Subject:** About the Gantt view > > Hi Priya, > > You told us you needed a Gantt view. I wanted to be straight with you: it's planned, but not before next quarter. I'll email you once when it ships, and not before. > > Sam The honest version builds more trust than silence, and it sets up a much stronger email later. **Day 60 and 90:** send only if there is real news on that feature. Otherwise, end the sequence. ### Reason: switched to a competitor The customer is now using something else. Discounts rarely work here; learning and specific differences might. **Day 30** > **Subject:** One question > > Hi Alex, > > You moved to another tool last month. Would you tell me what it does better? One line is enough, just hit reply. It goes straight to me. > > Sam **Day 60** > **Subject:** Moving back is one click > > Hi Alex, > > If the new tool isn't working out, Planwise can now import directly from CSV and from most tools' export formats. Your old workspace is still here until March 2. > > [Import your data] > > Sam **Day 90:** usually skip. If you send one, keep it to a single line saying the door is open. ### Reason: too hard to use The barrier was effort. Offer to remove it. **Day 30** > **Subject:** Want us to set it up for you? > > Hi Jordan, > > You said Planwise was hard to get going. If you're up for it, I can do a 20-minute setup call and build your first board with you. > > [Book a time] > > Sam **Day 60** > **Subject:** We simplified the first screen > > Hi Jordan, > > Since you left, we cut the onboarding to three steps and added a sample project you can edit. Here's what it looks like now. > > [See the new onboarding] > > Sam ### Reason: no longer needed (company closed, project ended) Usually send one email at most, at day 60 or 90, and only a friendly note. No discount. > **Subject:** Thanks for using Planwise > > Hi Lee, > > Just a note to say thanks for the time you spent with Planwise. If you ever need it again, your account email still works. > > Sam ## Which offers belong in win-back emails | Offer | Good fit | Watch out for | |---|---|---| | Discount on return | Price-driven cancellations | Training customers to churn and return for a discount | | Cheaper plan | Price, low usage | Making sure it actually covers their use case | | Annual billing | Price, if they liked the product | Only if the saving is real | | Setup call | Too hard to use | Staff time; cap it | | Feature news | Missing feature | Send only when it ships | | No offer | Competitor, no longer needed | None; restraint is the point | Two rules for discounts: make them one-time per customer, and state when the regular price resumes. See [pause vs discount vs downgrade](/blog/pause-vs-discount-retention-offers/) for the trade-offs. ## Measuring win-back Track per reason and per email: - **Reactivation rate:** reactivated customers / customers who entered the sequence. - **Reactivated MRR**, minus the cost of any discount. - **Retention after reactivation:** do they stay 3 and 6 months, or leave again when the discount ends? - **Reply rate:** especially for "one question" emails. Replies are research. - **Unsubscribe and spam complaint rate:** if it rises, your emails are too frequent or too pushy. Keep a holdout group that gets no win-back emails, so you can see how many customers would have come back on their own. ## Checklist - [ ] Cancel reason is stored with each cancellation. - [ ] One sequence per reason, three emails maximum. - [ ] Consent and unsubscribe handled. - [ ] Sender is a named person, replies are read. - [ ] Each email has one action. - [ ] "What changed" claims are true and specific. - [ ] Discounts are one-time and their terms are stated. - [ ] Reactivated customers leave the sequence immediately. - [ ] Holdout group in place. ## How NoChurn helps NoChurn sends [win-back emails](/#winback) at 30, 60 and 90 days, written from the cancel reason each customer gave in the [cancel flow](/#cancel). NoChurn works in English, German, French, Italian and Portuguese. Every feature is included on every plan, priced by MRR only ([pricing](/pricing/)).