> For the complete documentation index, see [llms.txt](https://docs.fulfillmenttools.com/documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fulfillmenttools.com/documentation/by-pillar/advanced-order-routing/complex-routing-with-combinatorics/calculations-within-routing/transport-cost-calculation-logic.md).

# Transport cost calculation logic

Transport costs represent the expenses incurred when goods are shipped between facilities or from a facility to the consumer. These costs typically depend on the shipping service provider, the parcel or packaging type used, the destination country, and, depending on the chosen logic, additional factors such as weight or volume.

## Packing logic and shipping cost calculation

fulfillmenttools applies bin-packing logic to distribute ordered items across available packaging units and calculates shipping costs accordingly.

There are two effort levels are available:

* [Standard logic](#standard-logic)
* [Advanced logic](#advanced-logic)

The logic applied to a given transfer within a sourcing path depends on how the `packagingUnitByContexts` object is configured in the respective [facility connection](https://docs.fulfillmenttools.com/documentation/by-pillar/advanced-order-routing/complex-routing-with-combinatorics/network-model/facility-connection).

If a packaging unit is referenced within a facility connection, the `packagingUnitsByContexts` property may only define the corresponding transit times. All other information is inherited from the referenced `packagingUnit` and must not be redefined at the facility connection level.

{% hint style="info" %}
For details on how a fulfillment network is defined by facility connections and how they are structured, see the [Facility connection](/documentation/by-pillar/advanced-order-routing/complex-routing-with-combinatorics/network-model/facility-connection.md) article.
{% endhint %}

### Determining which logic applies

The active logic for a given transfer is determined only by how `packagingUnitByContexts` is configured in the corresponding facility connection:

<table><thead><tr><th width="397.671875">Configuration</th><th>Applied logic</th><th width="288.93359375">Example</th></tr></thead><tbody><tr><td>Packaging unit data is defined inline in <code>packagingUnitByContexts</code> in the facility connection.</td><td>Standard</td><td><pre class="language-json"><code class="lang-json">"packagingUnitsByContexts": [
    {
        "context": [
            {
                ,
                "type": "CATEGORY",
                "values": [
                    "WEBSHOP"
                ]
            }
        ],
        "packagingUnits": [
            {
                "name": "Parcel XXL",
                "priority": 1,
                "dimensions": {
                    "height": 1000,
                    "length": 1000,
                    "width": 1000,
                    "maxWeightInGram": 1000
                }
                "transitTime": {
                    "maxTransitDays": 3,
                    "minTransitDays": 1
                }
            }
        ]
    }
]
</code></pre></td></tr><tr><td>The facility connection <code>packagingUnitByContexts</code> references an external <code>packagingUnit</code></td><td>Advanced</td><td><pre class="language-json"><code class="lang-json">"packagingUnitsByContexts": [
    {
        "context": [
            {
                ,
                "type": "TAG_REFERENCE",
                "values": [
                    "WEBSHOP"
                ]
            }
        ],
        "packagingUnits": [
            {
                "name": "Parcel XXL",
                "packagingUnitRef": "2384df9220fj20j2d0",
                "priority": 1,
                "transitTime": {
                    "maxTransitDays": 3,
                    "minTransitDays": 1
                }
            }
        ]
    }
]
</code></pre></td></tr></tbody></table>

### Mixed logic within a sourcing route

The standard and advanced logics aren't mutually exclusive. Within a single sourcing route, different transfers can each apply a different logic, depending on how the respective facility connection is configured.

<figure><img src="https://4170739437-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLrrr5jgTsDuR38gNJIrm%2Fuploads%2Fs5EZg2aGcdFgWIho7uIL%2FMixed%20logic%20winthin%20a%20sourcing%20route.png?alt=media&amp;token=2f5c5369-0981-44e2-b533-c884f8980778" alt="" width="375"><figcaption></figcaption></figure>

### Standard logic

Standard logic suits scenarios where the carrier portfolio within the network is relatively homogeneous, and the pricing structure is simple, with only marginal differences between carriers.

The standard packing logic applies when packaging unit information is defined directly within the facility connection object in `packagingUnitByContexts`. No reference to an external collection is required.

A first-fit decreasing algorithm is applied to assign items to packaging units. This approach offers sufficient accuracy across a wide range of use cases and improves calculation speed.

{% hint style="info" %}
**First-fit decreasing algorithm**

* Check whether the largest item fits in the highest-priority packaging unit (usually the smallest and cheapest to ship), based on the item's and package's dimensions.
* If it doesn't fit, the next packaging unit is tried (in order of priority). If it fits, check whether the next item fits in this package, and so on.
* Do this for every item. If a packaging unit is full (considering its dimensions and restrictions), check for a second package, starting again with the highest-priority package.
* A packaging unit is full when the sum of the item volumes exceeds the inner parcel volume. However, an empty space (`volumeBufferInPercent`) might be deducted to ensure that the items really fit. Note: Geometries aren't considered, and no "Tetris" is played. So, it's important to leave some empty space.
* A parcel is also full if the maximum item amount is reached. This feature ensures that only one item is placed in a single package.
  {% endhint %}

Shipping costs are calculated using a standardized formula applied uniformly across all transfers.

### Advanced logic

The advanced logic is particularly suitable when the carrier portfolio is broad and includes multiple shipping methods (for example, parcel, pallet, bulky goods, and two‑person handling).

In such environments, an optimized packing strategy combined with price‑optimized routing can significantly reduce fulfillment costs. This approach is especially beneficial when at least one of the following conditions applies:

* The network uses different parcel types
* Items vary significantly in size or dimensional characteristics
* The cost structure requires precise optimization across heterogeneous carriers

It should also be noted that the advanced logic is computationally more expensive and may not be ideal for very large networks where performance constraints are critical.

The advanced packing logic applies when `packagingUnitByContexts` within the facility connection references packaging units defined in a separate collection, rather than containing the packaging unit information inline.

{% hint style="info" %}
**Advanced algorithm**

* **Finds the cheapest combination of packaging units:** fulfillmenttools evaluates all feasible ways to group the ordered items into packaging units and selects the option with the lowest total cost.
* **Considers all available shipping options:** From standard parcels to freight and pallet shipments, fulfillmenttools automatically picks the best packaging unit type for each part of your order.
* **Respects physical constraints:** Item dimensions, weight limits, and carrier requirements are all factored in to ensure your shipment is valid and deliverable.
* **Guaranteed lowest shipping cost:** The result will always be the optimized packaging solution, not just a "good enough" estimate.
  {% endhint %}

Unlike the first-fit decreasing approach, the advanced logic evaluates all possible distribution combinations within the solution space. The goal is cost optimization: the algorithm identifies the item distribution across available facilities and their packaging units that yields the lowest overall shipping cost.

Packaging units defined in the separate collection also support a much broader set of configurable properties, including girth measurement, volumetric weight, a configurable weight basis, detailed price tables dependent on weight and destination region, and surcharges with a defined application order, calculation scope, and context.

### Pricing components

The transfer price consists of a base price, optional cost coefficients, and surcharges. The following sections describe which quantity a price is resolved against, how price tiers are defined, and how surcharges are applied. They apply to all packaging unit types. The type-specific sections describe only what differs per type.

Before a price can be resolved, fulfillmenttools determines the chargeable quantity of a packaging unit.

#### **Weight basis**

By default, fulfillmenttools calculates a packaging unit's weight from the article's regular weight (`weightPerUnit` in the listing attributes). Some carriers bill on an agreed weight instead of the real one. For these tariffs, `weightBasis` selects which article weight is used:

* `WEIGHT`: The article's regular weight (`weightPerUnit`). This is the default.
* `BILLABLE_WEIGHT`: The article's agreed billable weight (`billableWeightPerUnit`).

You can set `weightBasis` on the packaging unit and on the facility connection in `pricingPerTransfer`. If both are set and differ, the facility connection setting applies. If `BILLABLE_WEIGHT` is selected and an article has no billable weight maintained, the routing option is rejected rather than falling back to the regular weight.

#### Volumetric weight

Carriers commonly bill bulky but lightweight shipments by their volumetric weight. The optional `volumetricWeightFactor` converts the volume of a packaging unit into a comparable weight value:

$$
volumetric Weight  = \frac{(length ⋅width⋅
height)}{volumetricWeightFactor}
$$

The greater of the actual weight and the volumetric weight then determines the price tier. Without `volumetricWeightFactor`, only the actual weight is used. The field is mandatory for pallets and optional for all other packaging unit types.

The optional `maxVolumetricWeight` caps the volumetric weight at the configured value in grams. It's a billing cap only and doesn't restrict what the packaging unit can physically hold. The below tariff is modeled by combining both fields:

$$
billable weight = max(actual weight, min(volumetric weight, cap))
$$

**Example with `volumetricWeightFactor` 6000 and `maxVolumetricWeight` 30000**

| Dimensions       | Actual weight | Volumetric weight | Capped | Chargeable |
| ---------------- | ------------- | ----------------- | ------ | ---------- |
| 60 × 50 × 40 cm  | 8 kg          | 20 kg             | 20 kg  | 20 kg      |
| 100 × 90 × 80 cm | 5 kg          | 120 kg            | 30 kg  | 30 kg      |
| 40 × 30 × 20 cm  | 15 kg         | 4 kg              | 4 kg   | 15 kg      |
| 100 × 90 × 80 cm | 35 kg         | 120 kg            | 30 kg  | 35 kg      |

#### Pricing basis

Weight isn't the only quantity a tariff can be priced on. The optional `pricingBasis` defines which quantities are compared and in which unit the price table is interpreted:

* `pricingQuantities` lists the quantities to compare. Each is converted into `pricingUnit`, and the highest one determines the chargeable amount.
* `pricingUnit` is the unit the quantities are converted to and priced in: `GRAM`, `CUBIC_METER`, or `LOADING_METER`.

Conversions between quantities are configured on the packaging unit: `volumetricWeightFactor` converts volume to weight, `weightToVolumeFactor` converts weight to volume, and `ldmToWeightFactor` defines the grams equivalent to one loading meter. Loading meters are derived from the floor space of the packed unit and the loading width of the vehicle, which is configured in `transportDetails.vehicleWidthInMeters` on the facility connection.

#### Price tiers and zones

The base price is derived from the `pricing` array, which defines price tiers. Each tier specifies an `upperThreshold` and the corresponding price. The tier whose `upperThreshold` is equal to or greater than the chargeable quantity applies.

Two approaches are available for shipments that exceed all defined tiers:

* The highest configured `upperThreshold` matches the packaging unit's `maxWeight` exactly, ensuring no shipment exceeds the defined tiers.
* An `overflowFactor` is defined, which specifies the additional cost per unit above the highest `upperThreshold`.

This approach allows pricing to extend beyond the last tier without requiring an exhaustive weight table.

Optionally, price tiers can be differentiated by destination region using the `zone` field within each `pricing` object. A zone is defined by the ISO 3166-2 country code, followed by a dash and the first digits of the destination postal code (for example, `DE-50` for Cologne, Germany). This allows different prices to apply based on the delivery location. This is particularly relevant for freight and pallet shipments, where regional pricing is standard practice among carriers, but it also applies to parcel shipments.

**Rate-based tiers**

Carriers often quote a per-unit rate instead of a flat tier price, for example, €21.10 per 100 kg up to 4000 kg. Modeling this as flat tiers would require hundreds of generated rows. Instead, a tier can define an optional `factor` alongside `price`:

$$
tierPrice = \lceil \frac{quantity}{factor} \rceil ⋅ price
$$

* `factor` is interpreted in the unit given by `pricingBasis.pricingUnit`.
* The quantity is always rounded up to the next started unit. Exact billing is expressed as `factor: 1`.
* Without a `factor`, the `price` remains a flat price for the tier.

For example, a tier with `upperThreshold` 4000000 (4000 kg), `price` €21.10, and `factor` 100000 (100 kg) charges a 2350 kg shipment as ⌈2350 / 100⌉ × €21.10 = 24 × €21.10 = **€506.40**.

#### Surcharges

Surcharges are charged on top of the resolved base price. They are configured on two levels:

* `surchargesPerPackagingUnits` within `packagingPricingDetails` applies once per packaging unit. A surcharge on a packaging unit that's used five times in a transfer is charged five times.
* `surchargesPerTransfer` on the facility connection applies once per transfer, after the packaging units of that transfer have been summed up.

Both levels support the same three surcharge types:

| Type                       | Configuration                 | Charged amount                                         |
| -------------------------- | ----------------------------- | ------------------------------------------------------ |
| `ABSOLUTE_SURCHARGE_TYPE`  | `amount`                      | The fixed amount                                       |
| `RELATIVE_SURCHARGE_TYPE`  | `percentage`                  | The percentage of the amounts in its calculation scope |
| `THRESHOLD_SURCHARGE_TYPE` | `minimumAmount`, `percentage` | The greater of the two                                 |

A threshold surcharge models tariffs of the form "at least €X, but Y% once the shipment is large enough", for example, a cash on delivery fee. It resolves to a single absolute amount at calculation time and is then treated like an absolute surcharge.

**Example of a threshold surcharge: cash on delivery, `minimumAmount` €5.80 and `percentage` 3**

* Base of €150.00: 3% is €4.50, which stays below the minimum, so €5.80 is charged.
* Base of €250.00: 3% is €7.50, which exceeds the minimum, so €7.50 is charged.

The break-even point is €5.80 / 0.03 = €193.33

**Application order**

The order in which surcharges are applied is result-relevant: with a base price of €5.00, an absolute surcharge of €1.00 and a relative surcharge of 10%, applying the absolute first yields €6.60, applying the relative first yields €6.50.

The optional `priority` places a surcharge in the application sequence of its level. All three surcharge types share one single sequence rather than being applied in separate passes. Values are applied in ascending order, and gaps are allowed.

If no surcharge of a packaging unit declares a `priority`, every percentage of that packaging unit is calculated on the base price only. If no surcharge of a transfer declares one, every percentage of that transfer is calculated on the base price and the packaging units together.

**Calculation scope**

By default, a relative or threshold surcharge is calculated on everything charged before it at its position in the sequence. The optional `calculationScope` restricts that base:

* `mode` is either `INCLUDE`, which names the charges the percentage is calculated on, or `EXCLUDE`, which names the charges it's not calculated on.
* `references` lists the charges the mode applies to. Each reference has a `kind`, an optional `level`, and, for `TENANT_SURCHARGE` references, a `tenantSurchargeType`.

| \`kind\`           | Selects                                                      |
| ------------------ | ------------------------------------------------------------ |
| `BASE_PRICE`       | The resolved base price                                      |
| `TENANT_SURCHARGE` | Every charge made under the referenced `tenantSurchargeType` |
| `PACKAGING_UNITS`  | Everything the packaging units of the transfer charged       |
| `GOODS_VALUE`      | The order's goods value shipped with the transfer            |

`PACKAGING_UNITS` and `GOODS_VALUE` are only available on transfer level. `GOODS_VALUE` allows a cash on delivery fee to be calculated against the value of the goods rather than against the freight charges.

The optional `level` restricts a reference to charges made on one pricing level, either `PACKAGING_UNIT` or `TRANSFER`. If omitted, charges of both levels are selected, so a `tenantSurchargeType` configured on both matches both. A reference that matches nothing contributes nothing.

Scoped surcharges are additive: two surcharges configured on the same scope are both calculated against that scope and don't compound.

**Example of ordering and scope**

Base price €5.00, absolute toll €2.00, absolute cash on delivery €3.00, relative fuel surcharge 10%:

* Fuel scoped to exclude the cash on delivery charge: 10% × €7.00 = €0.70, total **€10.70**
* Fuel without a scope, on the full running amount: 10% × €10.00 = €1.00, total **€11.00**

**Context**

By default, a surcharge always applies. The optional context restricts it to cases where the carrier charges it, for example, by payment method, product category, or destination. A context condition consists of a type, its values, and an optional `NOT` operator, which inverts the condition. Multiple conditions are combined with `AND`.

The supported context types are `CATEGORY`, `TAG_REFERENCE`, `TARGET_POSTALCODE`, and `TARGET_COUNTRY`.

An item-related condition is fulfilled as soon as at least one item in scope matches. A single dangerous goods item therefore triggers the surcharge for the whole packaging unit or transfer. During the cost calculation, a surcharge whose context doesn't match is excluded from the result.

{% hint style="info" %}
**Typical contextualized surcharges**

* A cash on delivery fee that only applies when the order carries the corresponding tag
* A dangerous goods surcharge that only applies to items of the category "dangerous goods"
* An island surcharge that only applies to specific destination postal codes
  {% endhint %}

#### Shipment-based pricing

For carriers that price a shipment as a whole instead of per package, a price matrix can be configured on the facility connection in `pricingPerTransfer`. The base price is then resolved once per transfer against the aggregated quantity of all its packaging units, and the prices configured on those packaging units are ignored. Surcharges are unaffected and are still applied on both levels.

See the [facility connection article](/documentation/by-pillar/advanced-order-routing/complex-routing-with-combinatorics/network-model/facility-connection.md) for the configuration.

### Packaging unit type-specific definitions and calculation logics

The following section describes the logic applied to each `packagingUnit` type. It outlines the available configuration options, including the attributes and restrictions that can be defined for each type.

Also, it explains the factors used for price calculation, which are provided through the `packagingPricingDetails` associated with each packaging unit. Different shipping methods need different pricing calculation logics. These logics are defined per `packagingUnit` type and must be maintained accordingly.

By default, all items are eligible for all packaging types unless this is explicitly restricted through `packagingUnitsByContexts.context[]` in the facility connection.

The optional `minItemQuantity` and `maxItemQuantity` define the item count a packaging unit is usable for. fulfillmenttols considers a packaging unit during shipment building only if the item count reaches `minItemQuantity`, allowing units such as a pallet to be used only from a certain number of single items upward. Without `minItemQuantity`, there is no lower bound. Both fields are available for all packaging unit types.

{% hint style="info" %}
All the following examples are using advanced logic. So, using the [packaging units endpoint](https://fulfillmenttools.github.io/fulfillmenttools-api-reference-ui/#post-/api/packagingunits).
{% endhint %}

#### Parcel

**Definitions and restrictions**

The `parcel` `packagingUnit` type can be used for standard parcel shipment, fully enclosed in a box. Three-dimensional constraints apply because carriers calculate costs and enforce size limits based on weight, height, length, and width.

The maximum permissible dimensions are defined through the mandatory `dimensions` object, which holds `maxHeight`, `maxWidth`, and `maxLength` in millimeters, and the mandatory `maxWeight` in grams. These values establish the physical limits for routing and packing decisions. If an article or article combination exceeds any of these dimensions, fulfillmenttools doesn't assign it to this packaging unit.

The optional `volumeBufferInPercent` lets you configure additional free space within the parcel to account for packaging materials or irregular article geometries.\
​\
The optional `maxItemQuantity` specifies the maximum number of items that may be placed in a single parcel. This configuration supports operational requirements such as handling hazardous goods or specialized packaging scenarios, including bottle shipments or flower logistics.\
\
**Pricing structure and calculation logic**

The shipping cost for a parcel unit is determined by the `packagingPricingDetails` configuration. The base price is resolved from the weight-based tiers in `pricing` as described in price tiers and zones, and the configured surcharges are added.

A parcel is priced by its actual weight unless `volumetricWeightFactor` is set. With the factor set, the greater of actual and volumetric weight determines the tier, as described in chargeable quantity and weight basis.

**Example parcel cost calculation**

Use the tabs below to click through the example scenario.

{% tabs %}
{% tab title="Definitions and restrictions" %}
We'll set the following definitions:

* **Maximum** **dimension**:
  * Maximum length: 120 cm
  * Maximum width: 60 cm
  * Maximum height: 60 cm
* **Maximum weight:** 31.5 kg
* **Volume buffer**: 5% (for packaging material)

{% code title="api/packagingUnits" %}

```json
"dimensions": {
      "maxWidth": 600,
      "maxHeight": 600,
      "maxLength": 1200
    },
    "maxWeight": 31500,
    "volumeBufferInPercent": 5,
```

{% endcode %}
{% endtab %}

{% tab title="Pricing details" %}

* **Pricing tiers**
  * Up to 2 kg: €3.00
  * Up to 5 kg: €4.00
  * Up to 10 kg: €7.00
  * Up to 31.5 kg: €11.00
* **Environmental surcharge per unit**: €1.50

{% code title="api/packagingUnits" %}

```json
"packagingPricingDetails": {
            "pricing": [
                {
                    "prices": [
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 300
                            },
                            "upperThreshold": 2000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 400
                            },
                            "upperThreshold": 5000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 700
                            },
                            "upperThreshold": 10000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 1100
                            },
                            "upperThreshold": 31500
                        }
                    ]
                }
            ],
            "surchargesPerPackagingUnits": [
                {
                    "type": "ABSOLUTE_SURCHARGE_TYPE",
                    "tenantSurchargeType": "Environmental surcharge",
                    "amount": {
                        "currency": "EUR",
                        "decimalPlaces": 2,
                        "value": 150
                    }
                }
            ]
        }
