Recover failed Stripe payments with Linq iMessage texts
Skip the dunning email and reach customers where they read. When a Stripe payment fails, your Linq number sends a short iMessage with a one-tap retry link.
Build me a code workflow that recovers failed Stripe payments by texting the customer instead of relying on Stripe's dunning email. Every step is a fixed lookup or send, so this should be deterministic code, not an agent.
Trigger: a webhook from Stripe for the invoice.payment_failed event.
Steps:
1. Stripe Retrieve Invoice using the invoice id from the webhook payload. Pull the customer id, the hosted_invoice_url, and a short description from the first line item (fall back to "your subscription" if there is no line item description).
2. Stripe Retrieve Customer using that customer id. Pull the name and the phone field. If the phone field is empty, log "skipped: no phone on file" and stop. Do not raise an error.
3. Linq List Phone Numbers and pick the first active sender number on the account. If the workflow has more than one, the user should be able to configure which one to use.
4. Linq Check iMessage Capability for the customer's phone from the chosen sender. If Linq cannot reach the number (unsupported region or no capability for any service), log "skipped: unreachable" and stop. The capability check just tells us whether to try at all; the actual chat will route to iMessage, RCS, or SMS automatically.
5. Linq Create Chat from the chosen sender to the customer's phone (E.164) with an initial text part: "Hi {first name}, your payment for {description} didn't go through. You can update your card and retry here: {hosted_invoice_url}. Reply STOP to opt out." If the Stripe customer has no name, use "there" as the greeting. Keep the message under 320 characters.
Notes:
- The customer's phone on Stripe must be E.164 (for example +14155550123). If it isn't in that format, try a simple normalization; if normalization fails, treat it like a missing phone and skip.
- Linq enforces a limit of 30 messages per sender/recipient pair per 60 seconds. This workflow only sends one message per failed payment per customer, so we should not hit it under normal usage. Just surface the Linq error if it ever does fire.
- Output of the workflow run: a small JSON object with { invoice_id, customer_id, action: "sent" | "skipped:no_phone" | "skipped:unreachable", chat_id (if sent), reason (if skipped) }. This makes it easy to glance at the runs and see what happened.
Additional information
What does this prompt do?
- Listens for failed Stripe payments and reacts within seconds, no inbox to babysit.
- Pulls the customer's name, phone number, and a one-tap link to update their card.
- Sends a short, friendly text from your Linq number, delivered as iMessage when possible and SMS otherwise.
- Quietly skips customers with no phone on file or numbers in regions Linq can't reach, so the workflow never fails noisily.
What do I need to use this?
- A Stripe account with the failing customers and invoices in it.
- A Linq account with at least one phone number provisioned for sending.
- Customer phone numbers saved on their Stripe profile in international format. Customers without a phone are skipped automatically.
How can I customize it?
- The wording of the recovery text: greeting, tone, and the opt-out line at the end.
- Which Linq sender number to use if you have more than one number on your account.
- Whether to also post an internal note in Slack each time a text goes out or a customer is skipped.
Frequently asked questions
Why text customers instead of relying on Stripe's dunning emails?
What happens if a customer doesn't have a phone number on file in Stripe?
Will this work for international customers?
How fast does the text go out after the payment fails?
Does the customer pay anything to receive the text?
Stop losing revenue to dunning emails nobody opens.
Connect Stripe and Linq once, and Geni texts every customer with a failed payment in seconds.