Recover failed payments before the subscription cancels
Catch past-due subscriptions early, send a friendly link to fix the card, and hand the biggest accounts to a person.
failed-payment-recovery.md
Recover failed payments before the subscription cancels
Set up the tools below, then run the steps in order for the user, carrying each step's results into the next.
Inputs
Ask the user for these before you start.
sender: the address to send from, on a domain verified in Resend, e.g. billing@acme.examplestripe_emails_on: whether Stripe already emails customers about failed payments, e.g. no; if yes, this workflow only escalatesescalate_amount: the amount due that deserves a personal call, with its currency, e.g. 1,000 USD (Stripe's 100000 in cents)cs_channel: the Slack channel for escalations, e.g. #customer-success
Set up
Stripe (tool:stripe/list-subscriptions, tool:stripe/list-invoices)
Use the first option your agent supports.
MCP (official, remote)
Add this server to your agent's MCP settings, then sign in when asked.
{ "mcpServers": { "stripe": { "url": "https://mcp.stripe.com" } } }
- List subscriptions: call the MCP tool
stripe_api_readwithGET /v1/subscriptions - List invoices: call the MCP tool
stripe_api_readwithGET /v1/invoices
CLI (official)
Install the command and sign in with it, then confirm it runs.
npm install -g @stripe/cli
stripe --version
- List subscriptions: run
stripe subscriptions list - List invoices: run
stripe invoices list
Send an email (Resend, tool:resend/send-email)
Use the first option your agent supports.
Note: Pass an Idempotency-Key header (--idempotency-key on the CLI) so a retry never sends it twice; keys expire after 24 hours.
MCP (official, remote)
Add this server to your agent's MCP settings, then sign in when asked.
{ "mcpServers": { "resend": { "url": "https://mcp.resend.com/mcp" } } }
Call the MCP tool send-email.
CLI (official)
Install the command, then confirm it runs.
npm install -g resend-cli
resend --version
Run resend emails send.
Set $RESEND_API_KEY in your environment first (get a key: https://resend.com/api-keys).
Post a message (Slack, tool:slack/post-message)
Use the first option your agent supports.
Note: Needs the chat:write scope. Over MCP it posts as the signed-in user; the API and CLI post as the app's bot.
MCP (official, remote)
Add this server to your agent's MCP settings, then sign in when asked.
{ "mcpServers": { "slack": { "url": "https://mcp.slack.com/mcp" } } }
Call the MCP tool slack_send_message.
CLI (official)
Install the command, then confirm it runs.
curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash
slack --version
Run slack api chat.postMessage.
Set $SLACK_BOT_TOKEN in your environment first (get a key: https://api.slack.com/apps).
Before step 1, confirm access to each service with its cheapest read-only call, like a list or a search. Never send or change anything to test access.
Steps
- Find past-due subscriptions with List subscriptions (Stripe). List subscriptions with status
past_due. Keep each subscription ID and customer ID. - Get the unpaid invoices with List invoices (Stripe). For each subscription, list its
openinvoices. Keep, per customer,customer_name,customer_email, and each invoice'samount_dueandcurrency(in the currency's smallest unit),next_payment_attemptandhosted_invoice_url. - Write the nudges yourself. Skip this step and the next when
stripe_emails_onis yes, so no one gets two emails. Otherwise draft one short, friendly email per customer, with a subject and a plain-text body: the payment did not go through, eachhosted_invoice_urlto pay or update the card, and the next retry date, or that no retries are left whennext_payment_attemptis empty. Show the drafts to the user. - Send with Send an email (Resend). After the user approves, send each email from
senderto itscustomer_email, one recipient per email. Keep each email's ID. - Escalate the big ones with Post a message (Slack). Post one message per customer who owes
escalate_amountor more tocs_channel, withcustomer_name, the amount and the next retry date.
Done when
- Every customer with a past-due subscription got an email, or has a note saying why not.
cs_channelhas one post per large account, and the user has the total amount due by currency.
Rules
- Use only the services set up above. The read-only calls they need, like listing ids or polling for results, are fine.
- Ask the user before anything that sends messages, costs money, or changes data, and say how many records it touches. One approval covers a batch the user has seen.
- Never print API keys.
