Recover failed Stripe payments with SQL Server context and Gmail dunning

When a Stripe invoice payment fails, enrich the customer from your SQL Server billing database, send a tone-matched recovery email through Gmail, and log every attempt for retention.

Agentic Task
StripeSQL ServerGmailFinanceOperationsEmail AutomationNotifications & AlertsData Sync
PromptCreate

Build an agent workflow that recovers failed Stripe payments by enriching the customer from my SQL Server billing database, sending a tone-matched recovery email through Gmail, and logging every attempt back to SQL Server.

Trigger: a Stripe webhook on the invoice.payment_failed event. The webhook payload includes the invoice, the customer id, the failure reason, the amount due, and the next retry date if Stripe is going to retry automatically.

Steps the agent should run for each event:

1. Call Stripe's Retrieve Customer operation with the customer id from the webhook to get the customer's email, name, and any metadata on the Stripe record.

2. Look up that customer in my SQL Server billing database. Use Find Row against my customers table (keyed on stripe_customer_id) to get account_tier, signup_date, and primary_contact_name. Then use Select Rows against my subscriptions table to get their current plan and MRR, and Select Rows against my failed_payments table to count how many prior failed payment attempts this same customer has had in the last 90 days.

3. Decide tone based on context. First failure in 90 days = gentle, assume-good-faith reminder. Second failure = clearer, slightly firmer with a direct ask. Third or more = firm last-attempt message that mentions the account is at risk of pause or cancellation. Scale the language to plan size and tenure too: a long-tenured enterprise account gets a more deferential tone than a brand-new trial conversion.

4. Draft a recovery email matched to that tone. The email must include the customer's first name, the plan name, the amount that failed, the failure reason in plain English (e.g. "your card was declined" rather than the raw Stripe code), and a clearly labeled link to update their payment method. Use the Stripe customer billing portal link if available, otherwise fall back to a configured fallback URL.

5. Send the email via Gmail's Send a Message operation from my connected Gmail address, with a subject line that matches the tone (e.g. "Quick heads up about your last payment" for first failures vs. "Action needed to keep your account active" for repeat failures).

6. Insert a row into a dunning_attempts table in SQL Server capturing: customer_id, stripe_customer_id, stripe_invoice_id, failure_reason, severity_level (1, 2, or 3 from the tone decision above), email_subject_sent, email_recipient, and sent_at timestamp.

Setup step to include in the workflow: create the dunning_attempts table in SQL Server if it does not exist, with this schema:

CREATE TABLE dunning_attempts (id INT IDENTITY(1,1) PRIMARY KEY, customer_id NVARCHAR(64) NULL, stripe_customer_id NVARCHAR(64) NOT NULL, stripe_invoice_id NVARCHAR(64) NOT NULL, failure_reason NVARCHAR(512) NULL, severity_level INT NOT NULL, email_subject_sent NVARCHAR(256) NOT NULL, email_recipient NVARCHAR(256) NOT NULL, sent_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME());

Edge cases to handle:

- If the customer is not found in my SQL Server customers table, still send a recovery email using the Stripe customer record, set severity_level to 1, set customer_id to NULL in the log, and include a note in the log that the internal record was missing.

- If the Stripe customer has no email, skip sending and write a row to dunning_attempts with email_recipient set to "unknown" so retention can see the gap.

- Treat the webhook as idempotent: if a dunning_attempts row already exists for the same stripe_invoice_id, do not send a duplicate email.

Make the table names, the fallback payment URL, the from-name on the email, and the tone copy easy for me to edit at the top of the agent's instructions.

What does this prompt do?

  • Listens for failed Stripe payments and pulls the customer's name, plan tier, tenure, and prior failed attempts from your SQL Server billing tables.
  • Drafts a recovery email whose tone scales with severity: gentle for a first slip, firmer for repeat failures, with the right plan context baked in.
  • Sends the email from your own Gmail address with a clear link to update payment details, so the customer recognizes the sender.
  • Logs every recovery touch back to a SQL Server dunning_attempts table so retention can measure which messages actually win revenue back.

What do I need to use this?

  • A Stripe account with webhooks enabled and the invoice.payment_failed event turned on.
  • A SQL Server database that holds your customers, subscriptions, and prior failed payment history, plus a user with read and insert permissions.
  • A Gmail account you want recovery emails to come from.
  • A dunning_attempts table in SQL Server with columns for customer id, invoice id, failure reason, email subject, and timestamp (the prompt includes the schema).

How can I customize it?

  • Adjust the tone ladder: how gentle the first email is, how direct the third one gets, and how many failures count as repeat.
  • Swap in the exact table and column names from your billing schema so lookups hit the right place.
  • Change the from name, signature, and the wording of the update-payment-method link in the email.

FAQs

Does this work for both subscription invoices and one-off charges?
It is built around Stripe's invoice payment failure event, which covers subscription billing. If you want to react to one-off charge failures too, you can add the charge failed event and the agent will treat them the same way.
Will the email tone really change based on how many times the customer has failed?
Yes. The agent reads the prior failed attempts for that customer from your SQL Server tables before drafting, so a first-time slip gets a warm reminder while a third failure gets a firmer last-attempt message.
What happens if the customer is missing from my billing database?
The agent falls back to the details on the Stripe customer record and still sends a recovery email, while flagging the missing record in the dunning log so you can clean it up later.
Can I send from a shared inbox like billing@mycompany.com?
Yes, as long as that Gmail account is the one you connect. The email will be sent from whichever Gmail mailbox you authorize.
What goes into the dunning_attempts log?
Each row captures the customer id, the failed invoice id, the reason Stripe gave for the failure, the subject line of the email that was sent, and the timestamp, so retention can measure recovery rates over time.

Related templates

Win back LiveChat visitors whose chats went unanswered

Every couple of hours we find the chats your team never answered, email those visitors a real reply, and hand the sensitive ones to a support lead.

LiveChat
Gmail
Slack
Agentic Task
Let support send one-off Loops emails without an engineer

Your team picks a template, finds the customer, checks they are safe to email, then sends it, with every send logged where the whole team can see it.

Loops.so
Stripe
Google Sheets
App
Customer lifecycle inspector for Loops, Stripe and PostHog

Open one screen each morning to see a paying customer's billing, product activity and email history, then send the right next email without leaving it.

Loops.so
Stripe
PostHog
App
Chase the paperwork every new client and vendor still owes

One board showing every party you are onboarding, which documents are still missing or expiring, and a one click chase email for exactly what is outstanding.

General Input Storage
General Input Database
PDF.co
+1
App
File Gmail attachments into storage with names you can find

Every hour, new email attachments get sorted by document type and vendor, saved under clear names, and logged in a spreadsheet index.

Gmail
General Input Storage
Google Sheets
+1
Agentic Task
Month-end Stripe finance pack, stored and shared in Slack

On the first business day of each month, we build a line-item CSV and written summary of last month's Stripe activity, file it, and post the numbers to Slack.

General Input Storage
Stripe
Google Sheets
+1
Agentic Task

Stop losing revenue to silent failed payments.

Connect Stripe, your SQL Server billing database, and Gmail once, and Geni runs the recovery email and the dunning log every time a payment fails.