LemonSqueezy webhook requests coming through as GET instead of POST, why?

81 Views Asked by At

I have a python/django app which is hosted on PythonAnywhere, DNS and SSL via Cloudflare, and using LemonSqueezy to process payments. Per the docs, LemonSqueezy should send a webhook via POST to the URL I have supplied when an order is created. They do indeed send a webhook, however it is a GET request with an empty body, and I cannot figure out why.

I am able to successfully send POST requests both to my local version and to my live version of the site with Postman, so I don't think its a configuration issue with my server. However, I am able to successfully receive the POST webhook on webhook.site (a site for testing webhooks). So I don't think the LemonSqueezy webhooks are broken, either.

I've tested several variations of Cloudflare-proxied DNS records with and without a Cloudflare SSL certificate, and with and without a Let's Encrypt SSL Certificate from Pythonanywhere. I've also tested various SSL/TLS modes. In all of the combinations that actually resulted in successful page loads, I consistently was able to get POST requests from Postman but only GET requests from LemonSqueezy. Don't think it's a code issue but including the debug code I'm using anyways.

@csrf_exempt
def lemonsqueezy(request):
    logging.info(f'Body: {request.body}')
    logging.info(f'Scheme: {request.scheme}')
    logging.info(f'Method: {request.method}')
1

There are 1 best solutions below

0
Poindexter Labs On

Solved this a few mins after posting, of course.

Django rewrites POST requests to GET if the URLs don't have a trailing slash to match the defined URL path, otherwise they are converted to GET requests, apparently. If you POST to example.com/my-webhook, but the path is defined as example.com/my-webhook/, the trailing slash will be added but it will become a get request.

There appears to be a way to change this behavior using the APPEND_SLASH setting in settings.py, or changing your urls.py route from path() to re_path() to make the slash optional... i.e.

re_path(r'my-webhook/?$', views.my_webhook, name="my-webhook")