diff --git a/pretix_matrix_inviter/signals.py b/pretix_matrix_inviter/signals.py
index 8ad373f74a9a4c4548f99105d155b4fa79d47574..a95afd93e8525ed052c6ef71d20738c12b00181b 100644
--- a/pretix_matrix_inviter/signals.py
+++ b/pretix_matrix_inviter/signals.py
@@ -1,11 +1,15 @@
+import json
 from django import forms
 from django.dispatch import receiver
 from django.urls import resolve, reverse
 from django.utils.translation import ugettext_lazy as _
 from pretix.base.settings import settings_hierarkey
+from pretix.base.signals import logentry_display, order_placed
 from pretix.control.signals import nav_event_settings
 from pretix.presale.signals import question_form_fields
 
+from .tasks import matrix_inviter_invite
+
 settings_hierarkey.add_default("matrix_inviter_items", [], list)
 settings_hierarkey.add_default("matrix_inviter_authorization_token", "", str)
 settings_hierarkey.add_default("matrix_inviter_matrix_server", "", str)
@@ -38,6 +42,29 @@ def add_matrix_id_question(sender, position, **kwargs):
     }
 
 
+@receiver(order_placed, dispatch_uid="matrix_inviter_order_placed")
+def order_placed(sender, order, **kwargs):
+    if (
+        not sender.settings.matrix_inviter_authorization_token
+        and not sender.settings.matrix_inviter_matrix_server
+        and not sender.settings.matrix_inviter_matrix_room
+    ):
+        return
+
+    for order_position in order.positions.all():
+        if str(order_position.item.pk) not in sender.settings.get(
+            "matrix_inviter_items"
+        ):
+            continue
+
+        if not order_position.meta_info_data.get("question_form_data", {}).get(
+            "matrix_inviter_matrix_id"
+        ):
+            continue
+
+        matrix_inviter_invite.apply_async(args=(sender.pk, order.pk, order_position.pk))
+
+
 @receiver(nav_event_settings, dispatch_uid="matrix_inviter_nav_settings")
 def navbar_settings(sender, request=None, **kwargs):
     url = resolve(request.path_info)
@@ -55,3 +82,21 @@ def navbar_settings(sender, request=None, **kwargs):
             and url.url_name == "settings",
         }
     ]
+
+
+@receiver(logentry_display, dispatch_uid="matrix_inviter_logentry_display")
+def logentry_display(sender, logentry, **kwargs):
+    if not logentry.action_type.startswith("pretix_matrix_inviter"):
+        return
+
+    locales = {
+        "pretix_matrix_inviter.invite_sent": _(
+            "{matrix_id} has been invited to {matrix_room}."
+        ),
+        "pretix_matrix_inviter.error": _(
+            "There was an error inviting {matrix_id} to {matrix_room}: {error}"
+        ),
+    }
+    data = json.loads(logentry.data)
+
+    return locales[logentry.action_type].format_map(data)
diff --git a/pretix_matrix_inviter/tasks.py b/pretix_matrix_inviter/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..44050b1e67a10ac5bfc36d9aac30f5afb466b782
--- /dev/null
+++ b/pretix_matrix_inviter/tasks.py
@@ -0,0 +1,68 @@
+import logging
+import requests
+from celery.exceptions import MaxRetriesExceededError
+from pretix.base.models import Event, Order, OrderPosition
+from pretix.base.services.tasks import TransactionAwareTask
+from pretix.celery_app import app
+
+logger = logging.getLogger(__name__)
+
+
+@app.task(
+    base=TransactionAwareTask,
+    bind=True,
+    max_retries=10,
+    retry_backoff=True,
+    retry_backoff_max=3600,
+)
+def matrix_inviter_invite(self, event: int, order: int, order_position: int):
+    order_position = OrderPosition.objects.get(pk=order_position)
+
+    user_matrix_id = order_position.meta_info_data.get("question_form_data", {}).get(
+        "matrix_inviter_matrix_id"
+    )
+
+    if not user_matrix_id:
+        return
+
+    event = Event.objects.get(pk=event)
+    order = Order.objects.get(pk=order)
+    room_matrix_id = event.settings.matrix_inviter_matrix_room
+
+    try:
+        r = requests.post(
+            "https://{}/_matrix/client/v3/rooms/{}/invite".format(
+                event.settings.matrix_inviter_matrix_server,
+                room_matrix_id,
+            ),
+            headers={
+                "Authorization": "Bearer {}".format(
+                    event.settings.matrix_inviter_authorization_token
+                ),
+            },
+            json={
+                "user_id": user_matrix_id,
+            },
+        )
+        r.raise_for_status()
+    except (requests.ConnectionError, requests.HTTPError) as e:
+        try:
+            self.retry()
+        except MaxRetriesExceededError:
+            order.log_action(
+                "pretix_matrix_inviter.error",
+                data={
+                    "matrix_id": user_matrix_id,
+                    "matrix_room": room_matrix_id,
+                    "error": "HTTP Code {}".format(r.status_code),
+                },
+            )
+            raise e
+
+    order.log_action(
+        "pretix_matrix_inviter.invite_sent",
+        data={
+            "matrix_id": user_matrix_id,
+            "matrix_room": room_matrix_id,
+        },
+    )