Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/hub/servers/app/webhooks/stripe.ts
Views: 687
/*1Stripe Webhook to handle some events:23- invoice.paid --4- customer.subscription.created -- used for the webhook side of @cocalc/server/purchases/stripe-usage-based-subscription.ts56We *do* check the stripe signature to only handle requests that actually come from stripe.7See https://stripe.com/docs/webhooks/signatures for where the code comes from.89To test this in dev you need to use the stripe cli, which is a big GO program.10For some reason the binary just hangs when trying to run it on cocalc.com (maybe11due to how locked down our Docker containers are?), so it also seems only12possible to test/debug this in cocalc-docker or somewhere else.13*/1415import { Router } from "express";16import { getLogger } from "@cocalc/hub/logger";17import { getServerSettings } from "@cocalc/database/settings/server-settings";18import getConn from "@cocalc/server/stripe/connection";19import {20createCreditFromPaidStripeInvoice,21createCreditFromPaidStripePaymentIntent,22} from "@cocalc/server/purchases/create-invoice";23import * as express from "express";24import { isValidUUID } from "@cocalc/util/misc";25import { setUsageSubscription } from "@cocalc/server/purchases/stripe-usage-based-subscription";2627const logger = getLogger("hub:stripe-webhook");2829export default function init(router: Router) {30router.post(31"/webhooks/stripe",32express.raw({ type: "application/json" }),33async (req, res) => {34logger.debug("POST");3536try {37await handleRequest(req);38} catch (err) {39const error = `Webhook Error: ${err.message}`;40logger.error(error);41console.error(error);42res.status(400).send(error);43return;44}4546// Return a 200 response to acknowledge receipt of the event47res.send();48}49);50}5152async function handleRequest(req) {53const { stripe_webhook_secret } = await getServerSettings();54const stripe = await getConn();55const sig = req.headers["stripe-signature"];56const event = stripe.webhooks.constructEvent(57req.body,58sig,59stripe_webhook_secret60);61logger.debug("event.type = ", event.type);6263// Handle the event64switch (event.type) {65case "invoice.paid":66const invoice = event.data.object;67// Then define and call a function to handle the event invoice.paid68logger.debug("invoice = ", invoice);69await createCreditFromPaidStripeInvoice(invoice);70break;7172case "payment_intent.succeeded":73// This is I think ONLY used for deprecated credit cards.74const intent = event.data.object;75logger.debug("intent = ", intent);76await createCreditFromPaidStripePaymentIntent(intent);77break;7879case "customer.subscription.created":80logger.debug("event = ", event);81const { id, object } = (event.data?.object ?? {}) as any;82if (object == "subscription") {83const { account_id, service } =84(event.data?.object as any)?.metadata ?? {};85if (isValidUUID(account_id) && service == "credit") {86await setUsageSubscription({ account_id, subscription_id: id });87}88}89break;9091default:92// we don't handle any other event types yet.93logger.debug(`Unhandled event type ${event.type}`);94// logger.debug(event);95}96}979899