> ## Documentation Index
> Fetch the complete documentation index at: https://developers.kardinal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulky & heavy goods

> Capacity-gated customer returns, a subcontractor revenue floor, equipment-dependent service time, and two-person crews on one delivery-and-install fleet.

A bulky and heavy goods operation delivers and installs large items with a mix of in-house two-person crews and solo drivers, alongside subcontracted routes that need a guaranteed minimum payout to be worth running, and customer returns that can't be picked up while the truck is already loaded past a safe weight.

## What makes this vertical distinctive

* **Capacity-gated customer returns** — a customer return is only picked up once the truck's load has dropped under a set weight, or its deliveries are done, not on a fixed slot.
* **Subcontractor revenue floor** — a subcontracted route guarantees a minimum payout, with the revenue from its drops counted one-for-one beyond it.
* **Equipment-dependent service time** — a solo crew without a dolly takes measurably longer on a heavy item than a two-person crew.
* **Two-person crews** — heavy items are only assigned to crews certified for two-person handling.

## Combined example

```json theme={null}
{
  "resources": [
    {
      "id": "team-two-person",
      "vehicleProfile": { "type": "truck" },
      "capacities": { "weight": 1200, "nbDeliveries": 11, "nbPickups": 1, "revenue": 1000 },
      "skills": ["team_of_two_required"],
      "cost": { "costsByCapacity": { "revenue": { "constantCost": 650, "costFloor": 650, "costCoeff": 1 } } }
    },
    {
      "id": "team-solo",
      "vehicleProfile": { "type": "truck" },
      "capacities": { "weight": 1200, "nbDeliveries": 11, "nbPickups": 1 },
      "tags": ["equipment:solo-no-dolly"]
    }
  ],
  "orders": [
    {
      "id": "order-heavy-item",
      "stops": [
        {
          "type": "single",
          "id": "stop-heavy-item",
          "position": { "lon": 2.435, "lat": 48.805 },
          "kind": "delivery",
          "operationDuration": "PT40M",
          "capacities": { "weight": 90, "nbDeliveries": 1 },
          "tags": ["job:heavy-item"]
        }
      ],
      "requiredSkills": ["team_of_two_required"]
    },
    {
      "id": "order-customer-return",
      "stops": [
        {
          "type": "single",
          "id": "stop-customer-return",
          "position": { "lon": 2.39, "lat": 48.81 },
          "kind": "pickup",
          "operationDuration": "PT15M",
          "capacities": { "weight": 180, "nbPickups": 1 }
        }
      ]
    },
    {
      "id": "order-subcontracted-drop",
      "stops": [
        {
          "type": "single",
          "id": "stop-subcontracted-drop",
          "position": { "lon": 2.425, "lat": 48.817 },
          "kind": "delivery",
          "operationDuration": "PT15M",
          "capacities": { "revenue": 40, "weight": 50, "nbDeliveries": 1 }
        }
      ]
    }
  ],
  "additionalConstraints": [
    {
      "type": "atLeastOneValidCapacity",
      "capacities": { "nbDeliveries": 0, "nbPickups": 0, "weight": 400 },
      "name": "customer-return-once-under-400kg"
    }
  ],
  "additionalOperationDurations": [
    { "resourceTag": "equipment:solo-no-dolly", "stopTag": "job:heavy-item", "additionalOperationDuration": "PT20M" }
  ]
}
```

### Capacity-gated customer returns

Every delivery stop carries `nbDeliveries: 1` and the customer return's pickup carries `nbPickups: 1`, on top of their real `weight`; both counters are also declared on each resource so the constraint reads an explicit load. The single `atLeastOneValidCapacity` constraint then requires, at every stop, at least one of three things to hold: no delivery left on board (`nbDeliveries: 0`), no return collected yet (`nbPickups: 0`), or no more than 400 kg on board, the return included (`weight: 400`). Once the return is on board, `nbPickups` never drops back to `0` — so the return can only be placed once the truck has finished its deliveries, or dropped enough of them to stay at or under 400 kg. See [Sequencing pickups after deliveries](/guides/advanced-constraints#sequencing-pickups-after-deliveries) for the same pattern traced step by step.

### Subcontractor revenue floor