```

{% endcode %}
{% endtab %}

{% tab title="Items to pack" %}
**1 x item 1**

* 10 cm x 10 cm x 20 cm
* Weight per unit: 1.5 kg

**1x item 2**

* 20 cm x 40 cm x 80 cm
* Weight per unit: 6.1 kg

{% code title="listings.attributes for item 1" %}

```json
"attributes": [
                    {
                        "key": "weightPerUnit",
                        "value": "1500",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "height",
                        "value": "100",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "width",
                        "value": "100",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "length",
                        "value": "200",
                        "type": "NUMBER",
                        "category": "dimensions"
                    }
                ]
```

{% endcode %}
{% endtab %}

{% tab title="Result" %}

* 2 items need to be packed
* Items add up to a total weight of 7.6 kg (1.5 kg (item 1) + 6.1 kg (item 2)
* 7.6 kg has the corresponding pricing tier of up to 10 kg
* The up to 10 kg pricing tier is €7.00
* Add the mandatory environmental surcharge of €1.50

Total calculated costs: €7.00 + €1.50 = **€8.50**
{% endtab %}
{% endtabs %}

#### **Pallet**

**Definitions and restrictions**

This packaging unit type can be used for pallet-based shipment for heavier or bulk freight. In addition to three-dimensional constraints, a `volumetricWeightFactor` is required because freight carriers charge based on whichever is greater, the actual weight or volumetric (dimensional) weight. The factor converts physical volume into a comparable weight value for cost calculation. Common values are 5000 or 6000.

Additionally, a pallet may optionally define `minItemQuantity`, `maxItemQuantity`, and `volumeBufferInPercent`, which are evaluated the same way as parcel configuration. The optional `loadCarrierLength`, `loadCarrierWidth`, `loadCarrierHeight`, and `loadCarrierWeight` describe the empty load carrier itself, so that its own dimensions and tare weight are included in the packed unit.

**Pricing structure and calculation logic**

The shipping cost for a pallet unit follows the same zone-matching, weight-bracket, and surcharge logic as parcel units, with one additional step. Before the applicable price bracket is determined, fulfillmenttools calculates the shipment's volumetric weight using the mandatory `volumetricWeightFactor`. The greater of the actual weight and the volumetric weight is then used to select the price bracket. This reflects standard freight carrier practice, where oversized but lightweight shipments are billed based on dimensional weight rather than actual weight. Multi-currency pricing, the `overflowFactor`, and `surchargesPerPackagingUnits` apply in the same way as for parcel units.

**Example pallet cost calculation**

Use the tabs below to click through the example scenario.

{% tabs %}
{% tab title="Definitions and restrictions" %}
We'll set the following definitions:

* **Maximum** **dimension**:
  * Maximum length: 120 cm
  * Maximum width: 80 cm
  * Maximum height: 180 cm
* **Maximum weight:** 2000 kg
* **Volume buffer**: 5% (for packaging material)

{% code title="api/packagingUnits" %}

```json
"dimensions": {
      "maxWidth": 800,
      "maxHeight": 1800,
      "maxLength": 1200
    },
    "maxWeight": 2000000,
    "volumeBufferInPercent": 5,
