Skip to content

Public Marketplace (Mirakl) Integration ​

Flow ID: IN-04 | Module(s): eshop, job, Public, Transporters | Complexity: High Last Updated: 2026-04-04

Business Overview ​

Public is a Greek retail marketplace powered by the Mirakl platform. This integration provides polling-based order synchronization using the Mirakl Shop SDK, with five scheduled background jobs covering the full order lifecycle: fetching awaiting orders, syncing status updates, sending tracking information, marking orders as shipped, and backfilling shipping/customer data. Orders are accepted or rejected at the line-item level (unlike Shopflix which operates at the order level). The integration includes transporter selection during acceptance and automatic carrier mapping via the Mirakl carrier registry.

API Reference ​

The integration uses the Mirakl PHP Shop SDK (Mirakl\MMP\Shop\Client\ShopApiClient) rather than direct HTTP calls.

SDK MethodPurpose
getOrders(GetOrdersRequest)Fetch orders by state and date range
acceptOrder(AcceptOrderRequest)Accept/reject individual order lines
shipOrder(ShipOrderRequest)Mark order as shipped
updateOrderTrackingInfo(UpdateOrderTrackingInfoRequest)Send tracking number and carrier details
getOrderDocuments(GetOrderDocumentsRequest)Check for delivery bills
downloadOrdersDocuments(DownloadOrdersDocumentsRequest)Download delivery bill PDF
getShippingCarriers()List available carrier codes for tracking

API endpoint: https://publicgr-prod.mirakl.net/api

Authentication: API Key + Store ID passed to ShopApiClient constructor.

Timezone handling: All Mirakl dates are in UTC and converted to Europe/Athens via convertTime().

Code Flow ​

1. Fetch Awaiting Orders (Job) ​

Entry point: AdvGetPublicMarketplaceAwaitingOrders::executeCommand()

AdvGetPublicMarketplaceAwaitingOrders
  |-- Check PUBLIC_MARKETPLACE.ENABLED + API_KEY
  |-- PublicOrders::getPendingOrders(date - 1 week)
  |     |-- GetOrdersRequest with state=WAITING_ACCEPTANCE, TAX_INCLUDED
  |     |-- transformOrderData() maps Mirakl objects to arrays
  |-- Get existing order IDs from DB to avoid duplicates
  |-- For each new order:
        |-- mapOrderData() -> insert into public_orders
        |-- insertOrderBasket() -> batch insert into public_line_items

2. Update Order Status (Job) ​

Entry point: AdvUpdatePublicOrdersStatus::executeCommand()

AdvUpdatePublicOrdersStatus
  |-- PublicOrders::getOrders(date - 1 week) -- all states
  |-- For each order that exists locally:
        |-- Map Mirakl status to internal state
        |-- Update public_orders.state

3. Send Tracking Information (Job) ​

Entry point: AdvSetTrackingPublicMarketplace::executeCommand()

AdvSetTrackingPublicMarketplace
  |-- Get orders needing tracking from order_model::getOrdersForTrackingPublicMarketplace()
  |-- For each order:
        |-- Build tracking details (carrier_code, tracking_number, carrier_url)
        |-- PublicOrders::setTrackingDetails() with carrier lookup from Mirakl
        |-- On success: set is_tracking_sent = true

4. Mark Orders Shipped (Job) ​

Entry point: AdvSetPublicOrdersSent::executeCommand()

AdvSetPublicOrdersSent
  |-- Get SENT orders via order_model::getOrdersPublicMarketplaceForSetSent()
  |-- For each: PublicOrders::setOrderShipped()
  |-- Batch update is_sent = 1 for successful orders

5. Backfill Shipping Data (Job) ​

Entry point: AdvGetPublicMarketplaceShippingData::executeCommand()

AdvGetPublicMarketplaceShippingData
  |-- Get accepted orders missing customer data (got_customer_data = 0)
  |-- For each: fetch full order from Mirakl API
  |-- Extract billing + shipping addresses
  |-- Update shop_order with address fields
  |-- Update shop_customer with address fields
  |-- Set got_customer_data = 1

6. Admin Accept Flow ​

Entry point: Adv_public_orders_admin::accept($orderId)

