Skip to content
 PrestaShop · 20–25 min · medium

Integrate Perfect Day into PrestaShop.

Sell your Perfect Day coupons through your PrestaShop. PrestaShop doesn't have a built-in webhook function — you need a small custom module that listens for the order event. A notice: This guide applies to PrestaShop 1.7+.

Required beforehand: Go once the general preparation This involves creating a coupon, obtaining the application password, and providing the webhook URL. It takes approximately five minutes and applies to all shop systems.

Step 1 — Create a property for the coupon ID

PrestaShop has so-called "features" that allow you to attach any data to products.

  1. Create new property

    PrestaShop admin → Catalog → Attributes & Properties → Properties„"Add new property"". Name: Perfect Day Coupon ID. Save. Then under „"Values"" Assign a value to each coupon variant (e.g. 15114, 15115).

  2. Assign property to each product

    In the product editor → Tab „"Functions""„"Perfect Day Coupon ID"" select → assign the appropriate value → save.

    The properties option is more suitable than a custom field, since custom fields in PrestaShop are intended only for customer input, not for backend links.

Step 2 — Custom module for the webhook

The module listens for the hook actionValidateOrder and sends the order to Perfect Day.

  1. Create a module structure

    The module consists of two files:

    Directory structure
    modules/perfectdayconnector/ ├── perfectdayconnector.php └── config.xml
  2. perfectdayconnector.php

    The module's main file registers the order hook, reads the coupon ID property for each product, and sends the webhook. Approximately 80 lines.

    View full code — PHP · perfectdayconnector.php
    PHP · perfectdayconnector.php
    name = 'perfectdayconnector'; $this->tab = 'export'; $this->version = '1.0.0'; $this->author = 'DigElite'; $this->bootstrap = true; parent::__construct(); $this->displayName = $this->l('Perfect Day Connector'); $this->description = $this->l('Sends orders with Perfect Day Coupon IDs to the platform.'); $this->ps_versions_compliancy = ['min' => '1.7', 'max' => _PS_VERSION_]; } public function install() { return parent::install() && $this->registerHook('actionValidateOrder') && Configuration::updateValue('PFD_API_USER', '') && Configuration::updateValue('PFD_API_PASSWORD', ''); } public function uninstall() { Configuration::deleteByName('PFD_API_USER'); Configuration::deleteByName('PFD_API_PASSWORD'); return parent::uninstall(); } public function hookActionValidateOrder($params) { $order = $params['order']; if (!$order) return; $items = []; foreach ($params['cart']->getProducts() as $p) { $couponId = $this->getProductFeatureValue($p['id_product'], 'Perfect Day Coupon-ID'); if (!$couponId) continue; $items[] = ['coupon_id' => (int)$couponId, 'count' => (int)$p['cart_quantity']]; } if (empty($items)) return; $customer = new Customer($order->id_customer); $payload = [ 'shop_order_id' => (string) $order->reference, 'shop_type' => 'prestashop', 'shop_domain' => Tools::getShopDomain(), 'customer' => [ 'email' => $customer->email, 'name' => trim($customer->firstname . ' ' . $customer->lastname), 'locale' => substr(Context::getContext()->language->iso_code, 0, 2), ], 'items' => $items, 'order_total_cents' => (int) round($order->total_paid * 100), 'currency' => Context::getContext()->currency->iso_code, 'placed_at' => $order->date_add, ]; $user = Configuration::get('PFD_API_USER'); $pwd = Configuration::get('PFD_API_PASSWORD'); $ch = curl_init('https://plattform.deinperfectday.de/wp-json/perfectday/shop/webhook/order'); curl_setopt_array($ch, [ CURLOPT_POST => 1, CURLOPT_RETURNTRANSFER => 1, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode($user . ':' . $pwd), ], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_TIMEOUT => 15, ]); curl_exec($ch); curl_close($ch); } private function getProductFeatureValue($idProduct, $featureName) { $sql = 'SELECT fvl.value FROM ' . _DB_PREFIX_ . 'feature_product fp' . 'INNER JOIN'. _DB_PREFIX_ . 'feature_lang fl ON fl.id_feature = fp.id_feature' . 'INNER JOIN'. _DB_PREFIX_ . 'feature_value_lang fvl ON fvl.id_feature_value = fp.id_feature_value' . ' WHERE fp.id_product = ' . (int)$idProduct . "AND fl.name = '". pSQL($featureName) . "'". 'LIMIT 1'; return Db::getInstance()->getValue($sql); } }
  3. Install module

    Pack the module folder as a ZIP file, then open the PrestaShop admin panel → Modules → Module Manager → Upload Module → Insert ZIP file → install → activate.

  4. Configure credentials

    Enter your login details as configuration values — PFD_API_USER (your WordPress username) and PFD_API_PASSWORD (Your application password). This can be done via the module configuration or directly in the ps_configuration-Tabel.

Step 3 — Test order

  1. Place and check order

    Place a test order in the PrestaShop frontend and complete the payment (a bank wire transfer is sufficient for testing). Then check: Platform back office → Perfect Day → Shop orders (Entry with shop_type=prestashop?) and the customer mailbox to the brand email with print button.

If something is stuck

Troubleshooting.

The module hook isn't firing.

Clear the PrestaShop cache: Advanced parameters → Performance → Clear cache. Also check if the module is active.

Property value remains empty

The module code searches for the feature name. Perfect Day Coupon ID. If you've changed the name, you need to adjust it in the code. For multilingual shops, the feature name must be translated for each language.

HTTP 401 / 403

401 = Incorrect username or application password (Username is your WordPress username, not your email address). 403 = The coupon ID does not belong to your provider account.

Setup service

Would you prefer us to set it up for you?

We offer you a complete PrestaShop module with a convenient configuration UI, a hosted bridge via Make.com/Zapier, or a code review of your own custom module.

Frequently Asked Questions

Still questions?

Does this also work with PrestaShop 1.6?
This guide is for PrestaShop 1.7+. For older versions, please send us a support request — the module code will need to be adjusted.
Can I use a custom field instead of the property?
Technically yes, but not recommended. Custom fields in PrestaShop are intended for customer input, not for backend links. The properties method is more stable.

Shop connected — and now what?

Once the webhook is running, all orders will automatically appear in your back office. If you need another connection, each additional shop can be set up in just a few minutes.

Go to shop overview