Recover failed payments before the subscription cancels
Finds past-due Stripe subscriptions, emails each customer a link to pay with Resend, and posts the largest amounts to Slack.
Outcome
An email with a link to pay for every customer with a past-due subscription, or a note on why not, such as Stripe already emailing them.
A Slack post for each customer who owes more than your escalation amount.
The total amount due, by currency.
How it works
SFind past-due subscriptions, by List subscriptions by Stripe
List subscriptions with status
past_due. Keep each subscription ID and customer ID.
SGet the unpaid invoices, by List invoices by 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, by Your agent
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.
RSend, by Send an email by Resend
After the user approves, send each email from
senderto itscustomer_email, one recipient per email. Keep each email's ID.
SEscalate the big ones, by Post a message by Slack
Post one message per customer who owes
escalate_amountor more tocs_channel, withcustomer_name, the amount and the next retry date.
You'll be asked for
The address to send from, on a domain verified in Resend
e.g. billing@acme.example
Whether Stripe already emails customers about failed payments
e.g. no; if yes, this workflow only escalates
The amount due that deserves a personal call, with its currency
e.g. 1,000 USD (Stripe's 100000 in cents)
The Slack channel for escalations
e.g. #customer-success
failed-payment-recovery.mdView markdown
Recover failed payments before the subscription cancels
Finds past-due Stripe subscriptions, emails each customer a link to pay with Resend, and posts the largest amounts to Slack.
Set up the tools below, then run the steps in order for the user, carrying each step's results into the next. The run is done when the user has the outcome below.
Outcome
- An email with a link to pay for every customer with a past-due subscription, or a note on why not, such as Stripe already emailing them.
- A Slack post for each customer who owes more than your escalation amount.
- The total amount due, by currency.
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.
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.
