# Package Splitting Flow

This flow enables splitting a single marketplace order (or package) into multiple new packages under the same sales channel. It can be triggered in two distinct modes:

1. OMS Trigger Mode (Akinon OMS fires a webhook to the marketplace app)
2. External System Trigger Mode (Any external OMS / WMS / ERP or custom service calls the public flow-trigger endpoint directly)

Use OMS Trigger Mode if you already maintain package decisions inside Akinon OMS. Use External System Trigger Mode when package determination logic lives outside Akinon but you still want to drive marketplace synchronization.

At a high level the split operation:

* Validates that the source order / package exists and belongs to the channel.
* Validates `split_packages` feature flag is active.
* Creates new package rows / integration actions per provided grouping.
* Optionally carries over tracking related metadata (if already present) to target packages (implementation specific per marketplace).
* Logs the split result and returns a correlation id for auditing.

{% hint style="warning" %}
First, make sure that the **"split\_packages"** flag under **Feature Flags** in the relevant sales channel is set to **true**.

<img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-06347fdfca7922bcf729e49d47944704503e0dff%2Fimage.png?alt=media" alt="" data-size="original">
{% endhint %}

To configure the OMS Web Hook setting in Omnitron, follow this path:\
**Omnitron Left Main Menu > Akinon OMS > Settings > Web Hooks**

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdLZqr0oOdfqHIMoJzZLW2E-ZRUxw7s40e_8hHwogP_Ck8uG1nh7JL8wJC3Dz8u29WhadsgQYxi0juIchbh00vLqxzb-gl0QA9iIJ--tMbldM_CJwpxt__y4vRNvZ545gbbkgNIkg?key=LLcRkA1S2VxqctBeD39gOw" alt=""><figcaption></figcaption></figure>

After accessing this setting, click the **New Web Hook** button located at the top right of the screen. The following screen should appear:

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc_LkWlrZjjf8GkU7lOrx7n72Z1IHkZ345jqHpLGMGt5r2w7rVLOzoz55hq8s46KzqGyl6G9v8QQcmqCPgBwEqCxJtufGxS9TBvPx4mIBykMI2bTyGCWZf4d4wV-L_PzhnSFqxvOg?key=LLcRkA1S2VxqctBeD39gOw" alt=""><figcaption></figcaption></figure>

## 1. Akinon OMS Trigger Mode

The original (existing) configuration path—Akinon OMS emits a webhook to the marketplace application which then executes the split logic.

**Channel Settings:**\
`split_packages` flag must be enabled to use Akinon OMS Trigger Mode

**Webhook Settings:**

*Target URL:*\
In the field shown in the screenshot above, enter the URL generated in the following format:

```
https://{mp_frontend_url}/flow-trigger/{mp_frontend_url_slug}/split_packages
```

The variables used here are configured as explained below:

*mp\_frontend\_url:*\
Log in to <https://console.akinoncloud.com> using the credentials provided by Akinon. From the left main menu, select **Projects**.\
In the list that appears, click on the **Applications** link located above the relevant project:

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcOQUL-1fBZplWJUtapPES2trbW8kV3nYGNeGWzitYMETGSR18YFWj5YABz8Df7XxrKxESBIJLVoMUM-vfHa8KC6aXVElVOYcXJFx1GGyi-t_FDD1sDPj6PHP8HsbYxmQHaZ_Kdsg?key=LLcRkA1S2VxqctBeD39gOw)

On the screen that appears, scroll down to the **Applications** list at the bottom of the page and select the marketplace application (e.g., N11).

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe8aWyK7_MyXA6zYZgsysWvIM9LKbzCRlmMoV5Hj6R2RBQ0TMUgsU0R5v0IJpn1OOMMI9bP56E6ZCV0sH6k5u9m9AR9BPZjTN9yDuaPDFkUXzI6QSMoHqlhYKCdGNIO6SwJelUtFA?key=LLcRkA1S2VxqctBeD39gOw" alt=""><figcaption></figcaption></figure>