Each subcontracted drop carries the revenue it earns (`order-subcontracted-drop.capacities.revenue: 40`), and `revenue` is also declared on `team-two-person` with a ceiling that never binds, so it reads back in the tour's capacity values; the cost doesn't need that declaration. `costsByCapacity` is computed on the quantities handled at the tour's stops, and each drop counts its revenue once, at delivery: the base is the total revenue of the drops the tour serves. `constantCost: 650` guarantees the minimum payout even if fewer drops are served, and past `costFloor: 650`, `costCoeff: 1` follows the revenue one-for-one: the resource is paid max(650, revenue). See [Guaranteeing a minimum per-tour revenue via costsByCapacity](/guides/cost-modeling#guaranteeing-a-minimum-per-tour-revenue-via-costsbycapacity) — the exact worked example this follows.

### Equipment-dependent service time

`additionalOperationDurations` adds 20 minutes to every `job:heavy-item` stop when it's served by a resource tagged `equipment:solo-no-dolly` — the base `operationDuration` on the stop stays the crew-agnostic default, and the solo penalty is added only for the resources it actually applies to. See [Plan-level fields](/reference/data-model#plan-level-fields).

### Two-person crews

`order-heavy-item.requiredSkills: ["team_of_two_required"]` only matches resources carrying that same skill — `team-two-person` qualifies, `team-solo` doesn't. See [Driver skills and qualifications](/guides/advanced-constraints#driver-skills-and-qualifications).

## Full payload

