> 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/store-operations/services/service-container.md).

# Service container

A service container groups physical or virtual containers that belong to one or more [service jobs](/documentation/by-pillar/store-operations/services/service-jobs.md). Each container holds a set of line items (articles with quantities) and is linked to a facility through its referenced service jobs. All service container operations are available through the [fulfillmenttools REST API](https://fulfillmenttools.github.io/fulfillmenttools-api-reference-ui/#post-/api/servicecontainers).

Service containers exist in two types:

| Type       | Description                                                                                                                                                                     |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PHYSICAL` | Represents a real, physical container such as a tote or box. Always has a `sequenceNumber` greater than `0`.                                                                    |
| `VIRTUAL`  | A logical grouping with no physical counterpart. Always has `sequenceNumber = 0`. Can't be created via the REST API, fulfillmenttools creates virtual containers automatically. |

## Service container creation

A service container is created manually via the REST API or automatically by fulfillmenttools when a pick job is closed. For the automatic creation flow, see the [Automatic creation from pick jobs section](#automatic-creation-from-pick-jobs).

The endpoint for manual creation is:

```http
POST https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/servicecontainers
```

Returns `HTTP 201` on success.

| Field                         | Type      | Required | Description                                                                                                        |
| ----------------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
| `serviceJobRefs`              | string\[] | Yes      | Identifiers of the service jobs this container belongs to. Between one and 50 entries, no duplicates.              |
| `lineItems`                   | object\[] | Yes      | Items in this container. Maximum 50.                                                                               |
| `operativeContainerTypeRef`   | string    | No       | Identifier of the operative container type to base this container on.                                              |
| `nameLocalized`               | object    | No       | Localized name. Defaults to the name from the operative container type, or `"Unknown Service Container"`.          |
| `descriptionLocalized`        | object    | No       | Localized description.                                                                                             |
| `iconUrl`                     | string    | No       | URL to an icon. Defaults to the value from the operative container type.                                           |
| `sequenceNumber`              | number    | No       | Must be greater than `0` for physical containers. If omitted, the next available number is assigned automatically. |
| `scannableCodes`              | string\[] | No       | Barcode or Quick Response (QR) code values. Maximum 50.                                                            |
| `storageLocationRef`          | string    | No       | Identifier of the storage location where this container resides.                                                   |
| `stackRef`                    | string    | No       | Reference to a related stack.                                                                                      |
| `customAttributes`            | object    | No       | Arbitrary key-value payload. Merged on top of `customAttributes` from the operative container type.                |
| `dimensions`                  | object    | No       | Physical dimensions. Defaults to the operative container type value.                                               |
| `weightLimitInG`              | number    | No       | Weight limit in grams. Defaults to the operative container type value.                                             |
| `previousModuleContainerInfo` | object    | No       | Traceability link to a preceding module container, such as a load unit.                                            |

**Example request body:**

```json
{
  "serviceJobRefs": ["sj-456"],
  "lineItems": [
    {
      "article": {
        "tenantArticleId": "ART-001",
        "title": "Widget"
      },
      "quantity": 3,
      "globalLineItemId": "gli-123"
    }
  ],
  "operativeContainerTypeRef": "oct-blue-tote",
  "nameLocalized": { "en_US": "Blue Tote #1", "de_DE": "Blauer Korb #1" },
  "sequenceNumber": 1,
  "scannableCodes": ["TOTE-BARCODE-001"]
}
```

**Example response:**

```json
{
  "id": "sc-new-uuid",
  "version": 0,
  "type": "PHYSICAL",
  "sequenceNumber": 1,
  "facilityRef": "facility-123",
  "serviceJobRefs": ["sj-456"],
  "nameLocalized": { "en_US": "Blue Tote #1", "de_DE": "Blauer Korb #1" },
  "lineItems": [],
  "scannableCodes": ["TOTE-BARCODE-001"],
  "operativeContainerTypeRef": "oct-blue-tote"
}
```

### Creation validations

The following validations are applied to every manual creation call.

#### Input validations

| Rule                                                     | Error                                                                        |
| -------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `serviceJobRefs` must contain at least one entry.        | `"A service container must reference at least one service job."`             |
| `serviceJobRefs` must not contain duplicate identifiers. | `"Duplicate service job references are not allowed in a service container."` |
| Maximum 50 `serviceJobRefs`.                             | Validation error.                                                            |
| Maximum 50 `lineItems`.                                  | `"A service container cannot have more than 50 line items."`                 |
| Maximum 50 `scannableCodes`.                             | `"A service container cannot have more than 50 scannable codes."`            |
| Each line item: maximum 50 `recordableAttributes`.       | Validation error.                                                            |
| Each line item: maximum 50 `tags`.                       | Validation error.                                                            |
| Each line item: maximum 50 `stickers`.                   | Validation error.                                                            |

#### Operative container type validations

If `operativeContainerTypeRef` is provided, the following additional checks apply:

* The referenced operative container type must exist and be active. If its status is `INACTIVE`, fulfillmenttools rejects the request with: `"Creating with an inactive container type is not allowed. Inactive container type id: <id>."`
* Its `allowedOperativeTypes` must include `SERVICE`. If not, fulfillmenttools rejects the request with: `"The referenced operative container type with id <id> cannot be used for service containers as it does not allow operative type SERVICE."`

#### Sequence number uniqueness

* `sequenceNumber = 0` is reserved for virtual containers and can't be set explicitly. fulfillmenttools rejects any `sequenceNumber <= 0` on a non-virtual container with: `"sequenceNumber must be greater than 0. Received: <value>"`
* The `sequenceNumber` must be unique within the combination of `serviceJobRefs` and operative container type name. fulfillmenttools rejects a conflicting value with: `"A service container with sequenceNumber <n> already exists for this (serviceJob, containerType) combination."`
* If no `sequenceNumber` is provided, fulfillmenttools automatically assigns the next available number.

## Service container retrieval

### Service container by identifier

```http
GET https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/servicecontainers/{serviceContainerId}
```

### Service containers by service job

```http
GET https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/servicejobs/{serviceJobId}/servicecontainers
```

Returns all service containers associated with the given service job.

### Service container list

```http
GET https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/servicecontainers
```

| Parameter       | Type      | Required | Description                                                                                                                                                           |
| --------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `size`          | number    | Yes      | Number of results to return. Maximum: 500.                                                                                                                            |
| `startAfterId`  | string    | No       | Cursor for pagination.                                                                                                                                                |
| `orderBy`       | string    | No       | Sort order. One of: `SERVICE_CONTAINER_LAST_MODIFIED_ASC`, `SERVICE_CONTAINER_LAST_MODIFIED_DESC`, `SERVICE_CONTAINER_CREATED_ASC`, `SERVICE_CONTAINER_CREATED_DESC`. |
| `facilityRefs`  | string\[] | No       | Filter by facility identifiers.                                                                                                                                       |
| `serviceJobRef` | string    | No       | Filter by a single service job identifier.                                                                                                                            |

**Example response:**

```json
{
  "serviceContainers": [],
  "total": 5
}
```

## Service container deletion

```http
DELETE https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/servicecontainers/{serviceContainerId}
```

Returns `HTTP 200` on success. The system emits a `SERVICE_CONTAINER_DELETED` event transactionally.

## Required permissions

All service container endpoints require the caller to hold one of the following permissions:

| Permission          | Required for                                             |
| ------------------- | -------------------------------------------------------- |
| `SERVICE_JOB_READ`  | Read operations (`GET` endpoints)                        |
| `SERVICE_JOB_WRITE` | Write and delete operations (`POST`, `DELETE` endpoints) |

## Automatic creation from pick jobs

In addition to manual REST API creation, service containers are created automatically when a pick job is closed. This happens as part of the linked service jobs update flow.

### Creation trigger

When a pick job transitions to status `CLOSED`, fulfillmenttools:

1. Retrieves the operative process linked to the pick job.
2. Finds all linked service jobs that are children of the pick job inside the operative process tree.
3. Creates service containers for each linked service job.

All service jobs within a single linked service jobs entity share a single set of service containers. This means the `serviceJobRefs` field on each container contains all service job references from the linked service jobs entity.

### Container creation process

The system builds two groups of containers and creates them in one batch:

1. **Physical containers from load units**: one `PHYSICAL` container per load unit whose operative container type supports `SERVICE`, provided the load unit contains relevant line items.
2. **One virtual container (if needed)**: one `VIRTUAL` container that collects all line items that either weren't placed into any load unit, or were placed into a load unit whose operative container type doesn't support `SERVICE`. This container is only created if at least one such line item exists.

#### Containers from load units

For each load unit attached to the pick job, fulfillmenttools:

1. Resolves the load unit's `operativeContainerTypeRef`.
2. If the operative container type includes `SERVICE` in its `allowedOperativeTypes`, a `PHYSICAL` container is created and linked to that type.
3. If the operative container type doesn't support `SERVICE`, or no type is set, the load unit's line items are routed to the single virtual container instead.
4. Maps the load unit's line items to service container line items.
5. Skips the load unit entirely if no relevant line items result from the mapping.

The following fields are copied from the load unit to the service container:

| Service container field       | Source                                                                                      |
| ----------------------------- | ------------------------------------------------------------------------------------------- |
| `nameLocalized`               | Load unit `nameLocalized`                                                                   |
| `customAttributes`            | Load unit `customAttributes`, merged with the operative container type's `customAttributes` |
| `scannableCodes`              | Load unit `codes`                                                                           |
| `storageLocationRef`          | Load unit `storageLocationRef`                                                              |
| `stackRef`                    | Load unit `stackRef`                                                                        |
| `descriptionLocalized`        | Load unit `descriptionLocalized`, defaults to operative container type                      |
| `iconUrl`                     | Load unit `iconUrl`, defaults to operative container type                                   |
| `weightLimitInG`              | Load unit `weightLimitInG`, defaults to operative container type                            |
| `dimensions`                  | Load unit `dimensions`, defaults to operative container type                                |
| `previousModuleContainerInfo` | Set to `{ type: "LOADUNIT", containerRef: <loadUnit.id> }`                                  |

#### Line item mapping and batch picking

Each load unit line item is mapped to one or more service container line items. A special case applies when items were batch picked from different orders into the same load unit slot during a pick run:

* A load unit line item can reference multiple `globalLineItemIds` when items with the same article were batch picked from different orders.
* In that case, the line item is split by `globalLineItemId`. The quantity for each split entry is taken from the corresponding `pickLineItem.picked` value.
* In the standard case (single `globalLineItemId`), the load unit line item's `quantity` is used directly.

#### Virtual container

Service containers represent the physical objects (totes, trolleys, or similar) that carry picked items to the service station. They record details such as the container's current location via `storageLocationRef`. Because operative container types are configured per module, a type used during picking may not support `SERVICE`. Additionally, the picking process allows items to be picked without being placed into any load unit.

To ensure every picked item is represented in a service container, the system collects items from both cases (see following) into a single `VIRTUAL` container. This container is created along with all other service containers when fulfillmenttools updates the linked service jobs as part of closing the pick job. It's only created if at least one line item falls into either of the following categories:

* Items picked into a load unit whose operative container type doesn't support `SERVICE`
* Items that have a `globalLineItemId` and a `picked` quantity greater than `0`, but were not placed into any load unit during packing

If no such items exist because all items are already in physical containers, the virtual container is not created. When it is created, it has no `operativeContainerTypeRef`, and its `sequenceNumber` is always `0`.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.fulfillmenttools.com/documentation/by-pillar/store-operations/services/service-container.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
