diff --git a/pass/app/Payment.js b/pass/app/Payment.js
index bb7540faab48eceb48dd0eb622f78d91ee5a7c54..5f0c69f89864811ef794e5c3c375ad84f4dd86fb 100644
--- a/pass/app/Payment.js
+++ b/pass/app/Payment.js
@@ -67,7 +67,7 @@ class Payment {
     return Payments()
       .where("id", this.id)
       .where("receipt_id", null)
-      .update({ receipt_id: receipt_id })
+      .update({ receipt_id: receipt_id }, ["*"])
       .then((result) => {
         if (result && result.length === 1) {
           return new Payment(result[0]);
@@ -172,6 +172,11 @@ class Payment {
       });
   }
 
+  /**
+   * 
+   * @param {String} payment_id 
+   * @returns {Promise<Payment|never>}
+   */
   static async LOAD_FROM_PUBLIC_ID(payment_id) {
     let matcher = payment_id.match(/^(A)?(\d+)$/);
     if (!matcher) {
diff --git a/pass/app/Receipt.js b/pass/app/Receipt.js
index 9b2b120815c8399b7e97dd162a5011ee717b25f1..056c9fcf0678aaa7da52bc9d86f52b504c675587 100644
--- a/pass/app/Receipt.js
+++ b/pass/app/Receipt.js
@@ -6,6 +6,7 @@ const config = require("config");
  * @typedef {Object} ReceiptsDB
  * @property {number} id
  * @property {string} receipt
+ * @property {string} invoice_id
  * @property {number} payment_id
  * @property {string} created_at
  */
@@ -17,11 +18,8 @@ class Receipt {
    *
    * @param {Object} data
    * @param {number} data.id
-   * @param {string} data.company
-   * @param {string} data.name
-   * @param {string} data.email
-   * @param {string} data.address
    * @param {string} data.receipt
+   * @param {string} invoice_id
    * @param {number} data.payment_id
    * @param {string} data.created_at
    */
@@ -31,11 +29,8 @@ class Receipt {
     if (data.id < 0) {
       this.public_id = "TEST_INVOICE";
     }
-    this.company = data.company;
-    this.name = data.name;
-    this.email = data.email;
-    this.address = data.address;
     this.receipt = data.receipt;
+    this.invoice_id = data.invoice_id;
     this.payment_id = data.payment_id;
     this.created_at = dayjs(data.created_at);
   }
@@ -43,11 +38,8 @@ class Receipt {
   /**
    * @param {Object} data
    * @param {number} data.id
-   * @param {string} data.company
-   * @param {string} data.name
-   * @param {string} data.email
-   * @param {string} data.address
    * @param {string} [data.receipt]
+   * @param {string} data.invoice_id
    * @param {number} data.payment_id
    * @param {string} data.created_at
    *
@@ -65,6 +57,20 @@ class Receipt {
       });
   }
 
+  /**
+   * 
+   * @param {int} private_payment_reference 
+   * @returns {Promise<Receipt>}
+   */
+  static async LOAD_FROM_PAYMENT_REFERENCE(private_payment_reference) {
+    return Receipts().where("payment_id", private_payment_reference).first().then(receipt => {
+      if (receipt == null) {
+        return Promise.reject("Receipt not yet generated");
+      }
+      return new Receipt(receipt);
+    });
+  }
+
   /**
    * 
    * @param {number} internal_id 
@@ -79,6 +85,21 @@ class Receipt {
     })
   }
 
+  /**
+   * Loads the latest receipt for a given array of paymentreferences
+   * 
+   * @param {array} payment_reference_ids 
+   * @return {Promise<Receipt|null>}
+   */
+  static async GET_LATEST_RECEIPT(payment_reference_ids) {
+    return __database_client("payments").whereIn("payment_reference_id", payment_reference_ids).rightJoin("receipts", "payments.receipt_id", "receipts.id").whereNotNull("receipts.invoice_id").orderBy("receipts.created_at", "desc").first().then(payment => {
+      if (payment == undefined) {
+        return null;
+      }
+      return new Receipt(payment);
+    });
+  }
+
   /**
    *
    * @param {string} receiptdata
diff --git a/pass/config/default.json b/pass/config/default.json
index fdd79f2a3af984e30c71ee736a6659690559074b..5b97ff35bbd3e51e97c7d895eb835cc77fc1685b 100644
--- a/pass/config/default.json
+++ b/pass/config/default.json
@@ -29,6 +29,11 @@
       "url": "<ZAMMAD_URL>",
       "api_key": "<ZAMMAD_API_KEY>",
       "notification_ticket_id": "0"
+    },
+    "invoiceninja": {
+      "url": "https://invoiceninja.com/",
+      "api_token": "<YOUR_API_TOKEN>",
+      "group_id": "<YOUR_CUSTOM_GROUP_ID>"
     }
   },
   "price": {
diff --git a/pass/database/migrations/20240913103116_invoiceninja.js b/pass/database/migrations/20240913103116_invoiceninja.js
new file mode 100644
index 0000000000000000000000000000000000000000..0302d9dd3aa4632120591cd6b51dc04b8dfd5384
--- /dev/null
+++ b/pass/database/migrations/20240913103116_invoiceninja.js
@@ -0,0 +1,27 @@
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise<void> }
+ */
+exports.up = function (knex) {
+    return knex.schema.alterTable("receipts", table => {
+        table.string("invoice_id");
+        table.dropColumn("company");
+        table.dropColumn("name");
+        table.dropColumn("email");
+        table.dropColumn("address");
+    });
+};
+
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise<void> }
+ */
+exports.down = function (knex) {
+    return knex.schema.alterTable("receipts", table => {
+        table.dropColumn("invoice_id");
+        table.string("company", 500);
+        table.string("name", 500).notNullable();
+        table.string("email", 200).notNullable();
+        table.text("address").notNullable();
+    });
+};
diff --git a/pass/lang/de/invoice.json b/pass/lang/de/invoice.json
index f54655e5d8937d1f8c4efdab9d9a751fea28ac43..31af0049bdcb1fc35b144319c04667edd4e75857 100644
--- a/pass/lang/de/invoice.json
+++ b/pass/lang/de/invoice.json
@@ -46,8 +46,8 @@
       "label": "Anschrift",
       "placeholder": "Mustergasse 3&#10;30159 Musterstadt&#10;Deutschland"
     },
-    "submit": "Rechnung anfragen",
+    "submit": "Rechnung erstellen",
     "storage": "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).",
     "success": "Ihre Nachricht wurde uns zugestellt. Wir bearbeiten die Anfrage so schnell wie möglich und antworten an die hinterlegte E-Mail Adresse."
   }
-}
+}
\ No newline at end of file
diff --git a/pass/lang/de/order.json b/pass/lang/de/order.json
index 4bdb98f98672da12fa39166dfc77351644710aea..ae5e71f03774e43f761cd06ec454e37792aabdb0 100644
--- a/pass/lang/de/order.json
+++ b/pass/lang/de/order.json
@@ -12,7 +12,7 @@
     "thankyou": "Vielen Dank für Ihren Einkauf!",
     "actions": {
       "order-confirmation": "Auftragsbestätigung herunterladen",
-      "receipt": "Rechnung anfragen",
+      "receipt": "Rechnung erstellen",
       "download-receipt": "Rechnung herunterladen",
       "refund": "Erstattung anfragen"
     },
diff --git a/pass/lang/en/invoice.json b/pass/lang/en/invoice.json
index 0d205cea55dfcfbe7084178017502ba634d8041f..d88cb84c5233318c5a32b0174d996bc37a89a87b 100644
--- a/pass/lang/en/invoice.json
+++ b/pass/lang/en/invoice.json
@@ -2,7 +2,7 @@
   "title_order": "Order {{orderid}}",
   "title_invoice": "Receipt {{orderid}}",
   "author": "SUMA-EV - Association for Free Access to Knowledge",
-  "subject": "MetaGer key: token (x{amount}})",
+  "subject": "MetaGer Key: {{amount}} Token ({{payment_reference}})",
   "invoice": "Invoice",
   "payment_reference_id": "Payment ID",
   "order-confirmation": "Order confirmation",
@@ -35,19 +35,36 @@
       "label": "Company name (optional)",
       "placeholder": "Any company"
     },