```

{% endcode %}
{% endtab %}

{% tab title="Pricing details" %}

* **Pricing tiers**
  * Up to 100 kg: €30.00
  * Up to 200 kg: €40.00
  * Up to 300 kg: €48.00
  * ...
  * Up to 2000 kg: €200.00
* **Environmental surcharge per unit**: €1.50

{% code title="api/packagingUnits" %}

```json
"packagingPricingDetails": {
            "pricing": [
                {
                    "prices": [
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 3000
                            },
                            "upperThreshold": 100000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 4000
                            },
                            "upperThreshold": 200000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 4800
                            },
                            "upperThreshold": 300000
                        },
                        ...
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 20000
                            },
                            "upperThreshold": 2000000
                        }
                    ]
                }
            ],
            "surchargesPerPackagingUnits": [
                {
                    "type": "ABSOLUTE_SURCHARGE_TYPE",
                    "tenantSurchargeType": "Environmental surcharge",
                    "amount": {
                        "currency": "EUR",
                        "decimalPlaces": 2,
                        "value": 150
                    }
                }
            ]
        }
```

{% endcode %}
{% endtab %}

{% tab title="Items to pack" %}
**10 x item 1:**

* 100 cm x 15 cm x 5 cm
* Weight per unit: 25 kg

**40 x item 2**

* 60 cm x 20 cm x 1 cm
* Weight per unit: 1 kg

{% code title="listings.attributes for item 1" %}

```json
"attributes": [
                    {
                        "key": "weightPerUnit",
                        "value": "25000",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "height",
                        "value": "1000",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "width",
                        "value": "150",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "length",
                        "value": "50",
                        "type": "NUMBER",
                        "category": "dimensions"
                    }
                ]
