Recover failed Stripe payments with Postmark dunning emails
When a Stripe invoice payment fails, send a friendly Postmark recovery email with a one-click pay link, then alert your revenue team in Slack so nothing slips.
Build me an agent workflow that recovers failed Stripe subscription payments by sending a personalized dunning email through Postmark and alerting our revenue team in Slack.
Trigger: incoming Stripe webhook on the invoice.payment_failed event. Verify the Stripe signature and only proceed on that event type.
When the webhook fires, hand the invoice ID and customer ID to the agent and have it do the following:
1. Use Stripe Retrieve Invoice to load the failed invoice. Read the amount due (in the smallest currency unit, convert to dollars for display), currency, attempt count, hosted_invoice_url, the last_payment_error code, and the linked subscription ID.
2. Use Stripe Retrieve Customer to load the customer's name, email, and any metadata that helps personalize the message.
3. Use Stripe Retrieve Subscription on the invoice's subscription so the agent knows the plan/product name and the next renewal date.
4. Branch on the failure code. If last_payment_error.code is requires_action (3D Secure / authentication required), the customer did not actually decline, so skip the Postmark send and post a different Slack message that says "authentication required, customer needs to confirm with their bank." If it is card_declined or any other normal decline reason, continue to the dunning email.
5. Use Postmark Send Email with Template to send the recovery email. Use TemplateAlias = payment_failed (not TemplateId, so the workflow keeps working if the template is re-created). The From address must be a verified Postmark Sender Signature; let me pick which verified sender to use during setup. Pass a TemplateModel that includes: customer_first_name, product_name (from the subscription's plan/product), amount_due_formatted (e.g. "$49.00"), currency, hosted_invoice_url (Stripe's hosted payment page), attempt_count, and next_retry_date if Stripe provides one on the invoice. Keep the tone short, friendly, and urgent. After the send, check the response ErrorCode and fail loud if it is non-zero (Postmark returns HTTP 200 even on logical send errors).
6. Use Slack Bot Send a Message to post to the #revenue channel (let me pick the channel during setup). Include the customer name and email, the MRR at risk (use the subscription's plan amount as a proxy if invoice amount is one-off), the attempt count, whether the dunning email sent or was skipped, and a link to the Stripe customer page (https://dashboard.stripe.com/customers/{customer_id}). One short Slack message, formatted with Slack mrkdwn, not a giant block.
Other requirements:
- Use the Slack Bot integration (xoxb token), not the user-OAuth Slack integration, since this is an automated workspace alert.
- Convert Stripe amounts from cents to dollars before showing them in the email or Slack message.
- If the customer does not have an email on file, skip the Postmark send but still post the Slack alert so a human can chase them.
- Log every run with the invoice ID, customer ID, decision (sent / skipped-3DS / skipped-no-email), and Postmark MessageID if applicable, so I can audit recovery later.
Additional information
What does this prompt do?
- Listens for failed Stripe invoice payments the moment they happen, no waiting for a daily report.
- Sends the customer a short, personalized recovery email through Postmark with the amount due, the plan they pay for, and a direct link to pay the invoice.
- Skips the email when the failure is a 3D Secure step-up (the card was not declined, the bank just needs the customer to confirm), so you do not nag people who actually paid.
- Posts a one-line heads-up to your #revenue Slack channel with the customer name, monthly revenue at risk, retry attempt number, and a link to the Stripe customer page for human follow-up.
What do I need to use this?
- A Stripe account with permission to read invoices, customers, and subscriptions.
- A Postmark account with a verified sender address and a saved template named payment_failed for the recovery email.
- A Slack workspace where the bot can post to your #revenue (or other) channel.
How can I customize it?
- Change the Slack channel from #revenue to your billing, finance, or CS team channel, or send a direct message to an account owner instead.
- Tune the email tone and copy in your Postmark template (urgency, retry date language, plan-specific upsells) without touching the workflow.
- Adjust which failure reasons skip the email or change the message for soft declines (insufficient funds) vs hard declines (lost or stolen card).
Frequently asked questions
Why use Postmark instead of Stripe's built-in Smart Retries email?
Will it skip 3D Secure failures so customers do not get a confusing email?
Can I send the recovery email from a different domain?
What happens if the customer pays after the email goes out?
Can I add a 48-hour follow-up if the invoice still is not paid?
Stop losing revenue to silent card declines.
Connect Stripe, Postmark, and Slack once, and Geni runs personalized dunning the moment a payment fails.