-    "name": {
-      "label": "Full name",
-      "placeholder": "John Sample"
+    "first_name": {
+      "label": "First Name",
+      "placeholder": "John"
     },
-    "mail": {
-      "label": "E-mail"
+    "last_name": {
+      "label": "Last Name",
+      "placeholder": "Sample"
     },
-    "address": {
-      "label": "Address",
-      "placeholder": "Any street 3&#10;3015 Any city&#10;Germany"
+    "address1": {
+      "label": "Address 1",
+      "placeholder": "Main Street 1101"
     },
-    "submit": "Invoice request",
+    "address2": {
+      "label": "Address 2 (optional)",
+      "placeholder": "App. 3"
+    },
+    "zip": {
+      "label": "Postal Code",
+      "placeholder": "123456"
+    },
+    "city": {
+      "label": "City",
+      "placeholder": "Example City"
+    },
+    "state": {
+      "label": "State (optional)",
+      "placeholder": "Washington"
+    },
+    "submit": "Create Invoice",
     "storage": "We are legally obliged to keep once issued invoices <span class=\"bold\">10 years</span> long. Since an invoice must be issued to you personally, it necessarily contains personal data (name, address, e-mail).",
     "success": "Your message has been delivered to us. We will process the request as soon as possible and reply to the email address on file."
   }
-}
+}
\ No newline at end of file
diff --git a/pass/lang/en/order.json b/pass/lang/en/order.json
index 33a61736ad2b0181fcc2b5bd4a77220034bddb9e..20809ad64527758e8e371fabf4eda1f0a628b50c 100644
--- a/pass/lang/en/order.json
+++ b/pass/lang/en/order.json
@@ -12,7 +12,7 @@
     "thankyou": "Thank you for your purchase!",
     "actions": {
       "order-confirmation": "Download order confirmation",
-      "receipt": "Receipt request",
+      "receipt": "Create Receipt",
       "download-receipt": "Download receipt",
       "refund": "Request refund"
     },
