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