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.

Agentic Task
StripePostmarkSlack BotFinanceCustomer SupportEmail AutomationNotifications & Alerts

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?
Stripe's default email is generic and not branded to your product. With Postmark you control the copy, sender, subject, and design through a template, and you can personalize it per customer using the plan name, amount due, and a direct payment link.
Will it skip 3D Secure failures so customers do not get a confusing email?
Yes. When Stripe marks the failure as a 3D Secure step-up rather than a card decline, the workflow sends a different message (or no message) because the customer just needs to confirm with their bank, not update their card.
Can I send the recovery email from a different domain?
Yes, as long as the sender address is verified in Postmark under Sender Signatures or Domains. Update the From address in your Postmark template and the email will send from there.
What happens if the customer pays after the email goes out?
Nothing extra runs. The workflow only fires on failed payments, so once Stripe records a successful retry no further dunning email or Slack alert is sent.
Can I add a 48-hour follow-up if the invoice still is not paid?
Yes. Ask the workflow author agent to add a delayed check that re-reads the invoice 48 hours later and pings a person in Slack if it is still unpaid.

Stop losing revenue to silent card declines.

Connect Stripe, Postmark, and Slack once, and Geni runs personalized dunning the moment a payment fails.