diff --git a/pass/public/styles/orders/order.less b/pass/public/styles/orders/order.less
index 2725ac21a4ce92d2abb68045ce6c897e3019d97c..cce85201517f008415afec2135dbb2224a29fdec 100644
--- a/pass/public/styles/orders/order.less
+++ b/pass/public/styles/orders/order.less
@@ -1,56 +1,70 @@
 #order {
   padding: 1rem 0;
+
   .breadcrumbs {
     display: flex;
     gap: 0.5rem;
     padding: 0;
     list-style-type: disclosure-closed;
     font-size: clamp(0.7rem, 4vw, 1rem);
+
     li {
       margin-left: 1rem;
+
       &:first-child {
         margin-left: 0;
         list-style-type: none;
       }
+
       a {
         color: #777;
       }
     }
   }
+
   grid-area: content;
+
   #order-details {
     display: grid;
     grid-template-columns: 1fr auto auto;
     text-align: right;
     padding: 2rem 0;
-    > div {
+
+    >div {
       padding: 0.5rem;
+
       &.heading {
         text-align: left;
         border-bottom: 1px solid var(--color-main);
         font-weight: bold;
         padding-bottom: 0.2rem;
       }
+
       &:not(.heading) {
         padding: 0.5rem 0;
       }
+
       &.sum {
         font-weight: bold;
       }
+
       &.price {
         white-space: nowrap;
       }
+
       &.count {
         text-align: center;
       }
+
       &.exchanged {
-        > span {
+        >span {
           font-size: 0.8rem;
         }
       }
     }
   }
-  > h3 {
+
+  >h3 {
     text-align: center;
   }
 
@@ -60,6 +74,7 @@
     grid-template-columns: 1fr auto auto;
     justify-items: end;
     gap: 0.5rem;
+
     .button {
       font-size: 0.8rem;
       display: flex;
@@ -68,16 +83,20 @@
       line-height: 1;
       gap: 0.5rem;
       padding: 0.5rem;
+
       img {
         height: 1rem;
+
         &.order-receipt {
           filter: brightness(0) invert(1);
         }
       }
     }
+
     @media (max-width: 842px) {
       grid-template-columns: 1fr;
-      > a.button {
+
+      >a.button {
         width: 100%;
         padding: 1rem;
       }
@@ -86,18 +105,20 @@
 
   #invoice {
     #download-receipt {
-      > a.button {
+      >a.button {
         display: flex;
         margin: 0 auto;
         justify-content: center;
         align-items: center;
         gap: 0.5rem;
         padding: 0.5rem;
-        > img {
+
+        >img {
           height: 1.5em;
         }
       }
     }
+
     #invoice-form {
       #invoice-form-fields {
         display: grid;
@@ -111,15 +132,24 @@
           font-size: 0.7rem;
           place-content: center;
           text-align: center;
-          #email,
+
+          #first_name,
+          #last_name,
           #name,
-          #company {
+          #company,
+          #address1,
+          #address2,
+          #zip,
+          #city,
+          #state,
+          #country {
             padding: 0.5rem;
             border-radius: 5px;
             font-size: 0.8rem;
             width: 13rem;
             text-align: center;
           }
+
           #address {
             padding: 0.5rem;
             border-radius: 5px;
@@ -127,21 +157,24 @@
             text-align: center;
             width: 13rem;
           }
+
           button {
             display: flex;
             align-items: center;
             gap: 0.5rem;
             padding: 0.5rem;
+
             img {
               height: 1.2rem;
             }
           }
         }
       }
+
       .storage-time {
         font-size: 0.8rem;
         text-align: center;
       }
     }
   }
