Turn failed Stripe payments into Close recovery tasks

When a Stripe charge or invoice fails, open a same-day recovery task on the matching Close lead and ping your revenue channel in Slack.

Deterministic Code
StripeCloseSlack BotSalesFinanceNotifications & AlertsLead EnrichmentData Sync

Build a code workflow that turns every failed Stripe payment into a same-day recovery task on the matching Close lead, plus a Slack alert in our revenue-recovery channel.

Trigger: a Stripe webhook listening for charge.failed and invoice.payment_failed events. Verify the Stripe signature on every incoming request.

On each event, extract the customer email, the failure reason (decline code or failure message), the amount in dollars, the Stripe customer id, and the invoice id when present. For invoice.payment_failed, also capture the subscription id if it exists.

Use Stripe Retrieve Subscription to pull the current plan name and monthly recurring revenue when a subscription id is available, so we can include them in the task body. Skip this step gracefully for one-off charges with no subscription.

Use Close List Leads to find the lead whose primary contact email matches the Stripe customer's email (filter by query like email_address:"{email}"). If exactly one lead matches, use it. If zero match, treat it as unmatched and skip the Close step. If more than one match, pick the most recently updated lead and note the ambiguity in the Slack alert.

When a Close lead is found, use Close Create Task on that lead with: due date = today (in the Close org's timezone), assignee = lead owner by default (with a workflow option to override to a fixed user id), text title "Recover failed payment: ${amount} from {customer name or email}", and a body that includes the Stripe failure reason, the Stripe invoice id (or charge id), the plan and MRR if we fetched them, and a deep link to the Stripe payment in the dashboard.

Then use Slack Bot Send a Message to post in a configurable revenue-recovery channel. The message should include: the customer name and email, the dollar amount and currency, the failure reason, a link to the Stripe payment, and a link to the Close lead if matched. If no Close lead was matched, prefix the message with ":warning: Unmatched customer" so a human can triage. If multiple Close leads matched, mention that too.

Configurable inputs the workflow should expose: the Slack channel id for revenue-recovery alerts, the Close task assignee strategy (lead owner vs a fixed user id), and a toggle to include plan and MRR in the task body.

Deduplicate by Stripe invoice id (for invoice.payment_failed) and charge id (for charge.failed) so retries on the same invoice do not create duplicate Close tasks or duplicate Slack alerts. If a task already exists for that invoice or charge id, update the existing Slack alert or no-op instead of opening a second one.

Always return a 2xx to Stripe quickly so the webhook is not retried unnecessarily. Log the customer email, the event type, the matched Close lead id, the created Close task id, and the Slack message timestamp for every run.

Additional information

What does this prompt do?
  • Listens for failed Stripe charges and failed subscription invoices the moment they happen.
  • Finds the matching Close lead by the customer's email and opens a recovery task due today with the dollar amount and the reason the card was declined.
  • Posts a structured alert in your revenue channel in Slack with links to the Close lead, the Stripe customer, and the failure details.
  • If no Close lead matches the email, the Slack alert still fires and flags it as unmatched so a human can triage.
What do I need to use this?
  • A Stripe account with permission to view charges, invoices, and subscriptions.
  • A Close account where leads carry the customer's email as a contact.
  • A Slack workspace with a channel for revenue or billing alerts.
How can I customize it?
  • Choose who the recovery task is assigned to. The lead owner is the usual pick, but you can route everything to a single billing rep instead.
  • Change the Slack channel and tweak the wording of the alert, including which emoji or @mention it leads with.
  • Decide whether to include the customer's current plan and monthly recurring revenue from Stripe in the task body, so the rep knows how much is at risk before they reach out.

Frequently asked questions

Which Stripe events does this catch?
Two: a failed one-off charge, and a failed subscription invoice payment. Both fire the same recovery flow so you do not miss either kind of revenue at risk.
What happens if the customer is not in Close yet?
The Slack alert still fires, but it is flagged as unmatched. That way your rep can decide whether to create the lead, ignore it, or hand it to support.
Can the task be assigned to the lead owner instead of one fixed person?
Yes. You can pick lead owner as the default assignee, or pin it to a single billing rep. Both are one-line changes when you set the workflow up.
Does this replace Stripe Smart Retries or dunning emails?
No. Stripe still retries the card on its schedule. This workflow is the human side: it makes sure someone on your team knows and has a task to follow up before the customer churns.
Will it spam the channel if Stripe retries the same invoice four times?
You can deduplicate on the Stripe invoice ID so each invoice produces one task and one Slack alert, even when Stripe retries the card multiple times.

Stop letting failed payments quietly churn.

Connect Stripe, Close, and Slack once, and Geni opens a same-day recovery task with the right context every time a payment fails.