Function Description

Pipeline Initializer

The Pipeline Initializer of the Pacemaker Order Update will get all file patterns with the file pattern provider and search for matching files in the import directory.

By default, the import directory is var/pacemaker/import-order-update. This directory is dedicated to the Pacemaker Order Update component and is separate from the Pacemaker Product Import directory (var/pacemaker/import), which is scanned recursively by the product import and must not contain order update files.

If files were found, the corresponding file reader will be applied, which returns all created notification documents.

As soon as all documents were collected, the pipeline initializer removes all files from the import directory and invokes the Dispatcher.

File Pattern Provider

First, each instance (e.g. shipment, invoice, …​) has to define a file pattern in the di.xml. This file pattern is used to find the file in the Pacemaker directory.

This declaration consists of the following parts:

  • The pattern instance with a file pattern and the import path for the xml and json format

The file pattern provider will return all declared file patterns.

The following virtual types are declared by default, one pair (JSON and XML) per supported document type. All of them use var/pacemaker/import-order-update as the default import path:

Module Virtual Type Glob Pattern

techdivision/order-update-file-system-observer-shipment

ShipmentFilePattern

shipment*.json

techdivision/order-update-file-system-observer-shipment

ShipmentXmlFilePattern

shipment*.xml

techdivision/order-update-file-system-observer-invoice

InvoiceFilePattern

invoice*.json

techdivision/order-update-file-system-observer-invoice

InvoiceXmlFilePattern

invoice*.xml

techdivision/order-update-file-system-observer-cancellation

CancellationFilePattern

cancellation*.json

techdivision/order-update-file-system-observer-cancellation

CancellationXmlFilePattern

cancellation*.xml

techdivision/order-update-file-system-observer-creditmemo

CreditmemoFilePattern

creditmemo*.json

techdivision/order-update-file-system-observer-creditmemo

CreditmemoXmlFilePattern

creditmemo*.xml

Every virtual type can get overridden per project via a custom di.xml, e.g. to point a single document type to a different directory or to disable it (disabled argument).

Example of the file pattern definitions for all four document types
<type name="TechDivision\OrderUpdateFileSystemObserver\Model\FilePatternProvider">
    <arguments>
        <argument name="configuration" xsi:type="array">
            <item name="shipment" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\ShipmentFilePattern</item>
            </item>
            <item name="shipmentxml" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\ShipmentXmlFilePattern</item>
            </item>
            <item name="invoice" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\InvoiceFilePattern</item>
            </item>
            <item name="invoicexml" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\InvoiceXmlFilePattern</item>
            </item>
            <item name="cancellation" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\CancellationFilePattern</item>
            </item>
            <item name="cancellationxml" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\CancellationXmlFilePattern</item>
            </item>
            <item name="creditmemo" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\CreditmemoFilePattern</item>
            </item>
            <item name="creditmemoxml" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserver\Virtual\CreditmemoXmlFilePattern</item>
            </item>
        </argument>
    </arguments>
</type>

<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\ShipmentFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">shipment*.json</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>
<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\ShipmentXmlFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">shipment*.xml</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>

<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\InvoiceFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">invoice*.json</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>
<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\InvoiceXmlFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">invoice*.xml</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>

<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\CancellationFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">cancellation*.json</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>
<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\CancellationXmlFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">cancellation*.xml</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>

<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\CreditmemoFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">creditmemo*.json</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>
<virtualType name="TechDivision\OrderUpdateFileSystemObserver\Virtual\CreditmemoXmlFilePattern" type="TechDivision\OrderUpdateFileSystemObserver\Model\BaseFilePattern">
    <arguments>
        <argument name="globPattern" xsi:type="string">creditmemo*.xml</argument>
        <argument name="importPath" xsi:type="string">var/pacemaker/import-order-update</argument>
    </arguments>
</virtualType>

File Reader Provider

The file reader provider is another di configuration, which each instance has to declare. This definition is used to read the files for further processing.

Here you can also declare the reader for json and xml files. The Reader gets the content of the file and creates the notification document. Finally, it renames the file with a prefix.

