Search code examples
djangodjango-viewsstripe-paymentswebhooksdjango-sessions

How to save stripe webhook data to session variables in Django?


I am currently working on a 'success' page for my Django project (which uses Stripe to take payments). I would like to show their order total, with tax, on this page. My Stripe webhook is running and posting data, but for the life of me I can't use this data outside of the webhook's veiw. Normally, when I want to inform one view with data from another, I take advantage of Django's session variables. When I save the session variable, however, attempting to use it in my SuccessView returns 'None' rather than the value saved to it. Any help would be appreciated. Here is my relavent code:

views.py

def stripe_webhook(request):
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
        )
    except ValueError as e:
        # Invalid payload
        return HttpResponse(status=400)
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        return HttpResponse(status=400)

    # Handle the checkout.session.completed event
    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        customer_email = session["customer_details"]["email"]
        line_items = stripe.checkout.Session.list_line_items(session["id"])
        print(line_items)
        stripe_price_id = line_items["data"][0]["price"]["id"]
        price = Price.objects.get(stripe_price_id=stripe_price_id)
        total_paid_cents = line_items["data"][0]["amount_total"]
        total_paid_dollars = total_paid_cents / 100
        request.session['total_paid'] = total_paid_dollars
    return HttpResponse(status=200)

class SuccessView(TemplateView):
    template_name = "musicstudios/success.html"
    extra_context = sidebar_context
    def get_context_data(self, **kwargs):
        context = super(SuccessView, self).get_context_data(**kwargs)
        order_id = self.request.session.get('order_id')
        order = Order.objects.get(pk=order_id)
        product_id = order.product.id
        product = Product.objects.get(pk=product_id)
        customer = Customer.objects.get(pk=order.customer.id)
        total_paid = self.request.session.get('total_paid')
        print(total_paid)
        context['customer'] = customer
        context['product'] = product
        context['order'] = order
        context['order_total'] = total_paid
        return context

success.html

<div class="contentborder">
    <span class="mb-2">
        <span class="flex flex-col bg-slate-800 bg-opacity-25 border-slate-600 rounded-lg pl-4 pr-2 py-2 mt-2 mb-4">
            <span class="flex flex-row justify-between">
                <h3 class="text-xl font-bold mb-1">Order Details</h3>
            </span>
            <p class="py-1"><strong>Order total:</strong> ${{ order_total }}</p>
            <p class="py-1"><strong>Order includes:</strong> {{ order.price.price_description }}</p>
            {% if order.cust_requests %}
            <p class="py-1"><strong>Requests:</strong> {{ order.cust_requests }}</p>
            {% else %}
            <p class="py-1"><strong>Requests:</strong> No specific requests made.</p>
            {% endif %}
            {% if order.reference_track %}
            <p class="py-1"><strong>Reference track link:</strong> {{ order.reference_track }}
            {% else %}
            <p class="py-1"><strong>Reference track link:</strong> No reference track linked.</p>
            {% endif %}
            {% if order.music_file %}
            <p class="py-1"><strong>Music file:</strong> {{ order.music_file }}
            {% else %}
            <p class="py-1"><strong>Music file:</strong> No music file uploaded.</p>
            {% endif %}
            <p class="py-1"><strong>Order Date:</strong> {{ order.order_date }}
        </span>
    </span

Solution

  • When Stripe sends the Event to your webhook endpoint, it makes an HTTP request to your server. That request is completely unrelated to the request(s) made by your customer. You can't set something in the request's session for the webhook handler code that could then be shared with the success page's session itself. They are completely separate.

    The best option here is to handle this in your SuccessView too. You can look up the state of the Session itself using the Retrieve Checkout Session API during the redirect. Alternatively, you can store this information in your database when the webhook handler receives the Event and then have your SuccessView look at the state in your database.