On the next screen, locate the URL field in the section shown below. The part of the URL in the format **“xxxxxxxx.lb.akinoncloud.com”** corresponds to the **`mp_frontend_url`** variable.\
Use only the **`xxxxxxxx`** portion as the value for **`mp_frontend_url`** (`{mp_frontend_url}.lb.akinoncloud.com`).

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcX5TXdB-23yMtidxDONUudZn5gVEtTaJx81SAqlsnwkxC8NsvfB2yoo4CZYLg7LYfqKPPWg5F_1U3Rn93CkKU5oG0tX0WI29cZS_pqNEm2WTIzCtxqEQwmG56KEKLtQIEoyGIm?key=LLcRkA1S2VxqctBeD39gOw" alt=""><figcaption></figcaption></figure>

*Event Type:*\
Enter the value in the following format:

```
order.split_package
```

*Endpoint for Retrieving the `oms_channel_id` Variable:*\
An example cURL request to this endpoint is as follows:

```sh
curl --location 'https://{omnitron_url}.omnitron.akinon.net/api/v1/oms/channels/?limit=9999&page=1' \
--header 'Authorization: Token {omnitron_token}'
```

From the list of channels returned, retrieve the ID of the marketplace channel, as shown in the example below:

```json
{
  "id": 298, //get this id
  "channel_type": "sales_channel",
  "created_date": "2024-11-12T13:19:15.233646Z",
  "modified_date": "2025-04-17T09:04:10.620808Z",
  "omnitron_id": 564,
  "name": "N11:1750_Channel",
  "is_active": true
}
```

{% hint style="info" %}
The **channel ID** mentioned here refers to the **OMS channel ID**, not the **Omnitron channel ID**.
{% endhint %}

**Additional Headers:**

```
Authorization: Token {omnitron_user_token}
```

The **omnitron\_user\_token** variable used here refers to the dedicated **Omnitron user token**.

**Config:**\
Enter the **OMS channel ID** as the channel ID.

```
{"channel_id": 298}
```

**Retry Countdown Config:**

```
{"choice":"fixed","kwargs":{"seconds":120}}
```

### 1.1 Payload Structure (OMS Mode)

When Akinon OMS triggers the webhook it sends a JSON body (simplified) similar to:

```json
{
    "payload": {
        "number": "******************-749200412317",
        "packages": [
            {
                "number": "******************-749200412317",
                "packageitem_set": [
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-1"
                            }
                        }
                    },
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-2"
                            }
                        }
                    }
                ],
                "state": {
                    "enum_value": "550"
                }
            },
            {
                "number": "******************-749200412317P2",
                "packageitem_set": [
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-3"
                            }
                        }
                    },
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-4"
                            }
                        }
                    },
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-5"
                            }
                        }
                    }
                ],
                "state": {
                    "enum_value": "550"
                }
            }
        ]
    }
}
```

Notes:

* `packageitem_set` should be unique per new package (idempotency for retries).
* The sum of quantities per SKU across new packages must equal the original package quantities for that SKU (unless partial split rules are supported by a specific channel—default: strict equality).
* OMS handles signature / auth internally—no manual headers beyond the configured Authorization.

***

## 2. External System Trigger Mode

In this mode any authorized external system calls the marketplace application endpoint directly. Use this when package split logic is executed outside Akinon OMS.

### 2.1 Endpoint

```
POST https://{mp_frontend_url}.lb.akinoncloud.com/flow-trigger/{mp_frontend_url_slug}/split_packages
```

### 2.2 Authentication

Add header:

```
Authorization: Token {omnitron_user_token}
```

Tokens must belong to a user with permission to operate on the target channel. Rotate tokens according to your security policy.

### 2.3 Required Feature Flag

Channel config feature flag `split_packages` must be `true`. If disabled the endpoint returns 400.

### 2.4 Request Body Schema

