(request: HttpRequest)
return HttpResponse(status=200)
After checkout, Stripe sends a checkout.session.completed event. Stripe will
    wait up to 10 seconds for this webhook to return before redirecting a user
    back to the return URL.

    https://stripe.com/docs/billing/webhooks
After checkout, Stripe sends a checkout.session.completed event. Stripe will
    wait up to 10 seconds for this webhook to return before redirecting a user
    back to the return URL.
After checkout Stripe sends a checkout . session . completed event . Stripe will wait up to 10 seconds for this webhook to return before redirecting a user back to the return URL .
def stripe_webhook_handler(request: HttpRequest) -> HttpResponse:
    """
    After checkout, Stripe sends a checkout.session.completed event. Stripe will
    wait up to 10 seconds for this webhook to return before redirecting a user
    back to the return URL.

    https://stripe.com/docs/billing/webhooks
    """
    sig_header = request.META["HTTP_STRIPE_SIGNATURE"]
    try:
        event = stripe.Webhook.construct_event(
            payload=request.body,
            sig_header=sig_header,
            secret=settings.STRIPE_WEBHOOK_SECRET,
        )
    except ValueError:
        # Invalid payload
        logger.warning("problem parsing stripe payload", exc_info=True)
        raise BadRequest
    except stripe.error.SignatureVerificationError:
        logger.warning("invalid signature for webhook request", exc_info=True)
        raise BadRequest

    # https://stripe.com/docs/billing/lifecycle#subscription-lifecycle

    # triggered when a customer completes the Stripe Checkout form.
    # https://stripe.com/docs/payments/checkout/fulfillment#webhooks
    if event.type == "checkout.session.completed":
        # Stripe will wait until this webhook handler returns to redirect from checkout
        checkout_session = event.data.object
        if checkout_session.mode == "setup":
            # a setup checkout session occurs when a user updates their payment
            # method or billing email. We update the associated account and
            # stripe_customer_info on this event. Setup should occur after a
            # subscription has been created.
            account = Account.objects.get(id=checkout_session.client_reference_id)
            account.update_customer(checkout_session.customer)
            stripe_customer_info = account.stripe_customer_info()
            if stripe_customer_info is None:
                logger.warning("expected account %s to have customer info", account)
                return HttpResponse(status=200)
            stripe_customer_info.update_from_stripe()
        elif checkout_session.mode == "subscription":
            # subscription occurs after a user creates a subscription through
            # the checkout.
            account = Account.objects.get(id=checkout_session.client_reference_id)
            account.update_customer(checkout_session.customer)

            try:
                stripe_customer_info = StripeCustomerInformation.objects.get(
                    customer_id=account.stripe_customer_id
                )
            except StripeCustomerInformation.DoesNotExist:
                stripe_customer_info = StripeCustomerInformation(
                    customer_id=account.stripe_customer_id
                )
            stripe_customer_info.update_from_stripe()
        else:
            raise BadRequest
        # Then define and call a method to handle the successful payment intent.
        # handle_payment_intent_succeeded(payment_intent)
    elif event.type == "invoice.payment_succeeded":
        # triggered whenever a subscription is paid. We need to update the
        # subscription to have the correct period information.
        invoice = event.data.object
        if not invoice.paid:
            logger.warning("invoice not paid %s", event)
            return HttpResponse(status=200)
        stripe_customer: Optional[
            StripeCustomerInformation
        ] = StripeCustomerInformation.objects.filter(
            customer_id=invoice.customer
        ).first()
        if stripe_customer is None:
            logger.warning(
                "expected invoice to have corresponding StripeCustomerInformation"
            )
            raise BadRequest
        stripe_customer.update_from_stripe()
    elif event.type == "customer.subscription.deleted":
        # I don't think we need to do anything on subscription deletion. We can
        # let the subscription time run out.
        pass
    elif event.type == "invoice.payment_action_required":
        logger.warning("more action required for payment %s", event)
    elif event.type == "invoice.payment_failed":
        logger.warning("invoice.payment_failed %s", event)
    elif event.type == "customer.updated":
        stripe_customer_info = StripeCustomerInformation.objects.filter(
            customer_id=event.data.object.id
        ).first()
        if stripe_customer_info is None:
            logger.warning("customer.update event for unknown customer %s", event)
            raise BadRequest
        stripe_customer_info.update_from_stripe()

    elif event.type == "payment_method.attached":
        # a customer should only have one payment method.
        #
        # When a customer attaches a new payment method, remove the old ones to
        # ensure subscriptions use the newly added method.
        new_payment_method = event.data.object

        payment_methods = stripe.PaymentMethod.list(
            customer=new_payment_method.customer, type="card",
        )
        for payment_method in payment_methods.data:
            if payment_method.id != new_payment_method.id:
                stripe.PaymentMethod.detach(payment_method.id)

        stripe.Customer.modify(
            new_payment_method.customer,
            invoice_settings=dict(default_payment_method=new_payment_method.id),
        )
        stripe_customer_info = StripeCustomerInformation.objects.filter(
            customer_id=new_payment_method.customer
        ).first()
        if stripe_customer_info is None:
            logger.warning(
                "payment_method.attached event for unknown customer %s", event
            )
            raise BadRequest
        stripe_customer_info.update_from_stripe()

    else:
        logger.warning("unexpected event type %s", event.type)
        raise BadRequest

    return HttpResponse(status=200)
