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
PromptCreate

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.

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).

FAQs

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.

Related templates

Build a credential rotation checklist when someone leaves

When someone leaves, we check which shared passwords they used in their final months and post a ranked rotation list to your security channel.

1Password
Rippling
Slack Bot
+1
Agentic Task
Weekly Amazon S3 bucket security audit posted to Slack

Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.

Amazon S3
Slack Bot
Google Sheets
Agentic Task
Log Agorapulse social conversations to HubSpot contacts

Twice every weekday, the conversations from your social inbox land on the right HubSpot contact timelines, with a Slack recap for sales.

Agorapulse
HubSpot
Slack Bot
Agentic Task
Clean up HubSpot contacts from your Amazon SES suppression list

Every morning, find the addresses that hard bounced or filed a spam complaint, update the matching HubSpot contacts, and post a short Slack recap.

Amazon SES
HubSpot
Slack Bot
Agentic Task
Draft polite follow-ups for emails that never got a reply

Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.

Aurinko
Google Sheets
Slack Bot
Agentic Task
Replay failed SQS messages when a bug fix is merged

When you merge a fix in GitHub, this agent checks the matching dead-letter queue, replays the failed messages, and reports back on the pull request and in Slack.

Amazon SQS
GitHub
Slack Bot
Agentic Task

Stop losing revenue to silent card declines.

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