L.S.
I am working on my first Django project and struggling with the Stripe integration. My webhook is acting inconsistently—it worked fine when running locally on localhost with the Stripe CLI. However, after deploying with Nginx and Gunicorn, it has become unreliable. Sometimes it goes through, but in most cases, I receive a 500 status code.
I want to send an email to the customer with a PDF attachment when the checkout.sessionpleted
webhook is triggered. I read that the webhook should return a 200 status code as quickly as possible; otherwise, Stripe might time out. Or could the issue be caused by a time difference between the request and the server?
Regardless, I’m unsure how to properly fix this. I’d really appreciate any guidance from someone with experience.
import datetime
import stripe
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from webshop.models import Product, Customer, Order, OrderItem
from django.core.mail import EmailMessage
@csrf_exempt
def stripe_webhook(request):
payload = request.body
sig_header = request.META.get("HTTP_STRIPE_SIGNATURE")
endpoint_secret = settings.STRIPE_WEBHOOK_SECRET
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": "Invalid signature"}, status=400)
# Handle checkout success
if event["type"] == "checkout.sessionpleted":
session = event["data"]["object"]
session_id = session["id"]
# Fetch line items from Stripe
line_items = stripe.checkout.Session.list_line_items(session_id)
# Extract order details
customer_email = session.get("customer_details").get("email")
customer_name = session.get("customer_details").get("name")
amount_total = session.get("amount_total") / 100
payment_status = session.get("payment_status") == "paid"
# Get or create customer
customer, created = Customer.objects.get_or_create(email=customer_email, defaults={"name": customer_name})
# Create new order
order = Order.objects.create(
customer=customer,
date_ordered=datetime.datetime.now(),
payment_status=payment_status,
total_price=amount_total,
)
ordered_products = [] # Store product names for email
# Add order items
for item in line_items["data"]:
product_name = item["description"]
quantity = item["quantity"]
# Get product from database
try:
product = Product.objects.get(name=product_name)
OrderItem.objects.create(order=order, product=product, quantity=quantity)
ordered_products.append(product_name)
except Product.DoesNotExist:
print(f"⚠️ Product '{product_name}' not found in database, skipping.")
print(f"✅ Order created: {order}")
if ordered_products:
send_email_with_pdf(ordered_products, customer_email)
return JsonResponse({"status": "Order created"}, status=201)
return JsonResponse({"status": "success"}, status=200)
def send_email_with_pdf(product_name_list, recipient_email):
try:
email = EmailMessage(
subject='Your PDF(s)',
body='Please find the attached PDFs.',
from_email='[email protected]',
to=[recipient_email],
)
# Attach multiple PDFs
for name in product_name_list:
try:
product_obj = Product.objects.get(name=name)
if product_obj.remschema:
pdf_name = product_obj.remschema.name
pdf_content = product_obj.remschema.read()
email.attach(pdf_name, pdf_content, 'application/pdf')
except Product.DoesNotExist:
print(f"Product '{name}' not found.")
# Send the email only if there are attachments
if email.attachments:
email.send()
return "Email sent successfully!"
else:
return "No PDFs found to send."
except Product.DoesNotExist:
print("Product nog found")
return "PDF not found."
except Exception as e:
print(f"Error: {e}")
return f"Error: {e}"
stripe dashboard sc
I have the feeling that maybe the view is to slow?
L.S.
I am working on my first Django project and struggling with the Stripe integration. My webhook is acting inconsistently—it worked fine when running locally on localhost with the Stripe CLI. However, after deploying with Nginx and Gunicorn, it has become unreliable. Sometimes it goes through, but in most cases, I receive a 500 status code.
I want to send an email to the customer with a PDF attachment when the checkout.sessionpleted
webhook is triggered. I read that the webhook should return a 200 status code as quickly as possible; otherwise, Stripe might time out. Or could the issue be caused by a time difference between the request and the server?
Regardless, I’m unsure how to properly fix this. I’d really appreciate any guidance from someone with experience.
import datetime
import stripe
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from webshop.models import Product, Customer, Order, OrderItem
from django.core.mail import EmailMessage
@csrf_exempt
def stripe_webhook(request):
payload = request.body
sig_header = request.META.get("HTTP_STRIPE_SIGNATURE")
endpoint_secret = settings.STRIPE_WEBHOOK_SECRET
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": "Invalid signature"}, status=400)
# Handle checkout success
if event["type"] == "checkout.sessionpleted":
session = event["data"]["object"]
session_id = session["id"]
# Fetch line items from Stripe
line_items = stripe.checkout.Session.list_line_items(session_id)
# Extract order details
customer_email = session.get("customer_details").get("email")
customer_name = session.get("customer_details").get("name")
amount_total = session.get("amount_total") / 100
payment_status = session.get("payment_status") == "paid"
# Get or create customer
customer, created = Customer.objects.get_or_create(email=customer_email, defaults={"name": customer_name})
# Create new order
order = Order.objects.create(
customer=customer,
date_ordered=datetime.datetime.now(),
payment_status=payment_status,
total_price=amount_total,
)
ordered_products = [] # Store product names for email
# Add order items
for item in line_items["data"]:
product_name = item["description"]
quantity = item["quantity"]
# Get product from database
try:
product = Product.objects.get(name=product_name)
OrderItem.objects.create(order=order, product=product, quantity=quantity)
ordered_products.append(product_name)
except Product.DoesNotExist:
print(f"⚠️ Product '{product_name}' not found in database, skipping.")
print(f"✅ Order created: {order}")
if ordered_products:
send_email_with_pdf(ordered_products, customer_email)
return JsonResponse({"status": "Order created"}, status=201)
return JsonResponse({"status": "success"}, status=200)
def send_email_with_pdf(product_name_list, recipient_email):
try:
email = EmailMessage(
subject='Your PDF(s)',
body='Please find the attached PDFs.',
from_email='[email protected]',
to=[recipient_email],
)
# Attach multiple PDFs
for name in product_name_list:
try:
product_obj = Product.objects.get(name=name)
if product_obj.remschema:
pdf_name = product_obj.remschema.name
pdf_content = product_obj.remschema.read()
email.attach(pdf_name, pdf_content, 'application/pdf')
except Product.DoesNotExist:
print(f"Product '{name}' not found.")
# Send the email only if there are attachments
if email.attachments:
email.send()
return "Email sent successfully!"
else:
return "No PDFs found to send."
except Product.DoesNotExist:
print("Product nog found")
return "PDF not found."
except Exception as e:
print(f"Error: {e}")
return f"Error: {e}"
stripe dashboard sc
I have the feeling that maybe the view is to slow?
Share asked Mar 10 at 21:19 TSG16TSG16 11 Answer
Reset to default 0Its hard to know where something went wrong just based on this - could you get some logging going - maybe even with something like Sentry so you can easily see if there is anything going unhandled? then share here.
That being said, there are some easy performance improvements you can make here. Without knowing about your DB, rest of infrastructure, how many order items etc that we are iterating through, I don't know if they will be causing this issue. You should still look at making them though.
- look into making one query in your main view for the products. rather than
.get()
n
amount of times based on yourline_items
, grab all of those product names and do one query -Product.objects.filter(name__in=[YOUR_NAMES])
. iterate over them for yourOrderItem
stuff if you need to - you can get all the products you need with that ^
filter()
and pass the products as a queryset to thesend_email_with_pdf
function. That will prevent you having to do do all those.get()
calls again in there, each of which are DB hits. - in your view, each of your
OrderItem.objects.create()
calls are also new queries. instead. everytime you iterate here, instantiate anOrderItem
with your data and append it to a list. Then when you're done, callOrderItem.objects.bulk_create([YOUR_ORDER_ITEM_LIST])
with your list of instances. Again this will be just one db hit instead ofn
These 3 ideas will drastically improve your performance of this view, especially if you are dealing with a lot of products/items here. That being said, more logging will help and you might find that you need to move this email sending logic to something in the background - Celery, etc