Example of the shipment file reader definition
<type name="TechDivision\OrderUpdateFileSystemObserver\Model\FileReaderProvider">
    <arguments>
        <argument name="configuration" xsi:type="array">
            <item name="shipment" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_key" xsi:type="string">shipment</item>
                <item name="reader_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserverShipment\Model\ShipmentFileReader</item>
            </item>
            <item name="shipmentxml" xsi:type="array">
                <item name="disabled" xsi:type="boolean">false</item>
                <item name="pattern_key" xsi:type="string">shipmentxml</item>
                <item name="reader_instance" xsi:type="object">TechDivision\OrderUpdateFileSystemObserverShipment\Virtual\ShipmentXmlFileReader</item>
            </item>
        </argument>
    </arguments>
</type>

<type name="TechDivision\OrderUpdateFileSystemObserverShipment\Model\ShipmentFileReader">
    <arguments>
        <argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Json</argument>
    </arguments>
</type>
<virtualType name="TechDivision\OrderUpdateFileSystemObserverShipment\Virtual\ShipmentXmlFileReader" type="TechDivision\OrderUpdateFileSystemObserverShipment\Model\ShipmentFileReader">
    <arguments>
        <argument name="shipmentResolver" xsi:type="object">TechDivision\OrderUpdateFileSystemObserverShipment\Model\Resolver\Virtual\ShipmentResolverChain</argument>
        <argument name="serializer" xsi:type="object">TechDivision\OrderUpdateNotificationDispatcherApi\Model\Serializer\XmlSerialize</argument>
    </arguments>
</virtualType>

Notification Dispatcher

This dispatcher receives all notification documents and filters and groups the given documents by order. After that, a pipeline will be spawned for each notification and the entry will be saved to the pacemaker_order_update_notification table.

The first step of the pipeline is received by the corresponding notification handler from each instance (e.g. shipment, invoice …​). This is another Chain, which determines which step has to be initialized.

Example of the invoice handler definition
<type name="TechDivision\OrderUpdateNotificationDispatcherApi\Api\NotificationHandlerInterface">
    <arguments>
        <argument name="handlers" xsi:type="array">
            <item name="order.update.invoice" xsi:type="object">TechDivision\OrderUpdateInvoice\Model\InvoiceHandler</item>
        </argument>
    </arguments>
</type>

In the end, the move files step will be added to the pipeline.

Rest Api

The module Pacemaker Order Update Api (TechDivision_PacemakerOrderUpdateApi) provides a REST endpoint that allows external systems such as ERP or WMS to deliver order update files directly into Magento over HTTP. The API acts as a "Dumb Pipe": it accepts a filename and a Base64-encoded payload, validates the filename for security, decodes the payload, and writes the raw file to var/pacemaker/import-order-update/. No business logic is executed during the API call itself — all further processing is handled asynchronously by the Pacemaker pipeline.

The target directory is controlled by the ApiFilePattern virtual type’s basePath argument (module techdivision/pacemaker-order-update-api) and can get overridden per project via a custom di.xml.

Endpoint

Property Value

Method

POST

URL

/rest/V1/pacemaker/import/order-update-api

Content-Type

application/json

ACL Resource

Magento_Backend::pacemaker_order_update_api

Authentication & ACL

The endpoint requires a valid Magento Integration Token passed as a Bearer token in the Authorization header. In addition, the integration must be granted the ACL resource Magento_Backend::pacemaker_order_update_api.

The following steps are required to authorize an external system:
  • In the Magento Backend, navigate to System  Integrations

  • Create or edit an integration and assign the permission Pacemaker Order Update Api under Pacemaker - Enterprise Integration Platform > Order Update

  • Copy the generated access token and use it as a Bearer token in all API requests

Without the ACL permission, the API returns HTTP 403 Forbidden even if the token itself is valid.

Request Format

The request body is a JSON object with a source wrapper containing two required fields. The file content must be Base64-encoded before being sent.

Field Type Required Description

source.filename

string

Yes

The name of the file to be stored. Must end with .json or .xml. See [rest-api-filename-validation] for all validation rules.