```

{% endcode %}
{% endtab %}

{% tab title="Result" %}

* 50 items need to be packed
* The volumetric weight is lower than the real weight, so the real weight is used
* Items add up to a total weight of 290 kg (250 kg (10 x item 1 (25 kg)) + 40 kg (40 x item 2 (1kg))
* 290 kg has the corresponding pricing tier of up to 300 kg
* The up to 300 kg pricing tier is €48.00
* Add the mandatory environmental surcharge of €1.50

Total calculated costs: €48.00 + €1.50 = **€49.50**
{% endtab %}
{% endtabs %}

#### Bulky goods

**Definitions and restrictions**

This packaging unit type can be used for oversized or irregularly shaped items (for example, doors, bicycles, car tires, and so on) that can't be packed using a standard three‑dimensional box. Instead of height, length, and width, carriers for bulky goods typically apply girth‑based constraints, which express the combined circumference and longest dimension of a shipment.

For packaging units of this type, the maximum allowable girth (`maxGirth`) must be defined.

Carriers also enforce restrictions on maximum length (`maxLength`) and maximum weight (`maxWeight`). Optionally, a minimum and maximum number of items (`minItemQuantity`, `maxItemQuantity`) can be specified to limit how many articles may be consolidated into a single bulky‑goods unit. All of these fields are defined directly on the packaging unit, not within a `dimensions` object.

$$
girth = length + 2  (width + height)
$$

**Pricing structure and calculation logic**

The shipping cost for a bulky goods unit is calculated using the same zone-matching, tier, and surcharge model as parcel units.

Because bulky goods are defined by `maxLength` and `maxGirth` rather than three-dimensional box measurements, no volumetric weight is derived from the configured maximum dimensions. However, the packed unit reports the dimensions of the actual packing result, so a `volumetricWeightFactor` can be configured and is applied to those derived dimensions. See [dimensions of packed packaging units.](#dimensions-of-packed-packaging-units)

**Example bulky good cost calculation**

Use the tabs below to click through the example scenario.

{% tabs %}
{% tab title="Definitions and restrictions" %}
We'll set the following definitions:

* **Maximum** **dimension**:
  * Maximum length: 200 cm
  * Maximum girth: 300 cm
* **Maximum weight:** 31.5 kg

{% code title="api/packagingUnits" %}

```json
{
    "maxLength": 2000,
    "maxGirth": 3000,
    "maxWeight": 31500
}
```

{% endcode %}
{% endtab %}

{% tab title="Pricing details" %}

* **Pricing tiers**
  * Up to 31.5 kg: €25.00

{% code title="api/packagingUnits" %}

```json
{
    "packagingPricingDetails": {
        "pricing": [
            {
                "prices": [
                    {
                        "price": {
                            "currency": "EUR",
                            "decimalPlaces": 2,
                            "value": 2500
                        },
                        "upperThreshold": 31500
                    }
                ]
            }
        ]
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Items to pack" %}
**1 x item 1:**

* 140 cm x 60 cm x 7 cm
* Weight per unit: 19 kg

{% code title="listings.attributes for item 1" %}

```json
"attributes": [
                    {
                        "key": "weightPerUnit",
                        "value": "1900",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "height",
                        "value": "1400",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "width",
                        "value": "600",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "length",
                        "value": "70",
                        "type": "NUMBER",
                        "category": "dimensions"
                    }
                ]
```

{% endcode %}
{% endtab %}

{% tab title="Result" %}

* 1 item needs to be packed
* The `maxGirth` is 300 cm
* The girth of the item to pack is 274 cm (140 cm + 2(60 cm + 7 cm))
* The item is within the `maxGirth`
* The price is fixed at €25.00

Total calculated costs: **€25.00**
{% endtab %}
{% endtabs %}

#### Two-person handling

**Definitions and restrictions**

This packaging unit type is suitable for heavy or large items that require two-person delivery (for example, furniture). Three-dimensional constraints apply as with parcels. An additional optional `maxVolume` field is available for carriers that enforce a total cubic volume limit independent of individual dimensions. You can also apply `minItemQuantity` and `maxItemQuantity` restrictions.

**Pricing structure and calculation logic**

Volume-based pricing tiers define the shipping cost for two-person handling. For the surcharge model, the optional `overflowFactor` and all configured `surchargesPerPackagingUnits` are evaluated analogously to the other `packagingUnitTypes`. The optional `maxVolume` constraint on the unit determines whether a given set of items is eligible for this packaging unit. However, it doesn't affect the cost calculation.

Because two-person handling is a handling form rather than a fixed container, the packed unit reports the dimensions of the actual packing result. See [dimensions of packed packaging units.](#dimensions-of-packed-packaging-units)

**Example two-person handling cost calculation**

Use the tabs below to click through the example scenario.

{% tabs %}
{% tab title="Definitions and restrictions" %}
We'll set the following definitions:

* **Maximum** **dimension**:
  * Maximum length: 400 cm
  * Maximum width: 230 cm
  * Maximum height: 200 cm
* **Maximum weight:** 200 kg
* **Maximum volume:** 4 CBM

{% code title="api/packagingUnits" %}

```json
{
    "dimensions": {
        "maxWidth": 2300,
        "maxHeight": 2000,
        "maxLength": 4000
    },
    "maxWeight": 200000,
    "maxVolume": 40000000000
}
```

{% endcode %}
{% endtab %}

{% tab title="Pricing details" %}

* **Pricing tiers**
  * Up to 0.2 CBM: €20.00
  * Up to 0.4 CBM: €35.00
  * Up to 0.6 CBM: €37.00
  * Up to 0.8 CBM: €43.00
  * Up to 1.0 CBM: €48.00
  * Every additional 0.1 CBM: €2.00
* **Environmental surcharge per unit**: €1.50
* **Pre‑carriage costs per started CBM**: €6.00

{% code title="api/packagingUnits" %}

```json
"packagingPricingDetails": {
            "surchargesPerPackagingUnits": [
                {
                    "tenantSurchargeType": "Environmental surcharge",
                    "type": "ABSOLUTE_SURCHARGE_TYPE",
                    "amount": {
                        "currency": "EUR",
                        "decimalPlaces": 2,
                        "value": 150
                    }
                }
            ],
            "costCoefficient": {
                "value": {
                    "currency": "EUR",
                    "decimalPlaces": 2,
                    "value": 600
                },
                "measurementUnit": "CUBIC_METER"
            },
            "pricing": [
                {
                    "prices": [
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 2000
                            },
                            "upperThreshold": 200000000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 3500
                            },
                            "upperThreshold": 400000000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 3700
                            },
                            "upperThreshold": 600000000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 4300
                            },
                            "upperThreshold": 800000000
                        },
                        {
                            "price": {
                                "currency": "EUR",
                                "decimalPlaces": 2,
                                "value": 4800
                            },
                            "upperThreshold": 1000000000
                        }
                    ],
                    "overflowFactor": {
                        "price": {
                            "currency": "EUR",
                            "decimalPlaces": 2,
                            "value": 2000
                        },
                        "factor": 100000000
                    }
                }
            ]

        }
                      
```

{% endcode %}
{% endtab %}

{% tab title="Items to pack" %}
**1 x item 1:**

* 200 cm x 100 cm x 60 cm
* Weight per unit: 68 kg

{% code title="listings.attributes for item 1" %}

```json
"attributes": [
                    {
                        "key": "weightPerUnit",
                        "value": "68000",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "height",
                        "value": "2000",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "width",
                        "value": "1000",
                        "type": "NUMBER",
                        "category": "dimensions"
                    },
                    {
                        "key": "length",
                        "value": "600",
                        "type": "NUMBER",
                        "category": "dimensions"
                    }
                ]
```

{% endcode %}
{% endtab %}

{% tab title="Result" %}

* 1 item needs to be packed
* The `maxVolume` is 4 CBM
* The volume of the item to pack is 1.2 CBM (200 cm x 100 cm x 60 cm = 1.2 CBM)
* The item is within the `maxVolume`
* The up to 1 CBM pricing tier is €48.00
* Every extra 0.1 CBM is €2.00 (2 x €2.00 = €4.00)
* Add the pre‑carriage costs per started CBM (2 x €6.00 = €12.00)
* Add the mandatory environmental surcharge of €1.50

Total calculated costs: €48.00 + €4.00 + €12.00 + €1.50 = **€65.50**
{% endtab %}
{% endtabs %}

### Dimensions of packed packaging units

The dimensions a packed packaging unit reports are the basis for every dimension-dependent cost component: volume-based tiers, volumetric weight, cost coefficients per cubic meter, and loading meters. Depending on the packaging unit type, these dimensions are either the configured container or derived from the packing result.

| Type               | Dimensions of the packed unit                          |
| ------------------ | ------------------------------------------------------ |
| `PARCEL`           | The configured box, because it's a real container      |
| `PALLET`           | Length and width fixed, height from the packing result |
| `TWO_MAN_HANDLING` | Bounding box of the packing result                     |
| `BULKY_GOODS`      | Bounding box of the packing result                     |
| `LONG_GOODS`       | Bounding box of the packing result                     |

For types with derived dimensions, `maxLength`, `maxGirth`, `maxVolume`, and `maxWeight`, the configured `dimensions` act only as packing constraints, never as result values. The derived dimensions are validated against those constraints, including girth, and the longest edge is mapped to the length.

For example, a single item of 1400 × 1000 × 200 mm is packed into a bulky goods unit with a `maxLength` of 2000 mm. The packed unit reports 1400 × 1000 × 200 mm, not the configured maximum of 2000 mm.

## Create a PackagingUnitDetail by its ID

> This part of the API is in Beta status. For details, see the \<a href="<https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview>" target="\_blank">API release lifecycle documentation\</a>.\<br />\<br />Creates a single PackagingUnitDetail.

```json
{"openapi":"3.0.1","info":{"title":"fulfillmenttools","version":"VERSIONLESS"},"tags":[{"description":"Endpoints for managing packaging units.","name":"Packaging units"}],"servers":[{"url":"https://{tenant}.api.fulfillmenttools.com","variables":{"tenant":{"default":"your-tenant-name"}}}],"security":[{"BearerToken":[]}],"components":{"securitySchemes":{"BearerToken":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"PackagingUnitDetailForCreation":{"properties":{"nameLocalized":{"$ref":"#/components/schemas/LocaleStringConstrained"},"carrierRef":{"description":"The reference to the carrier associated with the packagingUnit.","type":"string"},"details":{"anyOf":[{"$ref":"#/components/schemas/PalletDetails"},{"$ref":"#/components/schemas/ParcelDetails"},{"$ref":"#/components/schemas/BulkyGoodsDetails"},{"$ref":"#/components/schemas/TwoManHandlingDetails"},{"$ref":"#/components/schemas/LongGoodsDetails"}]},"tenantPackagingUnitId":{"description":"The tenant specific identifier for the packagingUnit.","type":"string"}},"required":["nameLocalized","tenantPackagingUnitId","carrierRef","details"],"title":"PackagingUnitDetailForCreation","type":"object","description":"PackagingUnitDetailForCreation"},"LocaleStringConstrained":{"properties":{},"title":"LocaleStringConstrained","type":"object","description":"LocaleStringConstrained"},"PalletDetails":{"properties":{"dimensions":{"$ref":"#/components/schemas/PackagingUnitDetailDimensions"},"ldmToWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The grams equivalent to 1 loading meter, converting between weight and loading meters.","type":"number"},"loadCarrierHeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The height in millimeters of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"loadCarrierLength":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The length in millimeters of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"loadCarrierWeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The tare weight in grams of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"loadCarrierWidth":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The width in millimeters of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"maxItemQuantity":{"description":"The maximum number of items that can fit in the packagingUnit.","type":"number"},"maxVolumetricWeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />Caps the chargeable volumetric weight in grams. It does not restrict what the packagingUnit can hold.","type":"number"},"maxWeight":{"description":"The maximum weight in grams that the packagingUnit can hold.","type":"number"},"minItemQuantity":{"description":"The minimum number of items that can fit in the packagingUnit.","type":"number"},"packagingPricingDetails":{"$ref":"#/components/schemas/PackagingPricingDetails"},"pricingBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitPricingBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The basis used to determine which quantity of the packagingUnit is chargeable."},"type":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitType"}],"description":"The type of the packagingUnit."},"volumeBufferInPercent":{"description":"The volume buffer in percent for the packagingUnit.","type":"number"},"volumetricWeightFactor":{"description":"The volumetric weight factor for the packagingUnit.","type":"number"},"weightBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitWeightBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The article weight the packagingUnit is priced on: WEIGHT (weightPerUnit) or BILLABLE_WEIGHT (billableWeightPerUnit). Defaults to WEIGHT."}},"required":["type","dimensions","maxWeight","volumetricWeightFactor","packagingPricingDetails"],"title":"PalletDetails","type":"object","description":"PalletDetails"},"PackagingUnitDetailDimensions":{"properties":{"maxHeight":{"description":"The max height of the packagingUnit in millimeters.","type":"number"},"maxLength":{"description":"The max length of the packagingUnit in millimeters.","type":"number"},"maxWidth":{"description":"The max width of the packagingUnit in millimeters.","type":"number"}},"required":["maxHeight","maxLength","maxWidth"],"title":"PackagingUnitDetailDimensions","type":"object","description":"PackagingUnitDetailDimensions"},"PackagingPricingDetails":{"properties":{"costCoefficient":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitCostCoefficient"}],"description":"Cost coefficient for two-man handling"},"pricing":{"items":{"$ref":"#/components/schemas/PackagingUnitDetailPricingByZone"},"maxItems":500,"type":"array"},"surchargesPerPackagingUnits":{"description":"The surcharge applied per packagingUnit.","items":{"discriminator":{"mapping":{"ABSOLUTE_SURCHARGE_TYPE":"#/components/schemas/PackagingUnitDetailAbsoluteSurcharge","RELATIVE_SURCHARGE_TYPE":"#/components/schemas/PackagingUnitDetailRelativeSurcharge","THRESHOLD_SURCHARGE_TYPE":"#/components/schemas/PackagingUnitDetailThresholdSurcharge"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/PackagingUnitDetailRelativeSurcharge"},{"$ref":"#/components/schemas/PackagingUnitDetailAbsoluteSurcharge"},{"$ref":"#/components/schemas/PackagingUnitDetailThresholdSurcharge"}]},"maxItems":500,"type":"array"}},"required":["pricing"],"title":"PackagingPricingDetails","type":"object","description":"PackagingPricingDetails"},"PackagingUnitCostCoefficient":{"properties":{"measurementUnit":{"enum":["GRAM","CUBIC_METER"],"type":"string"},"value":{"$ref":"#/components/schemas/PackagingUnitsMoney"}},"required":["value","measurementUnit"],"title":"PackagingUnitCostCoefficient","type":"object","description":"PackagingUnitCostCoefficient"},"PackagingUnitsMoney":{"additionalProperties":false,"properties":{"currency":{"description":"The ISO 4217 currency code, e.g. EUR for Euro.","type":"string"},"decimalPlaces":{"default":2,"description":"The number of decimal places used by the currency, e.g. 2 for Euro.","exclusiveMinimum":true,"minimum":0,"type":"number"},"value":{"description":"The monetary value in the smallest currency unit","exclusiveMinimum":true,"minimum":0,"type":"number"}},"required":["currency","value"],"title":"PackagingUnitsMoney","type":"object","description":"PackagingUnitsMoney"},"PackagingUnitDetailPricingByZone":{"additionalProperties":false,"properties":{"overflowFactor":{"$ref":"#/components/schemas/PackagingUnitDetailOverflowFactor"},"prices":{"items":{"$ref":"#/components/schemas/PackagingUnitDetailPricesByWeight"},"maxItems":500,"type":"array"},"zone":{"description":"The shipping zone for which the pricing applies. Please proivide the ISO 3166-2 Country Code, followed by a dash and the first digits of the postal code, e.g. DE-50 for Cologne, Germany.","pattern":"^[A-Z]{2}-\\d+$","type":"string"}},"required":["prices"],"title":"PackagingUnitDetailPricingByZone","type":"object","description":"PackagingUnitDetailPricingByZone"},"PackagingUnitDetailOverflowFactor":{"additionalProperties":false,"properties":{"factor":{"description":"The factor appliable when the overflow factor is exceeded","exclusiveMinimum":true,"minimum":0,"type":"number"},"price":{"$ref":"#/components/schemas/PackagingUnitsMoney"}},"required":["price","factor"],"title":"PackagingUnitDetailOverflowFactor","type":"object","description":"PackagingUnitDetailOverflowFactor"},"PackagingUnitDetailPricesByWeight":{"additionalProperties":false,"properties":{"factor":{"description":"Charges price once per this many units of pricingUnit started, rounded up, instead of as a flat price for the tier. Use 1 to bill exactly. Omit it to charge price flat.","type":"number"},"price":{"$ref":"#/components/schemas/PackagingUnitsMoney"},"upperThreshold":{"description":"The weight threshold in grams up to which this price applies.","exclusiveMinimum":true,"minimum":0,"type":"number"}},"required":["price","upperThreshold"],"title":"PackagingUnitDetailPricesByWeight","type":"object","description":"PackagingUnitDetailPricesByWeight"},"PackagingUnitDetailRelativeSurcharge":{"properties":{"calculationScope":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitSurchargeCalculationScope"}],"description":"The charges the percentage is calculated on. If omitted, it is calculated on everything charged before it."},"context":{"description":"Restricts the surcharge to the given contexts. If omitted, the surcharge always applies.","items":{"$ref":"#/components/schemas/PackagingUnitSurchargeContext"},"maxItems":500,"type":"array"},"percentage":{"description":"The percentage of the surcharge.","type":"number"},"priority":{"description":"Places the surcharge in the packagingUnit's application sequence, which all surcharge types share. Ascending; gaps are allowed. If no surcharge of a packagingUnit declares one, every percentage is calculated on the base price only.","minimum":0,"type":"number"},"tenantSurchargeType":{"description":"The tenant specific identifier for the surcharge type.","type":"string"},"type":{"description":"The type of surcharge, which is RELATIVE in this case.","enum":["RELATIVE_SURCHARGE_TYPE"],"type":"string"}},"required":["tenantSurchargeType","type","percentage"],"title":"PackagingUnitDetailRelativeSurcharge","type":"object","description":"PackagingUnitDetailRelativeSurcharge"},"PackagingUnitSurchargeCalculationScope":{"properties":{"mode":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitSurchargeScopeMode"}],"description":"Whether the references name the charges the percentage is calculated on, or the ones it is not calculated on."},"references":{"description":"The charges the mode is applied to. A reference that matches nothing contributes nothing.","items":{"$ref":"#/components/schemas/PackagingUnitSurchargeScopeReference"},"maxItems":500,"minItems":1,"type":"array"}},"required":["mode","references"],"title":"PackagingUnitSurchargeCalculationScope","type":"object","description":"PackagingUnitSurchargeCalculationScope"},"PackagingUnitSurchargeScopeMode":{"description":"Whether the references name the charges the percentage is calculated on, or the ones it is not calculated on.","enum":["INCLUDE","EXCLUDE"],"title":"PackagingUnitSurchargeScopeMode","type":"string"},"PackagingUnitSurchargeScopeReference":{"properties":{"kind":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitSurchargeScopeReferenceKind"}],"description":"What the reference selects."},"level":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitSurchargeScopeLevel"}],"description":"Restricts the reference to the charges made on one pricing level. If omitted, charges of both levels are selected, so a tenantSurchargeType configured on both matches both."},"tenantSurchargeType":{"description":"The referenced tenant surcharge type. Only read for TENANT_SURCHARGE references.","type":"string"}},"required":["kind"],"title":"PackagingUnitSurchargeScopeReference","type":"object","description":"PackagingUnitSurchargeScopeReference"},"PackagingUnitSurchargeScopeReferenceKind":{"description":"What the reference selects.","enum":["BASE_PRICE","TENANT_SURCHARGE","PACKAGING_UNITS"],"title":"PackagingUnitSurchargeScopeReferenceKind","type":"string"},"PackagingUnitSurchargeScopeLevel":{"description":"Restricts the reference to the charges made on one pricing level. If omitted, charges of both levels are selected, so a tenantSurchargeType configured on both matches both.","enum":["PACKAGING_UNIT","TRANSFER"],"title":"PackagingUnitSurchargeScopeLevel","type":"string"},"PackagingUnitSurchargeContext":{"properties":{"operator":{"description":"The operator used to define how the context values are evaluated or compared.","enum":["NOT"],"type":"string"},"type":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitSurchargeContextTypes"}],"description":"The kind of context the values refer to."},"values":{"description":"The values the context is matched against.","items":{"type":"string"},"maxItems":500,"minItems":1,"type":"array"}},"required":["type","values"],"title":"PackagingUnitSurchargeContext","type":"object","description":"PackagingUnitSurchargeContext"},"PackagingUnitSurchargeContextTypes":{"description":"The kind of context the values refer to.","enum":["CATEGORY","TAG_REFERENCE","TARGET_POSTALCODE","TARGET_COUNTRY"],"title":"PackagingUnitSurchargeContextTypes","type":"string"},"PackagingUnitDetailAbsoluteSurcharge":{"properties":{"amount":{"$ref":"#/components/schemas/PackagingUnitsMoney"},"context":{"description":"Restricts the surcharge to the given contexts. If omitted, the surcharge always applies.","items":{"$ref":"#/components/schemas/PackagingUnitSurchargeContext"},"maxItems":500,"type":"array"},"priority":{"description":"Places the surcharge in the packagingUnit's application sequence, which all surcharge types share. Ascending; gaps are allowed. If no surcharge of a packagingUnit declares one, every percentage is calculated on the base price only.","minimum":0,"type":"number"},"tenantSurchargeType":{"description":"The tenant specific identifier for the surcharge type.","type":"string"},"type":{"description":"The type of surcharge, which is ABSOLUTE in this case.","enum":["ABSOLUTE_SURCHARGE_TYPE"],"type":"string"}},"required":["tenantSurchargeType","type","amount"],"title":"PackagingUnitDetailAbsoluteSurcharge","type":"object","description":"PackagingUnitDetailAbsoluteSurcharge"},"PackagingUnitDetailThresholdSurcharge":{"properties":{"calculationScope":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitSurchargeCalculationScope"}],"description":"The charges the percentage is calculated on. If omitted, it is calculated on everything charged before it."},"context":{"description":"Restricts the surcharge to the given contexts. If omitted, the surcharge always applies.","items":{"$ref":"#/components/schemas/PackagingUnitSurchargeContext"},"maxItems":500,"type":"array"},"minimumAmount":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitsMoney"}],"description":"The amount that is charged whenever the percentage part stays below it."},"percentage":{"description":"The percentage of the surcharge, charged whenever it exceeds the minimum amount.","type":"number"},"priority":{"description":"Places the surcharge in the packagingUnit's application sequence, which all surcharge types share. Ascending; gaps are allowed. If no surcharge of a packagingUnit declares one, every percentage is calculated on the base price only.","minimum":0,"type":"number"},"tenantSurchargeType":{"description":"The tenant specific identifier for the surcharge type.","type":"string"},"type":{"description":"The type of surcharge, which is THRESHOLD in this case.","enum":["THRESHOLD_SURCHARGE_TYPE"],"type":"string"}},"required":["tenantSurchargeType","type","minimumAmount","percentage"],"title":"PackagingUnitDetailThresholdSurcharge","type":"object","description":"PackagingUnitDetailThresholdSurcharge"},"PackagingUnitPricingBasis":{"properties":{"pricingQuantities":{"description":"The physical quantities compared, each converted to pricingUnit; the highest one determines the chargeable amount. At least one must be given.","items":{"$ref":"#/components/schemas/PackagingUnitPricingQuantity"},"maxItems":3,"type":"array"},"pricingUnit":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitPricingUnit"}],"description":"The unit the pricing quantities are converted to and priced in. LOADING_METER is not supported yet and is rejected."}},"required":["pricingUnit","pricingQuantities"],"title":"PackagingUnitPricingBasis","type":"object","description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />PackagingUnitPricingBasis"},"PackagingUnitPricingQuantity":{"description":"The physical quantities compared, each converted to pricingUnit; the highest one determines the chargeable amount. At least one must be given.","enum":["WEIGHT","VOLUME","LOADING_METERS"],"title":"PackagingUnitPricingQuantity","type":"string"},"PackagingUnitPricingUnit":{"description":"The unit the pricing quantities are converted to and priced in. LOADING_METER is not supported yet and is rejected.","enum":["GRAM","CUBIC_METER","LOADING_METER"],"title":"PackagingUnitPricingUnit","type":"string"},"PackagingUnitType":{"description":"The type of the packagingUnit.","enum":["PALLET","TWO_MAN_HANDLING","PARCEL","BULKY_GOODS","LONG_GOODS"],"title":"PackagingUnitType","type":"string"},"PackagingUnitWeightBasis":{"description":"The article weight the packagingUnit is priced on: WEIGHT (weightPerUnit) or BILLABLE_WEIGHT (billableWeightPerUnit). Defaults to WEIGHT.","enum":["WEIGHT","BILLABLE_WEIGHT"],"title":"PackagingUnitWeightBasis","type":"string"},"ParcelDetails":{"properties":{"dimensions":{"$ref":"#/components/schemas/PackagingUnitDetailDimensions"},"ldmToWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The grams equivalent to 1 loading meter, converting between weight and loading meters.","type":"number"},"maxItemQuantity":{"description":"The maximum number of items that can fit in the packagingUnit.","type":"number"},"maxVolumetricWeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />Caps the chargeable volumetric weight in grams. It does not restrict what the packagingUnit can hold.","type":"number"},"maxWeight":{"description":"The maximum weight in grams that the packagingUnit can hold.","type":"number"},"minItemQuantity":{"description":"The minimum number of items that can fit in the packagingUnit.","type":"number"},"packagingPricingDetails":{"$ref":"#/components/schemas/PackagingPricingDetails"},"pricingBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitPricingBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The basis used to determine which quantity of the packagingUnit is chargeable."},"type":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitType"}],"description":"The type of the packagingUnit."},"volumeBufferInPercent":{"description":"The volume buffer in percent for the packagingUnit.","type":"number"},"volumetricWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The volumetric weight factor for the packagingUnit.","type":"number"},"weightBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitWeightBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The article weight the packagingUnit is priced on: WEIGHT (weightPerUnit) or BILLABLE_WEIGHT (billableWeightPerUnit). Defaults to WEIGHT."}},"required":["type","dimensions","maxWeight","packagingPricingDetails"],"title":"ParcelDetails","type":"object","description":"ParcelDetails"},"BulkyGoodsDetails":{"properties":{"ldmToWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The grams equivalent to 1 loading meter, converting between weight and loading meters.","type":"number"},"maxGirth":{"description":"The maximum girth in millimeters of the packagingUnit.","type":"number"},"maxItemQuantity":{"description":"The maximum number of items that can fit in the packagingUnit.","type":"number"},"maxLength":{"description":"The maximum length in millimeters of the packagingUnit.","type":"number"},"maxVolume":{"description":"The maximum volume in cubic millimeters of the packagingUnit.","type":"number"},"maxVolumetricWeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />Caps the chargeable volumetric weight in grams. It does not restrict what the packagingUnit can hold.","type":"number"},"maxWeight":{"description":"The maximum weight in grams that the packagingUnit can hold.","type":"number"},"minItemQuantity":{"description":"The minimum number of items that can fit in the packagingUnit.","type":"number"},"packagingPricingDetails":{"$ref":"#/components/schemas/PackagingPricingDetails"},"pricingBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitPricingBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The basis used to determine which quantity of the packagingUnit is chargeable."},"type":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitType"}],"description":"The type of the packagingUnit."},"volumeBufferInPercent":{"description":"The volume buffer in percent for the packagingUnit.","type":"number"},"volumetricWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The volumetric weight factor for the packagingUnit.","type":"number"},"weightBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitWeightBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The article weight the packagingUnit is priced on: WEIGHT (weightPerUnit) or BILLABLE_WEIGHT (billableWeightPerUnit). Defaults to WEIGHT."}},"required":["type","maxLength","maxGirth","maxWeight","packagingPricingDetails"],"title":"BulkyGoodsDetails","type":"object","description":"BulkyGoodsDetails"},"TwoManHandlingDetails":{"properties":{"dimensions":{"$ref":"#/components/schemas/PackagingUnitDetailDimensions"},"ldmToWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The grams equivalent to 1 loading meter, converting between weight and loading meters.","type":"number"},"maxItemQuantity":{"description":"The maximum number of items that can fit in the packagingUnit.","type":"number"},"maxVolume":{"description":"The maximum volume in cubic millimeters of the packagingUnit.","type":"number"},"maxVolumetricWeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />Caps the chargeable volumetric weight in grams. It does not restrict what the packagingUnit can hold.","type":"number"},"maxWeight":{"description":"The maximum weight in grams that the packagingUnit can hold.","type":"number"},"minItemQuantity":{"description":"The minimum number of items that can fit in the packagingUnit.","type":"number"},"packagingPricingDetails":{"$ref":"#/components/schemas/PackagingPricingDetails"},"pricingBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitPricingBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The basis used to determine which quantity of the packagingUnit is chargeable."},"type":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitType"}],"description":"The type of the packagingUnit."},"volumeBufferInPercent":{"description":"The volume buffer in percent for the packagingUnit.","type":"number"},"volumetricWeightFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The volumetric weight factor for the packagingUnit.","type":"number"},"weightBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitWeightBasis"}],"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The article weight the packagingUnit is priced on: WEIGHT (weightPerUnit) or BILLABLE_WEIGHT (billableWeightPerUnit). Defaults to WEIGHT."},"weightToVolumeFactor":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />The factor converting the weight of the packagingUnit to an equivalent volume.","type":"number"}},"required":["type","dimensions","maxWeight","packagingPricingDetails"],"title":"TwoManHandlingDetails","type":"object","description":"TwoManHandlingDetails"},"LongGoodsDetails":{"properties":{"ldmToWeightFactor":{"description":"The grams equivalent to 1 loading meter, converting between weight and loading meters.","type":"number"},"loadCarrierHeight":{"description":"The height in millimeters of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"loadCarrierLength":{"description":"The length in millimeters of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"loadCarrierWeight":{"description":"The tare weight in grams of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"loadCarrierWidth":{"description":"The width in millimeters of the empty load carrier (e.g. pallet or skid) itself.","type":"number"},"maxGirth":{"description":"The maximum girth in millimeters of the packagingUnit.","type":"number"},"maxItemQuantity":{"description":"The maximum number of items that can fit in the packagingUnit.","type":"number"},"maxLength":{"description":"The maximum length in millimeters of the packagingUnit.","type":"number"},"maxVolume":{"description":"The maximum volume in cubic millimeters of the packagingUnit.","type":"number"},"maxVolumetricWeight":{"description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />Caps the chargeable volumetric weight in grams. It does not restrict what the packagingUnit can hold.","type":"number"},"maxWeight":{"description":"The maximum weight in grams that the packagingUnit can hold.","type":"number"},"minItemQuantity":{"description":"The minimum number of items that can fit in the packagingUnit.","type":"number"},"packagingPricingDetails":{"$ref":"#/components/schemas/PackagingPricingDetails"},"pricingBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitPricingBasis"}],"description":"The basis used to determine which quantity of the packagingUnit is chargeable."},"type":{"description":"The type of the packagingUnit.","enum":["PALLET","TWO_MAN_HANDLING","PARCEL","BULKY_GOODS","LONG_GOODS"],"type":"string"},"volumeBufferInPercent":{"description":"The volume buffer in percent for the packagingUnit.","type":"number"},"volumetricWeightFactor":{"description":"The volumetric weight factor for the packagingUnit.","type":"number"},"weightBasis":{"allOf":[{"$ref":"#/components/schemas/PackagingUnitWeightBasis"}],"description":"The article weight the packagingUnit is priced on: WEIGHT (weightPerUnit) or BILLABLE_WEIGHT (billableWeightPerUnit). Defaults to WEIGHT."}},"required":["type","packagingPricingDetails"],"title":"LongGoodsDetails","type":"object","description":"This part of the API is in Alpha status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />LongGoodsDetails"},"ApiError":{"items":{"$ref":"#/components/schemas/ErrorInner"},"type":"array","xml":{"name":"ApiError"},"title":"ApiError","description":"ApiError"},"ErrorInner":{"properties":{"description":{"type":"string"},"requestVersion":{"description":"The version provided within an invalid request.","format":"int64","type":"integer"},"summary":{"type":"string"},"version":{"format":"int64","type":"integer"}},"required":["summary"],"type":"object","title":"ErrorInner","description":"ErrorInner"}}},"paths":{"/api/packagingunits":{"post":{"deprecated":false,"description":"This part of the API is in Beta status. For details, see the <a href=\"https://docs.fulfillmenttools.com/documentation/apis/api-versioning-and-lifecycle#lifecycle-overview\" target=\"_blank\">API release lifecycle documentation</a>.<br /><br />Creates a single PackagingUnitDetail.","operationId":"createPackagingUnitDetail","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackagingUnitDetailForCreation"}}},"required":true},"responses":{"200":{"description":"Successfully created the PackagingUnitDetail."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Your user is not allowed to operate against this API instance"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Your user, although recognized, is not authorized to use this endpoint"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The requested entity was not found"}},"summary":"Create a PackagingUnitDetail by its ID","tags":["Packaging units"]}}}}
```

### Cost breakdown in the routing result

The calculated transport costs are reported per transfer and per packaging unit. This is broken down into the base price, the applied cost coefficient, and each applied surcharge, so that a price can be reconciled against the carrier tariff. The breakdown is returned for every transfer of every returned sourcing option, regardless of whether the routing strategy has an active total cost rating.

See the [Sourcing options article](/documentation/by-pillar/advanced-order-routing/complex-routing-with-combinatorics/sourcing-options-endpoint.md) for the structure.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.fulfillmenttools.com/documentation/by-pillar/advanced-order-routing/complex-routing-with-combinatorics/calculations-within-routing/transport-cost-calculation-logic.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