<Accordion title="Full payload — ready to submit as POST /plans">
  The preceding example isolates the four mechanisms this vertical needs; this expands it to the scale of a real working day — a full fleet schedule (`workingTimeWindow`, `departure`, `arrival`), the complete `objectives` list, and enough padding orders to look like an actual route rather than a minimal illustration. Submit it as-is via [`POST /plans`](/api-reference/plan/create-a-plan) — the service assigns the plan's `id`, so don't include one of your own.

  ```json theme={null}
  {
    "tz": "Europe/Paris",
    "resources": [
      {
        "id": "team-two-person",
        "vehicleProfile": { "type": "truck" },
        "workingTimeWindow": { "begin": "2026-08-03T07:00:00Z", "end": "2026-08-03T17:00:00Z" },
        "departure": { "lon": 2.42, "lat": 48.795 },
        "arrival": { "lon": 2.42, "lat": 48.795 },
        "capacities": { "weight": 1200, "nbDeliveries": 11, "nbPickups": 1, "revenue": 1000 },
        "skills": ["team_of_two_required"],
        "preferredStopTags": ["eco-requested"],
        "cost": { "costsByCapacity": { "revenue": { "constantCost": 650, "costFloor": 650, "costCoeff": 1 } } }
      },
      {
        "id": "team-solo",
        "vehicleProfile": { "type": "truck" },
        "workingTimeWindow": { "begin": "2026-08-03T07:00:00Z", "end": "2026-08-03T17:00:00Z" },
        "departure": { "lon": 2.42, "lat": 48.795 },
        "arrival": { "lon": 2.42, "lat": 48.795 },
        "capacities": { "weight": 1200, "nbDeliveries": 11, "nbPickups": 1 },
        "tags": ["equipment:solo-no-dolly"]
      }
    ],
    "orders": [
      {
        "id": "order-heavy-item",
        "stops": [
          {
            "type": "single",
            "id": "stop-heavy-item",
            "position": { "lon": 2.435, "lat": 48.805 },
            "kind": "delivery",
            "operationDuration": "PT40M",
            "capacities": { "weight": 90, "nbDeliveries": 1 },
            "tags": ["job:heavy-item"]
          }
        ],
        "requiredSkills": ["team_of_two_required"]
      },
      {
        "id": "order-standard-item",
        "stops": [
          {
            "type": "single",
            "id": "stop-standard-item",
            "position": { "lon": 2.4, "lat": 48.803 },
            "kind": "delivery",
            "operationDuration": "PT15M",
            "capacities": { "weight": 35, "nbDeliveries": 1 },
            "tags": ["job:heavy-item", "eco-requested"]
          }
        ]
      },
      {
        "id": "order-customer-return",
        "stops": [
          {
            "type": "single",
            "id": "stop-customer-return",
            "position": { "lon": 2.39, "lat": 48.81 },
            "kind": "pickup",
            "operationDuration": "PT15M",
            "capacities": { "weight": 180, "nbPickups": 1 }
          }
        ]
      },
      {
        "id": "order-drop-off",
        "stops": [
          {
            "type": "single",
            "id": "stop-drop-off",
            "position": { "lon": 2.43, "lat": 48.777 },
            "kind": "delivery",
            "operationDuration": "PT10M",
            "capacities": { "weight": 20, "nbDeliveries": 1 },
            "tags": ["job:drop-off"]
          }
        ]
      },
      {
        "id": "order-full-install",
        "stops": [
          {
            "type": "single",
            "id": "stop-full-install",
            "position": { "lon": 2.408, "lat": 48.781 },
            "kind": "delivery",
            "operationDuration": "PT2H",
            "capacities": { "weight": 120, "nbDeliveries": 1 },
            "tags": ["job:full-install"]
          }
        ]
      },
      {
        "id": "order-preferred-slot",
        "stops": [
          {
            "type": "single",
            "id": "stop-preferred-slot",
            "position": { "lon": 2.445, "lat": 48.79 },
            "kind": "delivery",
            "operationDuration": "PT25M",
            "capacities": { "weight": 45, "nbDeliveries": 1 },
            "preferredTimeWindows": [{ "begin": "2026-08-03T14:00:00Z", "end": "2026-08-03T16:00:00Z" }]
          }
        ]
      },
      {
        "id": "order-subcontracted-drop-0",
        "stops": [
          {
            "type": "single",
            "id": "stop-subcontracted-drop-0",
            "position": { "lon": 2.425, "lat": 48.817 },
            "kind": "delivery",
            "operationDuration": "PT15M",
            "capacities": { "revenue": 40, "weight": 50, "nbDeliveries": 1 }
          }
        ]
      },
      {
        "id": "order-subcontracted-drop-1",
        "stops": [
          {
            "type": "single",
            "id": "stop-subcontracted-drop-1",
            "position": { "lon": 2.412, "lat": 48.769 },
            "kind": "delivery",
            "operationDuration": "PT15M",
            "capacities": { "revenue": 60, "weight": 70, "nbDeliveries": 1 }
          }
        ]
      },
      {
        "id": "order-delivery-0",
        "stops": [
          {
            "type": "single",
            "id": "stop-delivery-0",
            "position": { "lon": 2.435, "lat": 48.805 },
            "kind": "delivery",
            "operationDuration": "PT20M",
            "capacities": { "weight": 250, "nbDeliveries": 1 }
          }
        ]
      },
      {
        "id": "order-delivery-1",
        "stops": [
          {
            "type": "single",
            "id": "stop-delivery-1",
            "position": { "lon": 2.4, "lat": 48.803 },
            "kind": "delivery",
            "operationDuration": "PT20M",
            "capacities": { "weight": 250, "nbDeliveries": 1 }
          }
        ]
      },
      {
        "id": "order-delivery-2",
        "stops": [
          {
            "type": "single",
            "id": "stop-delivery-2",
            "position": { "lon": 2.43, "lat": 48.777 },
            "kind": "delivery",
            "operationDuration": "PT20M",
            "capacities": { "weight": 250, "nbDeliveries": 1 }
          }
        ]
      },
      {
        "id": "order-delivery-3",
        "stops": [
          {
            "type": "single",
            "id": "stop-delivery-3",
            "position": { "lon": 2.408, "lat": 48.781 },
            "kind": "delivery",
            "operationDuration": "PT20M",
            "capacities": { "weight": 250, "nbDeliveries": 1 }
          }
        ]
      }
    ],
    "objectives": [
      "maximizeMandatoryStops",
      "minimizeResources",
      "minimizeCosts",
      "maximizePreferredStops",
      "minimizeDelay",
      "minimizeLargestTourDuration",
      "minimizeDistance",
      "minimizeWorkingDuration"
    ],
    "additionalConstraints": [
      {
        "type": "atLeastOneValidCapacity",
        "capacities": { "nbDeliveries": 0, "nbPickups": 0, "weight": 400 },
        "name": "customer-return-once-under-400kg"
      }
    ],
    "additionalOperationDurations": [
      { "resourceTag": "equipment:solo-no-dolly", "stopTag": "job:heavy-item", "additionalOperationDuration": "PT20M" }
    ]
  }
  ```
</Accordion>

## See also

* [Cost modeling](/guides/cost-modeling#guaranteeing-a-minimum-per-tour-revenue-via-costsbycapacity) — the `costsByCapacity` revenue-floor pattern.
* [Modeling advanced constraints](/guides/advanced-constraints#sequencing-pickups-after-deliveries) — capacity-based sequencing, and the `atLeastOneValidCapacity` building block.
* [Data model](/reference/data-model#constraints-catalog) — the full `additionalConstraints` and `globalConstraints` catalog.

Ready to model an operation like this one? [Send your first API call](/getting-started/first-api-call) with your own data, or contact [customer.success@kardinal.ai](mailto:customer.success@kardinal.ai) to walk through your specific constraints.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.