Django, stripe and webhook : {"error": "Missing stripe signature"}

I need your help. I'm trying to set up a striped payment system in the django app. However, I can't seem to connect the webhook to my logic. In addition, the handle_checkout_session function which should send a message after the success of each payment does not send any message.

def stripe_config(request):
    if request.method == 'GET':
        stripe_config = {'publicKey': settings.STRIPE_PUBLIC_KEY}
        return JsonResponse(stripe_config, safe=False)

login_required(login_url="login")
def stripe_payment(request):
    if request.method == 'GET':
        domain_url = getattr(settings, 'DOMAIN_URL')
        success_url = domain_url + reverse('stripe_success') + '?session_id={CHECKOUT_SESSION_ID}'
        cancel_url = domain_url + reverse('stripe_cancel')
        stripe.api_key = settings.STRIPE_SECRET_KEY
        order_id = request.GET.get('order_id')

        try:
            order = Order.objects.get(user=request.user, is_ordered=False, order_number=order_id)
            checkout_session = stripe.checkout.Session.create(
                client_reference_id=request.user.id if request.user.is_authenticated else None,
                success_url=success_url,
                cancel_url=cancel_url,
                payment_method_types=['card'],
                mode='payment',
                line_items=[
                    {
                        'price_data': {
                            'currency': 'eur',
                            'unit_amount': int(order.order_total * 100),
                            'product_data': {
                                'name': "Buy now",
                            },
                        },
                        'quantity': 1,
                    }
                ]
            )

            return JsonResponse({
                'sessionId': checkout_session['id']
            })
        except Order.DoesNotExist:
            return JsonResponse({
                'error': 'Order does not exist or has already been processed.'
            }, status=404)
        except stripe.error.StripeError as e:
            return JsonResponse({
                'error': str(e)
            }, status=500)

    return JsonResponse({'error': 'Invalid request method.'}, status=400)

@csrf_exempt
def stripe_webhook(request):
    stripe.api_key = settings.STRIPE_SECRET_KEY
    endpoint_secret = settings.STRIPE_WEBHOOK_SECRET

    payload = request.body
    sig_header = request.META.get('HTTP_STRIPE_SIGNATURE')
    print(sig_header)

    if sig_header is None:
        return JsonResponse({'error': 'Missing stripe signature'}, status=400)

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, endpoint_secret
        )
    except ValueError as e:
        return JsonResponse({'error': str(e)}, status=400)
    except stripe.error.SignatureVerificationError as e:
        return JsonResponse({'error': str(e)}, status=400)

    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        handle_checkout_session(session)

    return JsonResponse({'status': 'success'}, status=200)

def handle_checkout_session(session):
    try:
        order = Order.objects.get(payment__payment_id=session['id'])
        order.is_ordered = True
        order.save()

        ordered_products = OrderProduct.objects.filter(order_id=order.id)
        subtotal = 0
        tax = 0
        taxdhl = 0
        grand_total = 0
        grand_total_dhl = 0

        for i in ordered_products:
            subtotal += i.product_price * i.quantity
            tax += (2*subtotal)/100
            taxdhl = 1
            grand_total += subtotal + tax
            grand_total_dhl += grand_total + taxdhl

        user = order.user
        current_site = get_current_site(None)
        mail_subject = 'Thank you for your order!'
        message = render_to_string('orders/order_received_email.html', {
            'user': user,
            'order': order,
            'grand_total': grand_total,
            'grand_total_dhl': grand_total_dhl,
            'ordered_products': ordered_products,
            'tax': tax, 
            'taxdhl': taxdhl,
            'domain': current_site.domain,
            'uid': urlsafe_base64_encode(force_bytes(user.pk)),
            'token': default_token_generator.make_token(user),
        })

        from_email = 'Parisianist <customercare@parisianist.fr>'
        to_email = user.email

        mail = Mail(
            from_email=Email(from_email),
            to_emails=to_email,
            subject=mail_subject,
            html_content=message
        )

        try:
            sg = sendgrid.SendGridAPIClient(api_key=settings.SENDGRID_API_KEY)
            response = sg.send(mail)
            print(f"SendGrid Response Status Code: {response.status_code}")
            print(f"SendGrid Response Body: {response.body.decode('utf-8') if response.body else 'No Body'}")
            print(f"SendGrid Response Headers: {response.headers}")
        except Exception as e:
            print(f"An error occurred while sending email: {e}")

    except Order.DoesNotExist:
        pass

I don't know where the error is coming from. Your help will be welcome.

When your Webhook handler code receives the Webhook Event it is throwing the error you see. you can see it in your code:

if sig_header is None:
        return JsonResponse({'error': 'Missing stripe signature'}, status=400)

So you need to debug why the signature is null there -- I'd print out request.META to see what properties that contains and ensure you see the signature there and you are retrieving it correctly.

Back to Top