def stripe_webhook_handler ( request : HttpRequest ) -> HttpResponse : sig_header = request . META [ "HTTP_STRIPE_SIGNATURE" ] try : event = stripe . Webhook . construct_event ( payload = request . body , sig_header = sig_header , secret = settings . STRIPE_WEBHOOK_SECRET , ) except ValueError : # Invalid payload logger . warning ( "problem parsing stripe payload" , exc_info = True ) raise BadRequest except stripe . error . SignatureVerificationError : logger . warning ( "invalid signature for webhook request" , exc_info = True ) raise BadRequest # https://stripe.com/docs/billing/lifecycle#subscription-lifecycle # triggered when a customer completes the Stripe Checkout form. # https://stripe.com/docs/payments/checkout/fulfillment#webhooks if event . type == "checkout.session.completed" : # Stripe will wait until this webhook handler returns to redirect from checkout checkout_session = event . data . object if checkout_session . mode == "setup" : # a setup checkout session occurs when a user updates their payment # method or billing email. We update the associated account and # stripe_customer_info on this event. Setup should occur after a # subscription has been created. account = Account . objects . get ( id = checkout_session . client_reference_id ) account . update_customer ( checkout_session . customer ) stripe_customer_info = account . stripe_customer_info ( ) if stripe_customer_info is None : logger . warning ( "expected account %s to have customer info" , account ) return HttpResponse ( status = 200 ) stripe_customer_info . update_from_stripe ( ) elif checkout_session . mode == "subscription" : # subscription occurs after a user creates a subscription through # the checkout. account = Account . objects . get ( id = checkout_session . client_reference_id ) account . update_customer ( checkout_session . customer ) try : stripe_customer_info = StripeCustomerInformation . objects . get ( customer_id = account . stripe_customer_id ) except StripeCustomerInformation . DoesNotExist : stripe_customer_info = StripeCustomerInformation ( customer_id = account . stripe_customer_id ) stripe_customer_info . update_from_stripe ( ) else : raise BadRequest # Then define and call a method to handle the successful payment intent. # handle_payment_intent_succeeded(payment_intent) elif event . type == "invoice.payment_succeeded" : # triggered whenever a subscription is paid. We need to update the # subscription to have the correct period information. invoice = event . data . object if not invoice . paid : logger . warning ( "invoice not paid %s" , event ) return HttpResponse ( status = 200 ) stripe_customer : Optional [ StripeCustomerInformation ] = StripeCustomerInformation . objects . filter ( customer_id = invoice . customer ) . first ( ) if stripe_customer is None : logger . warning ( "expected invoice to have corresponding StripeCustomerInformation" ) raise BadRequest stripe_customer . update_from_stripe ( ) elif event . type == "customer.subscription.deleted" : # I don't think we need to do anything on subscription deletion. We can # let the subscription time run out. pass elif event . type == "invoice.payment_action_required" : logger . warning ( "more action required for payment %s" , event ) elif event . type == "invoice.payment_failed" : logger . warning ( "invoice.payment_failed %s" , event ) elif event . type == "customer.updated" : stripe_customer_info = StripeCustomerInformation . objects . filter ( customer_id = event . data . object . id ) . first ( ) if stripe_customer_info is None : logger . warning ( "customer.update event for unknown customer %s" , event ) raise BadRequest stripe_customer_info . update_from_stripe ( ) elif event . type == "payment_method.attached" : # a customer should only have one payment method. # # When a customer attaches a new payment method, remove the old ones to # ensure subscriptions use the newly added method. new_payment_method = event . data . object payment_methods = stripe . PaymentMethod . list ( customer = new_payment_method . customer , type = "card" , ) for payment_method in payment_methods . data : if payment_method . id != new_payment_method . id : stripe . PaymentMethod . detach ( payment_method . id ) stripe . Customer . modify ( new_payment_method . customer , invoice_settings = dict ( default_payment_method = new_payment_method . id ) , ) stripe_customer_info = StripeCustomerInformation . objects . filter ( customer_id = new_payment_method . customer ) . first ( ) if stripe_customer_info is None : logger . warning ( "payment_method.attached event for unknown customer %s" , event ) raise BadRequest stripe_customer_info . update_from_stripe ( ) else : logger . warning ( "unexpected event type %s" , event . type ) raise BadRequest return HttpResponse ( status = 200 )