accept($orderId)
  |-- Validate order exists + acceptance_until_date not expired + no existing shop_order_id
  |-- Load available transporters via public_order_transporters()
  |-- Match line items to shop products via EAN/product_code
  |-- Stock validation (bypassable via DISABLE_PRODUCT_STOCK_CHECK)
  |-- On POST accept_order:
        |-- Get order line IDs for line-item acceptance
        |-- PublicOrders::acceptOrder($orderId, $orderLineIds)
        |-- Re-fetch order from API for latest customer data
        |-- Build fake cart from line items
        |-- Create guest customer (with randomized email to avoid collisions)
        |-- Create internal order with selected transporter, status=PAID
        |-- Provider = PUBLIC_MARKETPLACE_PROVIDER constant
        |-- Fire ERP hook

7. Admin Reject Flow ​

Entry point: Adv_public_orders_admin::reject($orderId)

reject($orderId)
  |-- Get order line IDs
  |-- PublicOrders::rejectOrder($orderId, $orderLineIds) -- marks all lines as rejected
  |-- Update public_orders.state = 'rejected'

8. Status Mapping ​

Mirakl API statuses mapped to internal states:

Mirakl StatusInternal State
STAGINGopen
WAITING_ACCEPTANCEopen
WAITING_DEBITaccepted
WAITING_DEBIT_PAYMENTaccepted
SHIPPINGaccepted
SHIPPEDdispatched
TO_COLLECTdispatched
RECEIVEDdelivered
CLOSEDexpired
REFUSEDrejected
CANCELEDcancelled

Architecture ​

ecommercen/job/libraries/
  AdvGetPublicMarketplaceAwaitingOrders.php  -- Fetch new orders (JobCommand)
  AdvUpdatePublicOrdersStatus.php            -- Sync status changes (JobCommand)
  AdvSetTrackingPublicMarketplace.php        -- Send tracking info (JobCommand)
  AdvSetPublicOrdersSent.php                 -- Mark shipped (JobCommand)
  AdvGetPublicMarketplaceShippingData.php    -- Backfill addresses (JobCommand)

src/Public/PublicOrders.php                  -- Mirakl SDK client wrapper
ecommercen/core/AdvFactories.php             -- Factory method: Factories::publicMarketplace()

ecommercen/eshop/controllers/Adv_public_orders_admin.php  -- Admin controller
ecommercen/eshop/models/Adv_public_orders_model.php       -- Legacy model

src/Domains/Marketplace/Public/Order/                      -- Modern domain layer (read-only)
  Repository/{Entity,Repository,RepositoryConfigurator}.php
  Service.php, ListRequest.php
src/Domains/Marketplace/Public/LineItem/                   -- Modern domain layer (read-only)
  Repository/{Entity,Repository,RepositoryConfigurator}.php
  Service.php, ListRequest.php

src/Rest/Marketplace/Controllers/PublicOrder.php           -- REST API controller
src/Rest/Marketplace/Controllers/PublicLineItem.php        -- REST API controller
src/Rest/Marketplace/Resources/PublicOrder/                 -- Resource + Collection
src/Rest/Marketplace/Resources/PublicLineItem/              -- Resource + Collection

application/views/admin/public_orders/{list,accept,reject}.php -- Admin views

Factory pattern: All jobs use Factories::publicMarketplace() to instantiate PublicOrders with registry config, ensuring consistent configuration.

Delivery bill support: The PublicOrders client includes checkIfDeliveryBillExists($orderCode) and getOrderDeliveryBill($orderCode) methods for retrieving SYSTEM_DELIVERY_BILL documents. These are called from the general orders admin controller (Adv_orders_admin) rather than the Public-specific admin controller.

Data Model ​

public_orders ​

ColumnTypeDescription
order_idvarchar(255) PKMirakl order ID (string)
stateenumopen, accepted, rejected, cancelled, expired, dispatched, delivered, partially_returned, returned
invoicetinyint(1)Invoice requested flag
is_tracking_senttinyint(1)Tracking info sent to Mirakl
is_senttinyint(1)Ship notification sent to Mirakl
can_canceltinyint(1)Whether order can be cancelled
order_datedatetimeOrder creation date
has_invoicetinyint(1)Has invoice attached
created_atdatetimeLocal record creation
updated_atdatetimeLast local update
shipping_deadlinedatetimeMust-ship-by date
acceptance_until_datedatetimeAccept/reject deadline
shipping_pricedecimal(10,2)Shipping cost
total_pricedecimal(10,2)Order total
commission_pricedecimal(10,2)Mirakl commission amount
order_typevarchar(255)Billing type (receipt/invoice)
customer_idvarchar(255)Mirakl customer ID
first_name, last_namevarchar(255)Customer name
emailvarchar(255)Customer email
regionvarchar(255)Shipping zone label
commentstextCustomer comments
got_customer_datatinyint(1)Whether customer address data has been backfilled from Mirakl
shop_order_idint(11)Linked internal order ID