```json
{
    "payload": {
        "number": "******************-749200412317",
        "packages": [
            {
                "number": "******************-749200412317",
                "packageitem_set": [
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-1"
                            }
                        }
                    },
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-2"
                            }
                        }
                    }
                ],
                "state": {
                    "enum_value": "550"
                }
            },
            {
                "number": "******************-749200412317P2",
                "packageitem_set": [
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-3"
                            }
                        }
                    },
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-4"
                            }
                        }
                    },
                    {
                        "order_item": {
                            "extra_field": {
                                "id": "749200412317-5"
                            }
                        }
                    }
                ],
                "state": {
                    "enum_value": "550"
                }
            }
        ]
    }
}
```

**Field Explanations**

| JSON Path                                                        | Required    | Type           | Description                                                                                                                                                                                                     |
| ---------------------------------------------------------------- | ----------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `payload.number`                                                 | Yes         | string         | Source (original order or package) number being split. Must match an existing order/package for the channel.                                                                                                    |
| `payload.packages`                                               | Yes         | array          | List of resulting packages to create from the source. Each element represents one new package.                                                                                                                  |
| `payload.packages[].number`                                      | Optional    | string         | Pre-assigned identifier for the new package. If omitted the backend generates a deterministic value. Useful for external systems that need stable references.                                                   |
| `payload.packages[].packageitem_set`                             | Yes         | array          | Items (order lines) included in this new package. Total quantity per SKU across all new packages must equal the source package/order (if quantity not provided backend enforces conservation by item identity). |
| `payload.packages[].packageitem_set[].order_item`                | Yes         | object         | Wrapper referencing the original order item.                                                                                                                                                                    |
| `payload.packages[].packageitem_set[].order_item.extra_field.id` | Yes         | string         | External (extra\_field) identifier of the original order item (or sub-line). Must be unique per item within the source; reused values in retries ensure idempotency (no duplicate package creation).            |
| `payload.packages[].state`                                       | Optional    | object         | Initial state for the new package. Defaults to channel’s base state (e.g. "Created" / enum 100) if omitted.                                                                                                     |
| `payload.packages[].state.enum_value`                            | Conditional | string/integer | Enumeration value for the initial state. Required only if `state` provided. Example: "550". Values like "900" (ignore/canceled) may be skipped by the flow depending on business rules.                         |

Notes:

* OMS Trigger Mode may use `order_item.omnitron_id` instead of `order_item.extra_field.id`; External System Trigger Mode uses the `extra_field.id` form shown here—only one path is required per mode.
* Idempotency: Retrying with the same set of `extra_field.id` values does not duplicate already created packages; missing ones are added, completed ones are ignored.
* Quantity (`quantity`) may be mandatory for some channels; if absent the backend assumes full conservation based on original item mappings.

### 2.5 Response

You can process status code, 200 is success, rest is error.

### 2.6 Security Considerations

* Use a dedicated integration token with least privileges.
* Log and audit `correlation_id` for traceability.

### 2.7 Monitoring & Troubleshooting

* Logs related to split packaging can be found under the Split Packages title in the log screens.
* If a request returns an error, retry until the process completes.
* If a partial failure occurs (rare), retry with the exact same body; the service must not duplicate successfully created packages.

### 2.8 External Mode Quick Checklist

1. Ensure `split_packages` flag = true.
2. Obtain OMS `channel_id` (not Omnitron id).
3. Collect `order_number`. If splitting an existing package (not just an order), also collect `original_package_id` and include it in the payload.
4. Plan package grouping and validate quantity conservation.
5. Generate unique package item set per new package.
6. POST payload with Authorization header.
7. Log `correlation_id` and created package ids.
8. Handle / retry idempotently on network errors.

***

## 3. Operational Notes

* Splitting is currently a one-way operation; merging packages is not supported in this flow.
* After a successful split, downstream flows (price, stock, shipping updates) will reference the new package entities automatically.
* If a package was already dispatched/shipped, splitting may be rejected depending on marketplace rules (future enhancement: pre-check dispatch status).

## 4. Changelog

| Date       | Change                                                                                |
| ---------- | ------------------------------------------------------------------------------------- |
| 2025-10-20 | Added External System Trigger Mode, validation & error taxonomy, idempotency guidance |
| 2025-09-12 | Initial OMS-trigger documentation                                                     |
