# External documents

External documents that are relevant during order fulfillment can be added to the order process. As a result, these documents can be, for example, printed via the [Operations app](https://docs.fulfillmenttools.com/documentation/apps/operations-app/printing) or can be used by other clients to upload or change documents during processing.

A typical use case is to attach a branded invoice document which is generated outside of the fulfillmenttools platform. Such a document can be added to the process to be printed and added to the parcel during order fulfillment.

External documents can be assigned to a section, depending on the operational process in which it is needed. This way it can be configured in which part of the app the document is displayed, e.g., in the Picking, Packing, or Handover section.&#x20;

External documents can be added to the `process` entity. This allows the documents to be selected for printing within the mobile application or to be uploaded or modified by other clients during fulfillment processing.

{% hint style="info" %}
The print and document configuration must be checked as well when setting up printing of external documents. To control whether external documents are enabled for specific entity types, see [Document control with tags](#document-control-with-tags).
{% endhint %}

## Adding an external document

To add a document to a `process`, perform a `POST` request with a JSON body to the following endpoint:

```http
POST https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/processes/<processId>/documents
```

```json
{
    "type": "PDF",
    "section": "PACKJOB",
    "file": {
        "name": "invoice.pdf",
        "content": "<base64-encoded-file-content>"
    }
}
```

{% hint style="info" %}
The system only supports uploading PDF files.
{% endhint %}

### Document sections

The `section` field in the request object assigns the document to a specific part of the fulfillment process. This controls where in the application the document is displayed.

The following sections are supported:

* `PACKJOB`
* `PICKJOB`
* `HANDOVERJOB`
* `ORDER`
* `PARCEL`
* `PACKING_TARGET_CONTAINER`

### Placeholder documents

A placeholder document can be created early in the process without any file content. When the printing section is opened and the final document is not yet available, information about the pending document is displayed. Adding placeholders is optional, but it improves the user experience for the warehouse staff.

To create a placeholder, perform a `POST` request to the same endpoint with the following JSON body:

```http
POST https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/processes/<processId>/documents
```

```json
{
    "type": "PDF",
    "section": "PACKJOB"
}
```

## Updating an external document

Once a final document is available, it can be uploaded to replace a placeholder or update an existing document. To modify a document, perform a `PUT` request with the `documentId` and a JSON body containing the file.

```http
PUT https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/processes/<processId>/documents/<documentId>
```

```json
{
    "version": 1,
    "file": {
        "name": "invoice.pdf",
        "content": "<base64-encoded-file-content>"
    }
}
```

## Document control with tags

Each operative entity (pick job, pack job, parcel, and handover job) can have documents attached, such as shipping labels, delivery notes, or return notes. By default, a predefined set of document categories is enabled for each entity type. The tag configuration system lets you control which document categories are offered for each entity, enabling you to tailor documents to specific order types, sales channels, or other business rules.

A typical use case is differentiating between marketplace orders and own-store orders: marketplace orders may require only a shipping label, while own-store orders should also include a delivery note and return note.

### Document categories

The following document categories are available in fulfillmenttools:

| Category        | Description                          |
| --------------- | ------------------------------------ |
| `SENDLABEL`     | Shipping label                       |
| `RETURNLABEL`   | Return shipping label                |
| `DELIVERYNOTE`  | Delivery note                        |
| `RETURNNOTE`    | Return note                          |
| `EXTERNAL`      | External documents uploaded via API  |
| `TRANSFERLABEL` | Transfer label (for custom carriers) |
| `CUSTOMS`       | Customs document                     |

Not every category is available for every entity type. The following table shows which categories can be configured per entity:

| Category        | Pick job | Pack job | Parcel | Handover job |
| --------------- | -------- | -------- | ------ | ------------ |
| `SENDLABEL`     | Yes      | Yes      | Yes    | Yes          |
| `RETURNLABEL`   | Yes      | Yes      | Yes    | Yes          |
| `DELIVERYNOTE`  | Yes      | Yes      | Yes    | No           |
| `RETURNNOTE`    | Yes      | Yes      | Yes    | No           |
| `EXTERNAL`      | Yes      | Yes      | Yes    | Yes          |
| `TRANSFERLABEL` | No       | Yes      | Yes    | No           |
| `CUSTOMS`       | No       | No       | Yes    | No           |

{% hint style="info" %}
`TRANSFERLABEL` is added automatically based on the carrier type and can't be configured via tags. `CUSTOMS` documents on parcels are added from carrier results.
{% endhint %}

### How tag-based document control works

The tag configuration controls which document categories are enabled for an entity. It uses a two-level mechanism:

1. **Default documents** (`offeredDocumentsByDefault`): These document categories are applied when the entity has no tags or when none of its tags match a configured rule.
2. **Per-tag documents** (`offeredDocumentsPerTag`): These document categories are applied when the entity's tags match a specific tag and value combination.

#### Matching logic

When an operative entity is created, fulfillmenttools determines which documents to offer using the following logic:

1. If the entity **has tags**, `offeredDocumentsPerTag` is checked for entries whose `tagRef` and `matchingValues` match one of the entity's tags.
2. If a **match is found**, the `offeredDocuments` from that matching entry are used.
3. If **no match is found** or the entity has **no tags**, it falls back to `offeredDocumentsByDefault`.

### Setting up a tag configuration

{% stepper %}
{% step %}
**Create the needed tag**

Create a new tag or use an existing tag that represents the order attribute you want to differentiate by (for example, sales channel or shipping method).

{% hint style="info" %}
More information on tags can be found in the [Tags article](https://docs.fulfillmenttools.com/documentation/getting-started/tags).
{% endhint %}
{% endstep %}

{% step %}
**Configure the tag configuration for the desired entity**

Use the corresponding API endpoint to set the tag configuration. Each entity type has its own endpoint:

<table><thead><tr><th width="204.74609375">Entity</th><th>Endpoint</th></tr></thead><tbody><tr><td>Pick job</td><td><code>PUT /api/configurations/tags/pickjob</code></td></tr><tr><td>Pack job</td><td><code>PUT /api/configurations/tags/packjob</code></td></tr><tr><td>Parcel</td><td><code>PUT /api/configurations/tags/parcel</code></td></tr><tr><td>Handover job</td><td><code>PUT /api/configurations/tags/handoverjob</code></td></tr></tbody></table>

{% hint style="info" %}
The `GET` method is available on the same endpoints to retrieve the current configuration.

Permissions required: `CONFIG_READ` for reading, `CONFIG_WRITE` for writing.
{% endhint %}
{% endstep %}

{% step %}
**Create orders with the appropriate tags**

When orders are created with the configured tags, the matching document configuration is automatically applied to the operative entities created from those orders.
{% endstep %}
{% endstepper %}

### Example: Configuring pick job documents

The following example configures document categories for pick jobs, differentiating between express orders and marketplace orders.

{% tabs %}
{% tab title="Endpoint" %}

```http
PUT https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/configurations/tags/pickjob
```

{% endtab %}

{% tab title="Request body" %}

```json
{
  "version": 1,
  "offeredDocumentsByDefault": [
    { "documentCategory": "SENDLABEL" },
    { "documentCategory": "DELIVERYNOTE" }
  ],
  "offeredDocumentsPerTag": [
    {
      "tagRef": "tag-shipping-method",
      "matchingValues": ["express", "same-day"],
      "offeredDocuments": [
        { "documentCategory": "SENDLABEL" },
        { "documentCategory": "DELIVERYNOTE" },
        { "documentCategory": "RETURNNOTE" },
        { "documentCategory": "EXTERNAL" }
      ]
    },
    {
      "tagRef": "tag-channel",
      "matchingValues": ["marketplace"],
      "offeredDocuments": [
        { "documentCategory": "SENDLABEL" }
      ]
    }
  ]
}
```

In this example:

* **Default** (no tags or no matching tags): Pick jobs will have `SENDLABEL` and `DELIVERYNOTE` enabled.
* **Express or same-day shipping**: Pick jobs additionally get `RETURNNOTE` and `EXTERNAL` documents.
* **Marketplace orders**: Pick jobs only get a `SENDLABEL`, no delivery note or return note.
  {% endtab %}
  {% endtabs %}

### Allowed categories in per-tag configuration

When configuring `offeredDocumentsPerTag`, only certain document categories are allowed per entity type. The system validates the configuration and rejects unsupported categories.

<table><thead><tr><th width="374">Entity</th><th>Allowed categories in `offeredDocumentsPerTag`</th></tr></thead><tbody><tr><td>Pick job</td><td><code>SENDLABEL</code>, <code>RETURNLABEL</code>, <code>DELIVERYNOTE</code>, <code>RETURNNOTE</code>, <code>EXTERNAL</code></td></tr><tr><td>Pack job</td><td><code>SENDLABEL</code>, <code>RETURNLABEL</code>, <code>DELIVERYNOTE</code>, <code>RETURNNOTE</code>, <code>EXTERNAL</code></td></tr><tr><td>Parcel</td><td><code>SENDLABEL</code>, <code>RETURNLABEL</code>, <code>DELIVERYNOTE</code>, <code>RETURNNOTE</code>, <code>EXTERNAL</code>, <code>CUSTOMS</code></td></tr><tr><td>Handover job</td><td><code>EXTERNAL</code></td></tr></tbody></table>

{% hint style="warning" %}
This validation applies to `offeredDocumentsPerTag` only. The `offeredDocumentsByDefault` array isn't validated against these restrictions.
{% endhint %}
