Messaging Me

Use caseFewer subscriptions lost to a declined card, with a WhatsApp message.

When Stripe reports a failed payment, your app sends the user a WhatsApp message with the link to their billing page. They update their card before losing access.

The welcome, then the recovery: 38 seconds.

From the request in Claude Code to the successful payment, on a real WhatsApp conversation. The same film first shows the welcome at sign-up.

How it flows.

The failed payment, from Stripe to the WhatsApp messageStripeinvoice.payment_failedthe payment failsYour appits Stripe webhookone key per invoicePOST /v1/sendsOn their WhatsAppthe billing link
Stripe sends invoice.payment_failed to your app’s webhook, which finds the user and sends the template with POST /v1/sends, with one idempotency key per invoice.

Step by step, for real.

  1. 1

    The failed payment template

    Claude Code creates it with create_template, in the utility category: an alert on the account. The first name, and an “Update my card” button to your billing page; get_template_status confirms the approval.

  2. 2

    The Stripe webhook you already have

    On the invoice.payment_failed event, once Stripe’s signature is checked, your app finds the user behind the Stripe customer.

  3. 3

    The send

    It sends the template with POST /v1/sends, with an idempotency key taken from the invoice: the same event delivered twice within 24 hours sends one message.

  4. 4

    The card updated

    The user taps the button and updates their card on your billing page, before losing access.

What you type in Claude Code

With the plugin installed, one sentence is enough. The film’s also wires the welcome at sign-up: Claude Code creates both templates, writes the code and tests.

/messagingme:demarrer at sign-up (app/signup.ts), a whatsapp welcome with the link to create their first schedule. and when stripe reports a failed payment, a whatsapp with the link to update their card

The Stripe webhook, as Claude Code writes it

import { messagingme } from '../../../lib/messagingme';
import { userOfCustomer, verifiedStripeEvent } from '../../../lib/billing';

// Your Stripe webhook, the one you already have. The template payment_failed is UTILITY (an account alert): one
// variable, the first name, and a URL button to your billing page.
export async function POST(req: Request) {
  const event = await verifiedStripeEvent(req);
  if (!event) return new Response(null, { status: 400 });
  if (event.type === 'invoice.payment_failed') {
    const invoice = event.data.object;
    const user = await userOfCustomer(invoice.customer);
    if (user) {
      // A failed WhatsApp send never fails the Stripe webhook: Stripe would retry it, then disable it.
      try {
        const send = await messagingme.POST('/v1/sends', {
          body: {
            target: { template: { name: 'payment_failed', language: 'en' } },
            recipients: [{ phone: user.phone, variables: { firstName: user.firstName } }],
            params: [{ position: 1, source: { type: 'variable', key: 'firstName' } }],
          },
          // Stripe may deliver the same event again: within 24 hours, one message per invoice.
          idempotencyKey: `payment-${invoice.id}`,
        });
        // A refused recipient (STOP, plan limit) is not an error: it is listed in skipped, with its reason.
        if (send.skippedTotal > 0) console.warn(`payment ${invoice.id} not sent: ${send.skipped[0]?.reason}`);
      } catch (e) {
        console.error(`payment ${invoice.id}: WhatsApp send failed`, e);
      }
    }
  }
  return new Response(null, { status: 200 });
}

app/api/stripe/route.ts · all the code in the guide

What you pay.

  • The Free plan is enough to start: 1,000 templates sent a month and 100 contacts, the API and the MCP server included; beyond that, Pro.
  • Meta bills your business directly for each utility template, according to its rate card and the user’s country.

Frequently asked questions.

Is a Messaging Me webhook address needed?

No: everything starts from the Stripe webhook your app already has, and nothing comes back to it.

What if Meta reclassifies the template as marketing?

It would then only go to contacts who consented. Keep a factual text: the payment, the card, the access.

How much does a recovery message cost?

Free includes 1,000 templates a month. Meta bills each utility template to your business, according to its rate card and the user’s country.

Can Stripe send the same event twice?

Yes, and the idempotency key taken from the invoice covers it: within 24 hours, one message goes out. And a failed WhatsApp send never fails your Stripe webhook.

Must the user have agreed to receive messages?

Meta asks that the person agreed to be contacted on WhatsApp: ask for it at sign-up or in their account. A user who replies STOP receives nothing more.

Recover your failed payments today.

The plugin in two commands, then the sentence above in Claude Code. No account to create.

Get started with Claude Code · Pricing · All use cases