public_line_items ​

ColumnTypeDescription
idint(11) PK AIAuto-increment ID
public_order_idvarchar(255)Parent order ID
order_line_idvarchar(255)Mirakl order line ID (used for line-item accept/reject)
product_namevarchar(255)Product title
quantityint(11)Ordered quantity
unit_pricedecimal(11,2)Price per unit
total_pricedecimal(11,2)Line total
eanvarchar(255)SKU/EAN for product matching

public_transporters_mapping ​

ColumnTypeDescription
transporter_idint(11) PKInternal transporter ID
codevarchar(255) PKMirakl carrier code

Configuration ​

Registry Keys (PUBLIC_MARKETPLACE group) ​

KeyTypePurpose
ENABLEDboolMaster toggle for the integration
API_KEYstringMirakl Shop API key
STORE_IDstringMirakl store identifier
DISABLE_PRODUCT_STOCK_CHECKboolBypass stock validation during accept (optional)

Registry Keys (XML_FEEDS group) ​

KeyPurpose
IS_ENABLED_PUBLIC_MARKETPLACEEnable product feed for Public
IS_PROTECTED_PUBLIC_MARKETPLACEToken-protect the feed URL
PUBLIC_MARKETPLACE_TOKENFeed authentication token
CUSTOM_PRICE_PUBLIC_MARKETPLACEEnable custom price modifier
CUSTOM_PRICE_PUBLIC_MARKETPLACE_MODIFIERPrice modifier percentage

Job Configuration (application/config/jobs.php) ​

php
'public_marketplace' => [
    'enabled' => false,  // Enable per client
    'commands' => [
        ['command' => 'GetPublicMarketplaceAwaitingOrders', 'schedule' => '*/30 * * * *'],
        ['command' => 'SetTrackingPublicMarketplace', 'schedule' => '0 */1 * * *'],
        ['command' => 'SetPublicOrdersSent', 'schedule' => '0 */1 * * *'],
        ['command' => 'UpdatePublicOrdersStatus', 'schedule' => '0 */1 * * *'],
        ['command' => 'GetPublicMarketplaceShippingData', 'schedule' => '*/5 * * * *'],
    ]
]

REST API Routes ​

MethodPathAction
GET/rest/marketplace/public/orderCollection (filterable, sortable)
GET/rest/marketplace/public/order/itemSingle by filters
GET/rest/marketplace/public/order/{id}Single by ID (string PK)
GET/rest/marketplace/public/line-itemLine item collection
GET/rest/marketplace/public/line-item/itemSingle line item by filters
GET/rest/marketplace/public/line-item/{id}Single line item by ID

Client Extension Points ​

  • Job overrides: Create corresponding files in application/modules/job/libraries/
  • Admin controller override: application/modules/eshop/controllers/Public_orders_admin.php
  • Model override: application/modules/eshop/models/Public_orders_model.php
  • Transporter mapping: Admin UI for mapping internal transporters to Mirakl carrier codes (public_transporters_mapping table)
  • Product feed: Separate AdvPublicMarketplaceXml feed controller for Public product catalog
  • Stock check bypass: Per-client via PUBLIC_MARKETPLACE.DISABLE_PRODUCT_STOCK_CHECK

Business Rules ​

RuleDescription
Line-item acceptanceEach order line is individually accepted/rejected (unlike Shopflix full-order)
Acceptance deadlineOrders can only be accepted before acceptance_until_date expires
One-time acceptanceOrders with existing shop_order_id cannot be re-accepted
Transporter selectionAdmin selects a transporter during acceptance; carrier mapped to Mirakl code
Guest email randomizationGuest customer emails use uniqid() prefix to avoid collisions
Shipping data backfillCustomer address data not available at order creation; backfilled by separate job
Tracking carrier lookupCarrier codes resolved from Mirakl's carrier registry, not hardcoded
UTC to Athens conversionAll Mirakl timestamps converted from UTC to Europe/Athens
Commission trackingMirakl commission stored per order for financial reconciliation
Invoice from additional fieldsBilling type, tax code, tax office extracted from Mirakl additional_fields
Accepted orders = PAIDInternal order status set to PAID with PUBLIC_MARKETPLACE_PROVIDER