-}
+}
\ No newline at end of file
diff --git a/pass/routes/orders/receipt.js b/pass/routes/orders/receipt.js
index 9246e14c257295282f80b29bc625e6b9fe50efcf..7758d3580f0299110bd1c526469e8de7eaed4d72 100644
--- a/pass/routes/orders/receipt.js
+++ b/pass/routes/orders/receipt.js
@@ -5,8 +5,10 @@ const config = require("config");
 const { body, validationResult } = require("express-validator");
 const Receipt = require("../../app/Receipt");
 const Zammad = require("../../app/Zammad");
+const Payment = require("../../app/Payment");
+const { t } = require("i18next");
 
-router.get("/", (req, res) => {
+router.get("/", async (req, res) => {
   req.data.order.invoice = {
     params: {
       name: req.query.name || "",
@@ -19,22 +21,69 @@ router.get("/", (req, res) => {
     errors: {},
   };
 
+  let orders = req.data.key.key.get_charge_orders();
+  let payment_reference_ids = [];
+  orders.forEach(order => {
+    payment_reference_ids.push(order.payment_reference_id);
+  });
+
+  let receipt = await Receipt.GET_LATEST_RECEIPT(payment_reference_ids);
+  if (receipt != null) {
+    await fetch(config.get("app.invoiceninja.url") + "/api/v1/invoices/" + receipt.invoice_id, {
+      method: "GET",
+      headers: {
+        "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+        "Content-Type": "application/json"
+      },
+    })
+      .then(response => response.json())
+      .then(invoice => {
+        return fetch(config.get("app.invoiceninja.url") + "/api/v1/clients/" + invoice.data.client_id, {
+          method: "GET",
+          headers: {
+            "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+            "Content-Type": "application/json"
+          },
+        });
+      }).then(response => response.json())
+      .then(client => {
+        req.data.order.invoice_old = {
+          company: client.data.name,
+          first_name: client.data.contacts[0].first_name,
+          last_name: client.data.contacts[0].last_name,
+          address1: client.data.address1,
+          address2: client.data.address2,
+          zip: client.data.postal_code,
+          city: client.data.city,
+          state: client.data.state
+        }
+      }).catch(reason => { });
+  }
+
   res.render("key", req.data);
 });
 
 router.post(
   "/*",
-  body("email").isEmail({ domain_specific_validation: true }),
-  body("address").isLength({ max: 1000 }),
-  body("name").isLength({ max: 500 }),
-  body("company").isLength({ max: 500 }),
+  body("company").isLength({ max: 100 }),
+  body("first_name").isLength({ max: 50 }),
+  body("last_name").isLength({ max: 50 }),
+  body("address1").isLength({ max: 100 }),
+  body("address2").isLength({ max: 100 }),
+  body("zip").isLength({ max: 25 }),
+  body("city").isLength({ max: 25 }),
+  body("country").isLength({ max: 50 }),
   (req, res, next) => {
     req.data.order.invoice = {
       params: {
         company: req.body.company || "",
-        name: req.body.name || "",
-        email: req.body.email || "",
-        address: req.body["address"] || "",
+        first_name: req.body.first_name || "",
+        last_name: req.body.last_name || "",
+        address1: req.body.address1 || "",
+        address2: req.body.address2 || "",
+        zip: req.body.zip || "",
+        city: req.body.city || "",
+        state: req.body.state || "",
       },
       errors: {},
     };
@@ -51,7 +100,155 @@ router.post(
   }
 );
 
-router.post("/", (req, res) => {
+router.post("/", async (req, res) => {
+  let order_id = req.data.order.payment.public_id;
+  let payment_reference = req.data.order.payment_reference.public_id;
+
+  let url = req.data.links.order_actions_base + "/" + req.data.order.payment.public_id + "/receipt/download";
+
+  // Check if there already is a receipt
+  if (req.data.order.payment.receipt_id != null) {
+    res.redirect(url);
+    return;
+  }
+
+  // Check if there is a previous client
+  let orders = req.data.key.key.get_charge_orders();
+  let payment_reference_ids = [];
+  orders.forEach(order => {
+    payment_reference_ids.push(order.payment_reference_id);
+  });
+
+  let receipt = await Receipt.GET_LATEST_RECEIPT(payment_reference_ids);
+  let client_id = null;
+  if (receipt != null) {
+    await fetch(config.get("app.invoiceninja.url") + "/api/v1/invoices/" + receipt.invoice_id, {
+      method: "GET",
+      headers: {
+        "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+        "Content-Type": "application/json"
+      },
+    })
+      .then(response => response.json())
+      .then(invoice => {
+        return fetch(config.get("app.invoiceninja.url") + "/api/v1/clients/" + invoice.data.client_id, {
+          method: "GET",
+          headers: {
+            "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+            "Content-Type": "application/json"
+          },
+        });
+      }).then(response => response.json())
+      .then(client => {
+        client_id = client.data.id;
+      }).catch(reason => { });
+  }
+
+  // Create a new Client
+  let post_data = {
+    contacts: [{
+      "first_name": req.data.order.invoice.params.first_name,
+      "last_name": req.data.order.invoice.params.last_name,
+      "send_email": true
+    }],
+    name: req.data.order.invoice.params.company.length > 0 ? req.data.order.invoice.params.company : null,
+    address1: req.data.order.invoice.params.address1,
+    address2: req.data.order.invoice.params.address2,
+    city: req.data.order.invoice.params.city,
+    state: req.data.order.invoice.params.state,
+    postal_code: req.data.order.invoice.params.zip,
+    country_code: "DE",
+    currency_code: "EUR",
+    group_settings_id: config.get("app.invoiceninja.group_id")
+  };
+
+  let create_or_update_promise = null;
+  if (client_id != null) {
+    // Update
+    create_or_update_promise = fetch(config.get("app.invoiceninja.url") + "/api/v1/clients/" + client_id, {
+      method: "PUT",
+      headers: {
+        "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+        "Content-Type": "application/json"
+      },
+      body: JSON.stringify(post_data)
+    });
+  } else {
+    create_or_update_promise = fetch(config.get("app.invoiceninja.url") + "/api/v1/clients", {
+      method: "POST",
+      headers: {
+        "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+        "Content-Type": "application/json"
+      },
+      body: JSON.stringify(post_data)
+    });
+  }
+
+
+
+  return create_or_update_promise.then(response => response.json()).then(response => {
+    let client = response.data;
+    let assigned_user_id = client.contacts[0].id;
+    return fetch(config.get("app.invoiceninja.url") + "/api/v1/clients/" + client.id, {
+      method: "PUT",
+      headers: {
+        "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+        "Content-Type": "application/json"
+      },
+      body: JSON.stringify({
+        assigned_user_id: assigned_user_id,
+        contacts: client.contacts,
+      })
+    });
+  }).then(response => response.json()).then(response => {
+    let client = response.data;
+    Payment.LOAD_FROM_PUBLIC_ID(req.data.order.payment.public_id).then(payment => {
+      // Create the invoice
+      let actions = new URLSearchParams({
+        send_email: "false",
+        mark_sent: "true",
+        amount_paid: payment.converted_price
+      });
+      return fetch(config.get("app.invoiceninja.url") + "/api/v1/invoices?" + actions.toString(), {
+        method: "POST",
+        headers: {
+          "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+          "Content-Type": "application/json"
+        },
+        body: JSON.stringify({
+          client_id: client.id,
+          po_number: req.data.order.payment.public_id,
+          line_items: [{
+            quantity: 1,
+            cost: req.data.order.payment_reference.price,
+            notes: t("subject", {
+              ns: "invoice",
+              amount: Math.round(
+                (payment.converted_price / req.data.order.payment_reference.price) * req.data.order.payment_reference.amount
+              ),
+              payment_reference: req.data.order.payment_reference.public_id
+            }),
+            public_notes: t("payment-received", { ns: "invoice" }),
+            tax_name1: "MwSt.",
+            tax_rate1: 7
+          }]
+        })
+      })
+        .then(response => response.json())
+        .then(invoice => {
+          // Return the new invoice as pdf
+          return Receipt.CREATE_NEW_RECEIPT({
+            invoice_id: invoice.data.id,
+            payment_id: req.data.order.payment.id
+          });
+        }).then(receipt => {
+          payment.setReceipt(receipt.id)
+          return res.redirect(req.data.links.order_actions_base + "/" + receipt.payment_id + "/receipt/download")
+        });
+    })
+
+  })
+
   let moderation_params = {
     order: req.data.order.payment.public_id,
     payment_reference: req.data.order.payment_reference.public_id,
@@ -60,6 +257,9 @@ router.post("/", (req, res) => {
     email: req.data.order.invoice.params.email,
     address: req.data.order.invoice.params.address,
   };
+
+
+
   req.data.order.invoice.params = moderation_params;
   req.data.order.invoice.moderation_url = `${res.locals.baseDir
     }/admin/payments/receipt?${new URLSearchParams(
@@ -108,9 +308,43 @@ router.get("/download", (req, res) => {
     res.status(404).render("error");
   }
   return Receipt.LOAD_RECEIPT_FROM_INTERNAL_ID(req.data.order.payment.receipt_id).then(receipt => {
-    res.type("pdf").header({
-      "Content-Disposition": `inline; filename=${receipt.public_id}.pdf`
-    }).send(Buffer.from(receipt.receipt.toString(), "base64"));
+
+    // Receipt can either be in the database itself, or via invoiceninja
+    if (receipt.invoice_id != null) {
+      // Load invoice
+      let invoice_number = null;
+      return fetch(config.get("app.invoiceninja.url") + "/api/v1/invoices/" + receipt.invoice_id, {
+        method: "GET",
+        headers: {
+          "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+          "Content-Type": "application/json"
+        },
+      })
+        .then(response => response.json())
+        .then(invoice => {
+          invoice_number = invoice.data.number;
+          return fetch(config.get("app.invoiceninja.url") + "/api/v1/invoice/" + invoice.data.invitations[0].key + "/download", {
+            method: "GET",
+            headers: {
+              "X-API-TOKEN": config.get("app.invoiceninja.api_token"),
+              "Content-Type": "application/json"
+            },
+          })
+        })
+        .then(response => response.blob())
+        .then(blob => {
+          res.setHeader("Content-Length", blob.size);
+          res.setHeader("Content-Type", blob.type);
+          res.setHeader("Content-Disposition", `attachment; filename=receipt-metager-${invoice_number}.pdf`);
+          return blob.arrayBuffer().then(buf => {
+            res.send(Buffer.from(buf));
+          })
+        });
+    } else {
+      res.type("pdf").header({
+        "Content-Disposition": `inline; filename=${receipt.public_id}.pdf`
+      }).send(Buffer.from(receipt.receipt.toString(), "base64"));
+    }
   }).catch(reason => {
     console.error(reason);
     res.locals.error = { status: 404 };
diff --git a/pass/views/orders/invoice.ejs b/pass/views/orders/invoice.ejs
index 02d5d9e0c9a8d4cb35b263afdaf5b355844609b0..e842e6912746dd7735b2c22298e94af14d86d046 100644
--- a/pass/views/orders/invoice.ejs
+++ b/pass/views/orders/invoice.ejs
@@ -13,19 +13,35 @@
     <div id="invoice-form-fields">
       <div class="invoice-form-field">
         <label for="company" <%_ if(order.invoice.errors.company) { _%>class="error" <%_ } _%>><%= req.t("form.company.label", {ns: "invoice"}) _%></label>
-        <input type="text" name="company" id="company" placeholder="<%= req.t("form.company.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.company %>">
+        <input type="text" name="company" id="company" placeholder="<%= req.t("form.company.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.company ?? req.data.order.invoice_old.company %>">
       </div>
       <div class="invoice-form-field">
-        <label for="name" <%_ if(order.invoice.errors.name) { _%>class="error" <%_ } _%>><%= req.t("form.name.label", {ns: "invoice"}) _%>*</label>
-        <input type="text" name="name" id="name" placeholder="<%= req.t("form.name.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.name %>" required>
+        <label for="first_name" <%_ if(order.invoice.errors.first_name) { _%>class="error" <%_ } _%>><%= req.t("form.first_name.label", {ns: "invoice"}) _%>*</label>
+        <input type="text" name="first_name" id="first_name" placeholder="<%= req.t("form.first_name.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.first_name ?? req.data.order.invoice_old.first_name %>" required>
       </div>
       <div class="invoice-form-field">
-        <label for="email" <%_ if(order.invoice.errors.email) { _%>class="error" <%_ } _%>><%= req.t("form.mail.label", {ns: "invoice"}) _%>*</label>
-        <input type="email" name="email" id="email" placeholder="test@example.com" value="<%= order.invoice.params.email %>" required>
+        <label for="last_name" <%_ if(order.invoice.errors.last_name) { _%>class="error" <%_ } _%>><%= req.t("form.last_name.label", {ns: "invoice"}) _%>*</label>
+        <input type="text" name="last_name" id="last_name" placeholder="<%= req.t("form.last_name.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.last_name ?? req.data.order.invoice_old.last_name %>" required>
       </div>
       <div class="invoice-form-field">
-        <label for="address" <%_ if(order.invoice.errors["address"]) { _%>class="error" <%_ } _%>><%= req.t("form.address.label", {ns: "invoice"}) _%>*</label>
-        <textarea name="address" id="address" cols="30" rows="3" placeholder="<%- req.t("form.address.placeholder", {ns: "invoice"}) _%>" required><%= order.invoice.params["address"] %></textarea>
+        <label for="address1" <%_ if(order.invoice.errors.address1) { _%>class="error" <%_ } _%>><%= req.t("form.address1.label", {ns: "invoice"}) _%>*</label>
+        <input type="text" name="address1" id="address1" placeholder="<%= req.t("form.address1.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.address1 ?? req.data.order.invoice_old.address1 %>" required>
+      </div>
+      <div class="invoice-form-field">
+        <label for="address2" <%_ if(order.invoice.errors.address2) { _%>class="error" <%_ } _%>><%= req.t("form.address2.label", {ns: "invoice"}) _%></label>
+        <input type="text" name="address2" id="address2" placeholder="<%= req.t("form.address2.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.address2 ?? req.data.order.invoice_old.address2 %>">
+      </div>
+      <div class="invoice-form-field">
+        <label for="zip" <%_ if(order.invoice.errors.zip) { _%>class="error" <%_ } _%>><%= req.t("form.zip.label", {ns: "invoice"}) _%>*</label>
+        <input type="text" name="zip" id="zip" placeholder="<%= req.t("form.zip.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.zip ?? req.data.order.invoice_old.zip %>" required>
+      </div>
+      <div class="invoice-form-field">
+        <label for="city" <%_ if(order.invoice.errors.city) { _%>class="error" <%_ } _%>><%= req.t("form.city.label", {ns: "invoice"}) _%>*</label>
+        <input type="text" name="city" id="city" placeholder="<%= req.t("form.city.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.city ?? req.data.order.invoice_old.city %>" required>
+      </div>
+      <div class="invoice-form-field">
+        <label for="state" <%_ if(order.invoice.errors.state) { _%>class="error" <%_ } _%>><%= req.t("form.state.label", {ns: "invoice"}) _%></label>
+        <input type="text" name="state" id="state" placeholder="<%= req.t("form.state.placeholder", {ns: "invoice"}) _%>" value="<%= order.invoice.params.state ?? req.data.order.invoice_old.state %>">
       </div>
       <div class="invoice-form-field">
         <button type="submit" class="button">