diff --git a/stripe_checkout/settings/base.py b/stripe_checkout/settings/base.py
index 798ff849cc3e700f73d5bf6918cd4b1ef22cc3cc..10bf54f2e047202171b4ee9a9ca2ea0b9f7fa2e9 100644
--- a/stripe_checkout/settings/base.py
+++ b/stripe_checkout/settings/base.py
@@ -136,3 +136,5 @@ LOGGING = {
         "level": "INFO",
     },
 }
+
+STRIPE_WEBHOOK_ALLOWED_IPS = ["*"]
diff --git a/stripe_checkout/settings/prod.py b/stripe_checkout/settings/prod.py
index d4f7007b270d61ed96881ab80b7650ed0de2d819..6edf70c831cfbfaa7276a1904e6723c48394f38d 100644
--- a/stripe_checkout/settings/prod.py
+++ b/stripe_checkout/settings/prod.py
@@ -30,3 +30,18 @@ STATIC_URL = os.getenv("STATIC_URL", "/static/")  # noqa: F405
 STATIC_ROOT = os.getenv("STATIC_ROOT", "staticfiles/")  # noqa: F405
 SESSION_COOKIE_SECURE = True
 CSRF_COOKIE_SECURE = True
+
+STRIPE_WEBHOOK_ALLOWED_IPS = [
+    "3.18.12.63",
+    "3.130.192.231",
+    "13.235.14.237",
+    "13.235.122.149",
+    "18.211.135.69",
+    "35.154.171.200",
+    "52.15.183.38",
+    "54.88.130.119",
+    "54.88.130.237",
+    "54.187.174.169",
+    "54.187.205.235",
+    "54.187.216.72",
+]
diff --git a/stripe_checkout/stripe_checkout/visit_views.py b/stripe_checkout/stripe_checkout/visit_views.py
index 01824d72f4630ea8550e434e5e6014c96769e6bb..463e715864f494348820b9e444483e308f83a0d8 100644
--- a/stripe_checkout/stripe_checkout/visit_views.py
+++ b/stripe_checkout/stripe_checkout/visit_views.py
@@ -1,16 +1,17 @@
 import logging
 from typing import Union
+
+import requests
 from django import forms
 from django.http import Http404, HttpResponse
 from django.shortcuts import redirect, render
-from django.views.decorators.http import require_POST, require_http_methods, require_GET
 from django.views.decorators.csrf import csrf_exempt
-import requests
+from django.views.decorators.http import require_GET, require_http_methods, require_POST
 
-from stripe_checkout.stripe_checkout.shopping_cart import ShoppingCart
-
-from .models import Event, ExchangeRate
 from . import stripe
+from .models import Event, ExchangeRate
+from .shopping_cart import ShoppingCart
+from .utils import whitelist_ips
 from .visit import VisitorAPI
 
 logger = logging.getLogger(__name__)
@@ -67,7 +68,7 @@ def create_invoice(visitor, data):
         customer,
         purchase_order=data["purchase_order"],
         vat_number=data["vat_number"],
-        gbp_exchange_rate=exchange_rate
+        gbp_exchange_rate=exchange_rate,
     )
 
 
@@ -88,6 +89,7 @@ def checkout_success(request, visitor_id):
 
 @csrf_exempt
 @require_POST
+@whitelist_ips(by_setting="STRIPE_WEBHOOK_ALLOWED_IPS")
 def stripe_event(request):
     try:
         event = stripe.read_event(request.body, request.headers.get("Stripe-Signature"))
diff --git a/test/test_visit.py b/test/test_visit.py
index 7767f5583aab0f6a661ea17d485c67dab98ad04f..535a93d969f115157e260432a486b8d9cd7ee308 100644
--- a/test/test_visit.py
+++ b/test/test_visit.py
@@ -43,7 +43,7 @@ def test_exchange_rate(client, default_exchange_rate, visitor_id):
     call_args = stripe.Invoice.create.call_args[1]
     assert call_args["custom_fields"][0] == {
         "name": "GBP VAT Rate",
-        "value": "GBP 1.60 (0.8000)" ,
+        "value": "GBP 1.60 (0.8000)",
     }
 
 
@@ -62,3 +62,23 @@ def test_event_webhook(client):
         )
     assert rv.status_code == 200
     assert Event.objects.exists()
+
+
+@responses.activate
+@pytest.mark.django_db
+def test_event_webhook_disallowed_when_not_whitelisted(client, settings):
+    settings.STRIPE_WEBHOOK_ALLOWED_IPS = ["1.1.1.1"]
+    with patch(
+        "stripe.Webhook.construct_event", side_effect=lambda b, *_: json.loads(b)
+    ):
+        rv = client.post(
+            "/stripe-event-webhook/",
+            json.dumps(
+                {
+                    "type": "invoice.paid",
+                    "data": {"object": {"id": "stripe-invoice"}},
+                }
+            ),
+            content_type="application/json",
+        )
+    assert rv.status_code == 403