source.data

string

Yes

The Base64-encoded content of the order update file. Strict Base64 validation is applied — invalid characters cause an immediate error.

Example request body
{
    "source": {
        "filename": "order-update-000000123.json",
        "data": "ewoia2V5b25lIjogImtleW9uZSIsCiJrZXl0d28iOiAia2V5dHdvIgp9"
    }
}

Filename Validation Rules

The API enforces strict security checks on the submitted filename to prevent injection attacks and directory traversal. All checks are applied in the listed order. The first failing check aborts the request with HTTP 400 Bad Request.

Rule Description

Not empty

The filename must not be an empty string.

No null bytes

The filename must not contain null byte characters (\0). Null bytes can cause PHP’s filesystem functions to truncate the filename at the wrong position.

No path traversal

The filename must not contain .. sequences.

No path separators

The filename must not contain / or \ characters.

Allowed characters only

Only alphanumeric characters, hyphens (-), underscores (), and dots (.) are permitted. Pattern: ^[a-zA-Z0-9\-\.]+$

Max length 255

The filename must not exceed 255 characters.

Allowed extension

The filename must end with .json or .xml (case-insensitive). Extensions such as .php, .sh, .exe, or .bat are rejected.

Filenames that do not pass all security checks are rejected immediately. Examples of rejected filenames: ../../etc/passwd, /etc/passwd, file;rm -rf /.xml, file&command.xml, order-update.php.

Response Format

On success, the API returns HTTP 200 OK with a JSON array containing a confirmation message and the absolute path of the saved file. On failure, the API returns the corresponding HTTP error code with a descriptive error message.

Index Type Description

[0]

string

Confirmation message: "Successfully saved import data"

[1]

string

Absolute filesystem path to the saved file.

Response on success (HTTP 200)
[
    "Successfully saved import data",
    "/var/www/html/var/pacemaker/import-order-update/order-update-000000123.json"
]
Response on validation error (HTTP 400)
{
    "message": "Invalid filename: only alphanumeric characters, dash, underscore and dot are allowed."
}

File Persistence

Accepted files are written to the Pacemaker order update import directory on the Magento server. The target path is var/pacemaker/import-order-update/{filename}.

The following applies to file storage:
  • The directory var/pacemaker/import-order-update/ is created automatically if it does not yet exist

  • The Base64 payload is decoded in strict mode — the raw binary result is written verbatim to disk without any transformation

  • Magento’s internal Filesystem abstraction is used for all write operations

Duplicate filenames are rejected. If a file with the same name already exists in var/pacemaker/import-order-update/, the API returns HTTP 400 Bad Request with the message "File already exists: <filename>". Re-submission of the same filename is not possible without first removing the existing file from the server.

After the file is persisted, no further action is taken by this API. The Pipeline Initializer picks up files from var/pacemaker/import-order-update/ and processes them asynchronously.

Error Handling

HTTP Status Condition Error Message

200 OK

Success

— (see response format above)

400 Bad Request

Filename is empty

"Filename cannot be empty"

400 Bad Request

Null byte in filename

"Invalid filename: null byte detected"

400 Bad Request

Path traversal in filename (..)

"Invalid filename: directory traversal detected"

400 Bad Request

Path separator in filename (/ or \)

"Invalid filename: path separators not allowed"

400 Bad Request

Disallowed characters in filename

"Invalid filename: only alphanumeric characters, dash, underscore and dot are allowed"

400 Bad Request

Filename exceeds 255 characters

"Invalid filename: maximum length is 255 characters"

400 Bad Request

File extension missing

"Invalid filename: file extension is required"

400 Bad Request

File extension not .json or .xml

"Invalid filename: only json, xml extensions are allowed"

400 Bad Request

Base64 decoding fails or produces empty output

"Failed to decode/store base64 data"

400 Bad Request

File with the same name already exists

"File already exists: <filename>"

401 Unauthorized

Missing or invalid Bearer token

Magento standard authentication error

403 Forbidden

Valid token but ACL permission not granted

Magento standard ACL error