1

I want to run a Firebase cloud function everytime a user is charged by Stripe's subscription extension. Is there any event that is generated by that extension that can trigger a cloud function, such as a write to Firestore?

My scenario is that I want to generate a new document in an Orders collection whenever a user is successfully charged that references the corresponding User document.

Scott McCartney
  • 153
  • 1
  • 8

2 Answers2

1

I was able to solve this myself by borrowing some code from the official repo for Stripe's Firebase extension here: https://github.com/stripe/stripe-firebase-extensions/blob/next/firestore-stripe-subscriptions/functions/src/index.ts

I made my own Firebase function and called it handleInvoiceWebhook that validated and constructed a Stripe Invoice object, mapped it to a custom Invoice interface I made with the fields I cared about, then saved that to an invoices collection.

export const handleInvoiceWebhook = functions.https.onRequest(
  async (req: functions.https.Request, resp) => {
    let event: Stripe.Event;
    try {
      event = stripe.webhooks.constructEvent(
        req.rawBody,
        req.headers['stripe-signature'] || '',
        functions.config().stripe.secret
      );
    } catch (error) {
      resp.status(401).send('Webhook Error: Invalid Secret');
      return;
    }
    const invoice = event.data.object as Stripe.Invoice;
    const customerId= invoice.customer as string;

    await insertInvoiceRecord(invoice, customerId);
    resp.status(200).send(invoice.id);
  }
);

/**
 * Create an Invoice record in Firestore when a customer's monthly subscription payment succeeds.
 */
const insertInvoiceRecord = async (
  invoice: Stripe.Invoice,
  customerId: string
): Promise<void> => {
  // Invoice is an interface with only fields I care about
  const invoiceData: Invoice = {
    invoiceId: invoice.id,
    ...map invoice data here
  };
  await admin
    .firestore()
    .collection('invoices')
    .doc(invoice.id)
    .set(invoiceData);
};

Once deployed, I went to the Stripe developer dashboard (https://dashboard.stripe.com/test/webhooks) and added a new Webhook listening for the Event type invoice.payment_succeeded and with the url being the Firebase function I just made.

NOTE: I had to deploy my Stripe API key and Webhook Secret as enviroment variables for my Firebase function with the following command: firebase functions:config:set stripe.key="sk_test_123" stripe.secret="whsec_456"

Scott McCartney
  • 153
  • 1
  • 8
0

Unfortunately it doesn't look like the extension handles the ongoing payment events: https://github.com/stripe/stripe-firebase-extensions/blob/master/firestore-stripe-subscriptions/functions/src/index.ts#L419-L432

You'd either need to modify that code to include likely invoice.payment_succeeded - and then handle appropriately - or write a cloud function to handle that yourself (similar to what's shown there).

floatingLomas
  • 8,553
  • 2
  • 21
  • 27
  • That's good to know, I made a feature request in their Github repo to hopefully support that event as part of the extension in the future: https://github.com/stripe/stripe-firebase-extensions/issues/124 – Scott McCartney Jan 18 '21 at 03:46