
When a subscription payment fails, most of the work is done for you. Stripe's documentation describes automatic retries for failed subscription and invoice payments, and a recommended setting called Smart Retries that picks retry times using signals such as when payment tends to succeed. For new accounts Smart Retries is on by default, configured for up to 8 retries within 2 weeks, according to Stripe's documentation at the time of writing.
So what is left for a workflow? Three things Stripe's retry engine cannot do for you: decide what to say to each customer, notice the cases that need a person, and handle the end of the retry schedule.
What Stripe tells you, and what it does not#
Stripe sends an invoice.payment_failed webhook when a subscription payment fails, including retry attempt updates. The invoice carries an attempt_count and a next_payment_attempt date. Two details from the docs shape the design:
- Hard declines are different. If the issuer returns a hard decline code, such as
lost_card,stolen_card,incorrect_numberorauthentication_required, Stripe keeps scheduling retries but they only run once a new payment method is detected. Nothing will succeed until the customer acts. - The end of the schedule is configurable. When recovery fails, your settings decide whether the subscription is cancelled, marked unpaid, left past due or paused.
Notice the practical consequence. A soft decline, such as a temporary problem, may resolve by itself, and an email is optional. A hard decline will not resolve without the customer, and waiting is pointless.
The workflow#
Here is a design that uses only things that exist in Cadrix today: a webhook start, a Condition, an agent, a Human Input step, and either email or WhatsApp tools.
- Start from a webhook. In your Stripe dashboard, send
invoice.payment_failedevents to the workflow's webhook address. Do not trust the payload blindly. A safe pattern is to take only the event ID from the webhook and fetch the event again from the Stripe API with a web request, so what you act on comes from Stripe and not from whoever called your address. - Normalise the data. Pull out the customer email, the amount, the attempt count, the next attempt date and the decline code. A short JavaScript step or a web request back to the Stripe API can do it.
- Skip duplicates. Webhooks can be delivered more than once. Store the event ID in a sheet or a variable and stop if you have seen it. Our retries post covers idempotency in more depth.
- Branch on the reason. A Condition sends hard declines down one path and everything else down another.
- Soft declines: wait. For a first attempt with a retry scheduled, do nothing, or send a light notice that a retry is coming. Over-messaging on a first attempt is the main way this workflow annoys people.
- Hard declines: ask the customer to update. An agent drafts a short message in the customer's language that says what happened, how to update their payment method and the date of the next attempt.
- Approval for sensitive accounts. A Condition checks the amount or the plan. Large or strategic accounts go to a Human Input step where an account owner reviews and edits the draft before it is sent. Small accounts go straight out.
- Send. Use the Gmail or Outlook tool, or WhatsApp where you have consent to use it for service messages.
- Log. Write a row to a sheet: customer, event ID, attempt count, decline code, what was sent and when.
Run it first in a test account with Stripe's test mode, so you can see the whole path before a real customer is involved.
Writing the message#
The agent's instructions are where most of the quality comes from. A few rules that help:
- State the facts the webhook gave you and nothing else. Do not let the agent guess why the payment failed.
- Never include card details, even partial ones, beyond what the customer already sees on their invoice.
- One action per message: a link to update the payment method.
- No threats. Mention the date of the next attempt, and what happens at the end of the schedule only if your policy states it.
- Keep it short enough to read on a phone.
Give the agent a short example or two of tone. Then test with real-looking cases, including a customer whose name has an apostrophe and one whose language is not English.
The decision that should stay with a person#
The last step of dunning is cancel, pause or write off. That is a business decision with customer-relationship consequences, and it is rarely the same for every account. A long-standing customer on a large plan who failed once is different from a trial account that never had a valid card.
The workflow can prepare the decision. When the final retry fails (the attempt_count reaches your configured maximum, or the subscription status changes), send a summary to a Human Input step: customer, plan, history, messages already sent, and a suggested action. The person approves, edits or rejects. Only then does the workflow call the Stripe API or notify your team.
Where the human goes. Two places: the draft email for accounts above a value you choose, and the end-of-schedule decision for every account. Everything in between runs on its own and is logged.
Mistakes to avoid#
Fighting Stripe's retries. Do not build your own retry loop that charges the customer on top of Stripe's. Let Stripe retry; your workflow communicates.
Messaging on every event. One webhook per attempt means several. Decide which attempts get a message, for example the first hard decline and the last attempt before the end of the schedule.
Trusting the model with money. The agent drafts. It should not call a tool that refunds, cancels or changes a subscription without an approval in front of it.
Forgetting the failure path. If the email tool fails or the webhook is malformed, someone should hear about it. Set a default error workflow for the workspace so failures reach a person.
Measure it#
After a month, look at the log. How many hard declines were followed by a customer update within three days? Which message versions worked? How often did approvers edit the draft, and what did they change? The edits are free training data for your instructions.
Sources#
- Stripe documentation, "Automate payment retries": https://docs.stripe.com/billing/revenue-recovery/smart-retries


