diff --git a/pass/app/Order.js b/pass/app/Order.js
index 4b5e09d33315e0b5705ee3009a12884c0db7b1b4..67351cb9c4cc22501d86521b14ba5d363a91ad69 100644
--- a/pass/app/Order.js
+++ b/pass/app/Order.js
@@ -382,6 +382,47 @@ class Order {
       });
   }
 
+  async attachReceipt(blob) {
+    let civicrm_data = config.get("app.civicrm");
+    if (!civicrm_data.enabled) {
+      return;
+    }
+    console.log(this.#order_date.format("YYYY-MM-DD HH:mm:ss"));
+    return fetch(civicrm_data.url + "/Attachment/create", {
+      method: "post",
+      headers: {
+        "Content-Type": "application/x-www-form-urlencoded",
+        "X-Civi-Auth": `Bearer ${civicrm_data.api_key}`,
+      },
+      body:
+        "params=" +
+        encodeURIComponent(
+          JSON.stringify({
+            values: {
+              name: `INV_${this.getOrderID()}.pdf`,
+              mime_type: "application/pdf",
+              content: blob,
+              entity_table: "civicrm_contribution",
+              entity_id: this.#civicrm_contribution_id,
+            },
+          })
+        ),
+    })
+      .then((response) => {
+        console.log(response.status);
+        return response.json();
+        if (response.status !== 200) {
+          throw "Error Creating Civicrm Contribution";
+        } else {
+          return response.json();
+        }
+      })
+      .then((response_json) => {
+        console.log(JSON.stringify(response_json));
+        //this.#civicrm_contribution_id = response_json.values[0].id;
+      });
+  }
+
   async updateOrderLinkTTL() {
     let redis_key = Order.PURCHASE_LINK_ORDER_TO_KEY_PREFIX + this.#order_id;
 
diff --git a/pass/app/pdf/OrderReceipt.js b/pass/app/pdf/OrderReceipt.js
index 2a5534f1b4780c7d934e6893f40e796afcb5d329..aa8c6b42971d98e471c2d026a55b546f65207b05 100644
--- a/pass/app/pdf/OrderReceipt.js
+++ b/pass/app/pdf/OrderReceipt.js
@@ -6,15 +6,19 @@ class OrderReceipt {
    *
    * @param {Order} order
    */
-  static CREATE_ORDER_RECEIPT(order, target) {
+  static CREATE_ORDER_RECEIPT(order, invoice) {
     let letter_left_margin = OrderReceipt.CM_TO_POINTS(2.5, false);
     let letter_right_margin = OrderReceipt.CM_TO_POINTS(2, false);
 
     let PDFDocument = require("pdfkit");
+    let title = `Bestellung ${order.getOrderID()}`;
+    if (invoice) {
+      title = `Rechnung INV_${order.getOrderID()}`;
+    }
     const doc = new PDFDocument({
       size: "A4",
       info: {
-        Title: `Bestellung ${order.getOrderID()}`,
+        Title: title,
         Author: "SUMA-EV - Verein für freien Wissenszugang",
         Subject: "MetaGer Schlüssel: Suchanfragen (x300)",
       },
@@ -37,23 +41,33 @@ class OrderReceipt {
       .stroke();
 
     // Our Address Information
-    /*
-  doc
-    .fontSize(8)
-    .text(
-      "SUMA-EV | Röselerstraße 3 | 30159 Hannover | Deutschland",
-      OrderReceipt.CM_TO_POINTS(2, false),
-      OrderReceipt.CM_TO_POINTS(4.5, true),
-      {
-        width: OrderReceipt.CM_TO_POINTS(8.5, false),
-      }
-    );
-*/
+    if (invoice) {
+      console.log(invoice);
+      doc
+        .fontSize(8)
+        .text(
+          "SUMA-EV | Röselerstraße 3 | 30159 Hannover | Deutschland",
+          OrderReceipt.CM_TO_POINTS(2, false),
+          OrderReceipt.CM_TO_POINTS(4.5, true),
+          {
+            width: OrderReceipt.CM_TO_POINTS(8.5, false),
+          }
+        )
+        .moveDown()
+        .fontSize(10)
+        .text(invoice.name);
+      invoice.address.split("\r\n").forEach((line) => {
+        doc.text(line);
+      });
+    }
+
     // General Information
+    let text = invoice ? "Rechnung:" : "Bestellnummer:";
+    let number = invoice ? "INV_" + order.getOrderID() : order.getOrderID();
     doc
       .fontSize(12)
       .text(
-        "Bestellnummer: ",
+        text,
         OrderReceipt.CM_TO_POINTS(21 - 8.5, false),
         OrderReceipt.CM_TO_POINTS(5, true),
         {
@@ -63,7 +77,7 @@ class OrderReceipt {
         }
       )
       .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf")
-      .text(order.getOrderID(), { align: "right" })
+      .text(number, { align: "right" })
       .font("public/fonts/liberation-sans/LiberationSans-Regular.ttf")
       .text("Telefon:", {
         width: OrderReceipt.CM_TO_POINTS(7.5, false),
@@ -104,11 +118,13 @@ class OrderReceipt {
       )
       .strokeColor("#ff7f00")
       .stroke();
+
+    text = invoice ? "Rechnung" : "Auftragsbestätigung";
     doc
       .fontSize(12)
       .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf")
       .text(
-        "Auftragsbestätigung " + order.getOrderID(),
+        text + " " + number,
         OrderReceipt.CM_TO_POINTS(2.5, false),
         OrderReceipt.CM_TO_POINTS(9.846, true)
       );
@@ -189,6 +205,19 @@ class OrderReceipt {
         align: "right",
       })
       .font("public/fonts/liberation-sans/LiberationSans-Regular.ttf");
+    if (invoice) {
+      doc
+        .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf")
+        .text(
+          "Rechnungsbetrag dankend erhalten!",
+          OrderReceipt.CM_TO_POINTS(2.5, false),
+          OrderReceipt.CM_TO_POINTS(18, true),
+          {
+            align: "center",
+          }
+        )
+        .font("public/fonts/liberation-sans/LiberationSans-Regular.ttf");
+    }
 
     // Footer
     doc
diff --git a/pass/routes/authentication.js b/pass/routes/authentication.js
index 5f5d3b07a9a6647a9ab670645f798bd8d9cfd68b..c8c016da62aa82d342c68a832a10d4380d34586d 100644
--- a/pass/routes/authentication.js
+++ b/pass/routes/authentication.js
@@ -12,7 +12,7 @@ const session_prefix = "auth:";
  *
  * The authenticated user needs to be member of the group defined in the config
  *
- * You can call any url with the parameter moderate=true to trigger a login with
+ * You can call any url with the parameter moderation=true to trigger a login with
  * redirect to the same URL after successfull authentication or 401 error on
  * failed authentication.
  *
@@ -34,7 +34,7 @@ router.use(
     },
   }),
   (req, res, next) => {
-    if (req.query.moderate) {
+    if (req.query.moderation) {
       requiresAuth()(req, res, next);
     } else {
       next("route");
@@ -57,13 +57,17 @@ router.use(
       }
     }
 
-    if (req.query.moderate) {
+    if (req.query.moderation) {
       if (!req.data.admin) {
         res.locals.error = { status: 401 };
         res.locals.message = "Unauthorized";
         res.status(401).render("error");
       } else {
-        let redirect_url = req.originalUrl.replace(/moderate=true/, "");
+        let params = req.query;
+        delete params.moderation;
+        let redirect_url = `${req.path}?${new URLSearchParams(
+          params
+        ).toString()}`;
         res.redirect(redirect_url);
       }
     } else {
diff --git a/pass/routes/index.js b/pass/routes/index.js
index 4312648e2caf2d4797819c85905920e335f818cd..0c6cec15d7211111611fa4ec21ea64960be481e2 100644
--- a/pass/routes/index.js
+++ b/pass/routes/index.js
@@ -13,7 +13,9 @@ router.get("/", function (req, res, next) {
 });
 
 router.get("/login", (req, res) => {
-  let gitlab_url = `https://gitlab.example.com/oauth/authorize?client_id=${config.get("app.gitlab.client_id")}&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES`
+  let gitlab_url = `https://gitlab.example.com/oauth/authorize?client_id=${config.get(
+    "app.gitlab.client_id"
+  )}&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES`;
 });
 
 module.exports = router;
diff --git a/pass/routes/key.js b/pass/routes/key.js
index 73f27be0c7b8163865ba5f96802a0e716d26c4ed..281423d0e039c91d088878341e709402f39862bc 100644
--- a/pass/routes/key.js
+++ b/pass/routes/key.js
@@ -28,7 +28,7 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => {
 
   let qr_data_uri = await QRCode.toDataURL(metager_url);
 
-  req.data = {
+  req.data = Object.assign(req.data, {
     created_new: req.query.new === "true" ? true : false,
     key: {
       key: req.params.key,
@@ -38,7 +38,7 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => {
     },
     js: [],
     css: ["/styles/key/key.css"],
-  };
+  });
   next("route");
 });
 
diff --git a/pass/routes/orders.js b/pass/routes/orders.js
index b13b65e04d58951528c9ea6441a8ada266c9c4aa..83a85d514bec84db92ca504fd5efd5b4bbe08ce4 100644
--- a/pass/routes/orders.js
+++ b/pass/routes/orders.js
@@ -42,7 +42,7 @@ router.get("/:order_id", (req, res) => {
 });
 
 router.get("/:order_id/pdf", (req, res) => {
-  let doc = OrderReceipt.CREATE_ORDER_RECEIPT(req.data.order.order, res);
+  let doc = OrderReceipt.CREATE_ORDER_RECEIPT(req.data.order.order);
   res.status(200).header({
     "Content-Type": "application/pdf",
   });
@@ -52,21 +52,24 @@ router.get("/:order_id/pdf", (req, res) => {
 router.get("/:order_id/invoice", (req, res) => {
   req.data.order.invoice = {
     params: {
-      name: "",
-      email: "",
-      address: "",
+      name: req.query.name || "",
+      email: req.query.email || "",
+      address: req.query.address || "",
     },
+    create_invoice_url: `/key/${
+      req.data.key.key
+    }/orders/${req.data.order.order.getOrderID()}/invoice/create`,
     errors: {},
   };
   res.render("key", req.data);
 });
 
 router.post(
-  "/:order_id/invoice",
+  "/:order_id/invoice*",
   body("email").isEmail({ domain_specific_validation: true }),
   body("address").isLength({ max: 1000 }),
   body("name").isLength({ max: 500 }),
-  (req, res) => {
+  (req, res, next) => {
     req.data.order.invoice = {
       params: {
         name: req.body.name || "",
@@ -84,9 +87,52 @@ router.post(
       res.render("key", req.data);
       return;
     }
+    next();
+  }
+);
+
+router.post(
+  "/:order_id/invoice",
+  (req, res, next) => {
+    // Check if admin parameter is set and if so if the user is authenticated
+    if (req.body.admin) {
+      if (req.data.admin) {
+        next();
+      } else {
+        res.locals.error = { status: 401 };
+        res.locals.message = "Unauthorized";
+        res.status(401).render("error");
+      }
+    } else {
+      next();
+    }
+  },
+  (req, res) => {
+    let moderation_params = {
+      moderation: true,
+      name: req.data.order.invoice.params.name,
+      email: req.data.order.invoice.params.email,
+      address: req.data.order.invoice.params.address,
+    };
+
+    req.data.order.invoice.moderation_url = `${config.get("app.url")}/key/${
+      req.data.key.key
+    }/orders/${req.data.order.order.getOrderID()}/invoice?${new URLSearchParams(
+      moderation_params
+    ).toString()}#invoice-form`;
+
+    // Render the message
+    let ejs = require("ejs"),
+      fs = require("fs"),
+      template = fs.readFileSync(
+        `${__dirname}/../views/orders/invoice_message.ejs`,
+        "utf-8"
+      );
+
+    let message = ejs.render(template, req.data);
 
     // No validation errors. Try to create a new Ticket
-    return fetch(config.get("app.osticket.url"), {
+    return fetch(`${config.get("app.osticket.url")}/api/tickets.json`, {
       method: "post",
       headers: {
         "X-API-Key": config.get("app.osticket.api_key"),
@@ -98,13 +144,14 @@ router.post(
         source: "API",
         name: req.data.order.invoice.params.name,
         email: req.data.order.invoice.params.email,
-        subject: "MetaGer Schlüssel: Rechnung",
-        message: req.data.order.invoice.params.address,
+        subject: `MetaGer Schlüssel: Rechnung (${req.data.order.order.getOrderID()})`,
+        message: `data:text/html;charset=utf-8,${message}`,
         topicId: 12, // ToDo change topic for english autoresponder
       }),
     })
       .then((response) => {
-        if (response.status != 200) {
+        if (response.status != 201) {
+          console.error(response.body);
           throw "Fehler beim Erstellen der Benachrichtigung,";
         } else {
           req.data.order.invoice.success = true;
@@ -112,6 +159,7 @@ router.post(
         }
       })
       .catch((reason) => {
+        console.log(reason);
         req.data.order.invoice.errors["send_email"] =
           "Fehler beim Erstellen der Benachrichtigung,";
         res.render("key", req.data);
@@ -120,4 +168,33 @@ router.post(
   }
 );
 
+router.post(
+  "/:order_id/invoice/create",
+  (req, res, next) => {
+    // Check if admin parameter is set and if so if the user is authenticated
+    if (req.data.admin) {
+      next();
+    } else {
+      res.locals.error = { status: 401 };
+      res.locals.message = "Unauthorized";
+      res.status(401).render("error");
+    }
+  },
+  (req, res) => {
+    let doc = OrderReceipt.CREATE_ORDER_RECEIPT(
+      req.data.order.order,
+      req.data.order.invoice.params
+    );
+    res.header({
+      "Content-Type": "application/pdf",
+    });
+    let blob_stream = require("blob-stream");
+    let stream = doc.pipe(blob_stream());
+    stream.on("finish", () => {
+      const blob = stream.toBlob("application/pdf");
+      req.data.order.order.attachReceipt(blob);
+    });
+  }
+);
+
 module.exports = router;
diff --git a/pass/views/orders/invoice_message.ejs b/pass/views/orders/invoice_message.ejs
new file mode 100644
index 0000000000000000000000000000000000000000..be654f0329ebbe4c6b639d0a03b700f15f91b685
--- /dev/null
+++ b/pass/views/orders/invoice_message.ejs
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+</head>
+<body>
+    <p>Eine Rechnung für die Bestellung mit der ID <span style="font-weight: bold"><%= order.order.getOrderID() %></span> wurde angefragt. Folgende Rechnungsdaten wurden übermittelt:</p>
+    <div style="display: grid; grid-template-columns: auto 1fr; gap: 1rem; align-items: center; justify-content: center;">
+        <label for="name">Name</label>
+        <input type="text" name="name" id="name" value="<%= order.invoice.params.name %>" disabled>
+        <label for="email">E-Mail</label>
+        <input type="email" name="email" id="email" value="<%= order.invoice.params.email %>" disabled>
+        <label for="address" <%_ if(order.invoice.errors["address"]) { _%>class="error"<%_ } _%>>Anschrift</label>
+        <textarea name="address" id="address" cols="30" rows="3" placeholder="Mustergasse 3&#10;30159 Musterstadt&#10;Deutschland" disabled><%= order.invoice.params["address"] %></textarea>
+        <a href="<%= order.invoice.moderation_url %>" target="_blank" style="display: block;text-decoration: none;border: 1px solid rgb(168, 84, 0);border-radius: 5px;padding: .2rem .5rem;background-color: rgb(185, 92, 0);color: white!important;font-weight: bold;grid-column: span 2;text-align: center;max-width: 15em;justify-self: center;">Rechnung erstellen</a>
+    </div>
+    <p style="margin-top: 1rem">Bitte Rechnungsdaten überprüfen und die Rechnung erstellen. Anschließend die erstellte Rechnung als Antwort auf dieses Ticket an den Nutzer schicken.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/pass/views/orders/order.ejs b/pass/views/orders/order.ejs
index 034f58b91136efac97f466a4455e2f1dc76bd86a..8fccdd413c4139619aa24ea668117bed9f44ba4b 100644
--- a/pass/views/orders/order.ejs
+++ b/pass/views/orders/order.ejs
@@ -31,13 +31,14 @@
         </a>
     </div>
     <%_ } else { _%>
-    <form method="POST" id="invoice-form">
+    <form <% if(admin) { %>action="<%= order.invoice.create_invoice_url %>"<%_ } _%> method="POST" id="invoice-form">
         <h2>Rechnung</h2>
         <ul class="breadcrumbs">
             <li><a href="<%= order.orders_url %>">Bestellungen</a></li>
             <li><a href="<%= order.order_url %>"><%= order.order.getOrderID() %></a></li>
             <li>Rechnung</li>
         </ul>
+        <%_ if(!order.invoice.success) { _%>
         <p>
             Wenn Sie eine Rechnung benötigen, tragen Sie bitte Ihre Rechnungsdaten in das nachfolgende Formular ein. Wir benötigen von Ihnen dafür Ihren vollständigen Namen, Ihre postalische Anschrift und Ihre E-Mail Adresse um Ihnen die Rechnung zuzustellen.
         </p>
@@ -52,18 +53,31 @@
         </div>
         <div class="invoice-form-field">
             <label for="address" <%_ if(order.invoice.errors["address"]) { _%>class="error"<%_ } _%>>Anschrift*</label>
-            <textarea name="address" id="address" cols="30" rows="4" placeholder="Mustergasse 3&#10;30159 Musterstadt&#10;Deutschland" required><%= order.invoice.params["name-and-address"] %></textarea>
+            <textarea name="address" id="address" cols="30" rows="4" placeholder="Mustergasse 3&#10;30159 Musterstadt&#10;Deutschland" required><%= order.invoice.params["address"] %></textarea>
         </div>
+        <% if (admin) { %>
+        <input type="hidden" name="admin" value="true">
+        <div class="invoice-form-field">
+            <button type="submit" class="button">
+                <img src="/images/invoice.svg" alt="" />
+                <span>Rechnung erstellen</span>
+            </button>
+        </div>
+        <%_ } else { _%>
         <div class="invoice-form-field">
             <button type="submit" class="button">
                 <img src="/images/invoice.svg" alt="" />
                 <span>Rechnung anfragen</span>
             </button>
         </div>
+        <% } %>
         </div>
         <p class="storage-time">
             Wir sind rechtlich dazu verpflichtet einmal ausgestellte Rechnungen <span class="bold">10 Jahre</span> lang aufzubewahren. Da eine Rechnung auf Sie persönlich ausgestellt sein muss, enthält sie zwangsläufig personenbeziehbare Daten (Name, Anschrift, E-Mail).
         </p>
+        <%_ } else { _%>
+        <p>Ihre Nachricht wurde uns zugestellt. Wir bearbeiten die Anfrage so schnell wie möglich und antworten an die hinterlegte E-Mail Adresse.</p>
+        <%_ } _%>
     </form>
     <%_ } _%>
 </div>
\ No newline at end of file