# Create Orders/Trackings

This API allows you to create new orders, update existing orders, add shipment trackings, cancel trackings, cancel orders, and manage partial line item cancellations.

## Endpoint Details

* Method: `PUT`
* Path: `/v4/track/orders/`
* Full URL: `https://api.parcellab.com/v4/track/orders/`
* Authentication: Header `Authorization: Parcellab-API-Token <token>`

This endpoint is idempotent, meaning you can safely call it multiple times with the same data without creating duplicate orders. If an order exists, it will be updated; if not, it will be created.

<details>

<summary><i class="fa-key">:key:</i> Authentication</summary>

Use the `Authorization` header with this format:

`Authorization: Parcellab-API-Token <token>`

API tokens can be created at `https://app.parcellab.com/service/account/apitoken/`. For `PUT /v4/track/orders/`, the token must include at least the `write` scope. Make sure to use the API token (non-encoded version, not the encoded token).

</details>

<details>

<summary><i class="fa-bug">:bug:</i> Error Handling</summary>

The API returns standard HTTP status codes:

* `200 OK` - Order successfully updated
* `201 Created` - New order created
* `400 Bad Request` - Invalid request data
* `401 Unauthorized` - Missing or invalid authentication
* `403 Forbidden` - Insufficient permissions
* `404 Not Found` - Order not found (for GET requests)

**Validation Errors**

```json
{
  "errors": [
    {
      "detail": "Cannot cancel 3 of item ITEM-001. Only 2 available.",
      "attr": "mutations.0.line_items.0.quantity_to_cancel",
      "code": "invalid"
    }
  ],
  "type": "validation_error"
}
```

**Mutation Results**

Each mutation includes a result indicating success or failure:

```json
{
  "mutations": [
    {
      "type": "change_line_item_quantity",
      "result": {
        "success": true,
        "message": "Line item ITEM-001 cancelled (1 → 0)"
      }
    }
  ]
}
```

</details>

## Example API Call

Use following samples as a starting point for the API interaction. Swap your token in the header (use your token in the same format) and set your `account` key in the payload.

For sample payloads at different stages of the order lifecycle, see below: [#typical-use-cases-for-oms-and-wms-integration](#typical-use-cases-for-oms-and-wms-integration "mention")

<details>

<summary><code>curl</code></summary>

```shellscript
curl --request PUT \
  --url https://api.parcellab.com/v4/track/orders/ \
  --header 'Authorization: Parcellab-API-Token MTYxMjE5NzpocTF1L3hvbnV5NWVtY25lbHlmYzQrNylwKnJva3N1dXV0YzhoKXVl' \
  --header 'content-type: application/json' \
  --data '{"account":1612197,"order_number":"ORD-2026-02-25-01","recipient_email":"customer@example.com","destination_country_iso3":"USA"}'
```

</details>

<details>

<summary>JavaScript <code>fetch</code></summary>

```javascript
const url = 'https://api.parcellab.com/v4/track/orders/';
const options = {
  method: 'PUT',
  headers: {
    'content-type': 'application/json',
    Authorization: 'Parcellab-API-Token MTYxMjE5NzpocTF1L3hvbnV5NWVtY25lbHlmYzQrNylwKnJva3N1dXV0YzhoKXVl'
  },
  body: '{"account":1612197,"order_number":"ORD-2026-02-25-01","recipient_email":"customer@example.com","destination_country_iso3":"USA"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

</details>

<details>

<summary>Python <code>requests</code></summary>

```python
import requests

url = "https://api.parcellab.com/v4/track/orders/"

payload = {
  "account": 1612197,
  "order_number": "ORD-2026-02-25-01",
  "recipient_email": "customer@example.com",
  "destination_country_iso3": "USA"
}
headers = {
  "content-type": "application/json",
  "Authorization": "Parcellab-API-Token MTYxMjE5NzpocTF1L3hvbnV5NWVtY25lbHlmYzQrNylwKnJva3N1dXV0YzhoKXVl"
}

response = requests.put(url, json=payload, headers=headers)

print(response.json())
```

</details>

## Best Practices

1. **Use Idempotent Updates**: The `PUT` endpoint is idempotent. Use it for both creation and updates to avoid duplicates.
2. **Partial Updates**: Only send the fields you want to update. The API merges changes with existing data.
3. **Order Identification**: Use either `order_number` + `account` or `external_id` to identify orders. When creating new orders, `external_id` is generated by parcelLab and returned in the response.
4. **Tracking Identification**: Trackings require either `tracking_number` + `courier` or `external_reference`.
5. **Use `change_line_item_quantity` for partial cancellations**: If only part of an order line should be cancelled or reduced, send a `change_line_item_quantity` mutation with the new absolute quantity. For full-order cancellation, use the `cancel_order` mutation instead.
6. **Keep line identifiers unique per logical line**: `line_item_id` should uniquely identify one logical order line. If the same SKU appears on multiple lines, do not reuse the same `line_item_id`; use the source system's stable line key so each line can be targeted independently.
7. **Keep order and tracking line identifiers aligned**: If you send shipment-level `tracking.articles`, the identifiers in those articles should match the corresponding item in `articles_order` by `line_item_id` or `order_item_id`. This alignment is required for later line-item changes to be reflected correctly on the order status page and in downstream payloads.
8. **Validate Line Item Quantities**: Before cancelling, ensure the requested quantity doesn't exceed available quantity.
9. **Tags**: You can set tags on a tracking to identify custom attributes in filters and exports. For example: `tags: ["loyalty_customer", "customer_loyalty:gold", "international_order", "dropship"]`.

## Data Models

#### Order Schema

For upserts, send only the fields you want to set or update.

<details>

<summary>Recommended fields to send</summary>

<table><thead><tr><th width="201">Field</th><th width="112">Type</th><th width="141.5">When to send</th><th>Notes</th></tr></thead><tbody><tr><td><code>account</code></td><td>integer</td><td>Always</td><td>Required</td></tr><tr><td><code>order_number</code></td><td>string</td><td>Create + most updates</td><td>Primary external reference in most integrations.</td></tr><tr><td><code>destination_country_iso3</code></td><td>string</td><td>Create</td><td>Required on create.</td></tr><tr><td><code>recipient_email</code></td><td>string</td><td>Create</td><td>Required on create.</td></tr><tr><td><code>recipient_name</code></td><td>string</td><td>Recommended</td><td>Useful for notifications and lookup UX.</td></tr><tr><td><code>client_key</code></td><td>string</td><td>Recommended</td><td>Important for multi-brand/multi-shop accounts.</td></tr><tr><td><code>shipping_address</code></td><td>AddressSchema</td><td>Recommended</td><td>Strongly recommended if available.</td></tr><tr><td><code>billing_address</code></td><td>AddressSchema</td><td>Optional</td><td>Useful if billing and shipping differ.</td></tr><tr><td><code>language_iso2</code></td><td>string</td><td>Recommended</td><td>Enables localized communication.</td></tr><tr><td><code>timezone</code></td><td>string</td><td>Optional</td><td>Helps communication timing.</td></tr><tr><td><code>delivery_method</code></td><td>string</td><td>Optional</td><td>Must be configured in system.</td></tr><tr><td><code>articles_order</code></td><td>LineItemOrder[]</td><td>Recommended</td><td>Needed for line-item-level mutations and visibility.</td></tr><tr><td><code>external_reference</code></td><td>string</td><td>Optional</td><td>Retailer internal order reference.</td></tr><tr><td><code>customer_number</code></td><td>string</td><td>Optional</td><td>Retailer customer identifier.</td></tr><tr><td><code>invoice_number</code></td><td>string</td><td>Optional</td><td>Invoice reference.</td></tr><tr><td><code>payment_method</code></td><td>string</td><td>Optional</td><td>Payment method.</td></tr><tr><td><code>order_currency</code></td><td>string</td><td>Optional</td><td>ISO 4217</td></tr><tr><td><code>order_total_amount</code></td><td>decimal</td><td>Optional</td><td>Order total.</td></tr><tr><td><code>order_tax_amount</code></td><td>decimal</td><td>Optional</td><td>Tax amount.</td></tr><tr><td><code>order_net_amount</code></td><td>decimal</td><td>Optional</td><td>Net amount.</td></tr><tr><td><code>order_discount_amount</code></td><td>decimal</td><td>Optional</td><td>Discount amount.</td></tr><tr><td><code>order_date</code></td><td>datetime</td><td>Optional</td><td>Order creation timestamp.</td></tr><tr><td><code>channel</code></td><td>string</td><td>Optional</td><td>Sales channel.</td></tr><tr><td><code>announced_delivery_date_min</code></td><td>date</td><td>Optional</td><td>Earliest expected delivery.</td></tr><tr><td><code>announced_delivery_date_max</code></td><td>date</td><td>Optional</td><td>Latest expected delivery.</td></tr><tr><td><code>cancelled_date</code></td><td>datetime</td><td>Optional</td><td>Use when explicitly marking the full order as cancelled.</td></tr><tr><td><code>cancelled_reason</code></td><td>string</td><td>Optional</td><td>Optional full-order cancellation reason such as <code>customer</code>, <code>inventory</code>, <code>payment</code>, or <code>other</code>.</td></tr><tr><td><code>tags</code></td><td>string[]</td><td>Optional</td><td>For filtering/export.</td></tr><tr><td><code>additional_attributes</code></td><td>AdditionalAttribute[]</td><td>Optional</td><td>Custom attributes.</td></tr><tr><td><code>mutations</code></td><td>Mutation[]</td><td>Optional</td><td>Use for tracking and line-item changes.</td></tr></tbody></table>

</details>

<details>

<summary>Generated/returned by parcelLab</summary>

* `external_id` (UUID): generated by parcelLab on create.
* `mutations[].operation_id` (UUID): generated if not provided.
* `mutations[].result`: populated in responses with per-mutation processing status.

</details>

#### Line Item Order Schema

Represents individual products in `articles_order`.

<details>

<summary>Recommended fields to send</summary>

| Field                   | Type                   | Notes                                                                          |
| ----------------------- | ---------------------- | ------------------------------------------------------------------------------ |
| `line_item_id`          | string                 | Required identifier for mutations. Must be unique per logical order line.      |
| `order_item_id`         | string                 | Recommended when available. Keep it stable across order and tracking payloads. |
| `quantity`              | integer                | Ordered/open quantity.                                                         |
| `sku`                   | string                 | Recommended                                                                    |
| `product_id`            | string                 | Recommended                                                                    |
| `variant_id`            | string                 | Recommended when variants exist.                                               |
| `article_name`          | string                 | Recommended for portal display.                                                |
| `article_category`      | string                 | Optional                                                                       |
| `article_store_url`     | string                 | Optional                                                                       |
| `article_image_url`     | string                 | Optional                                                                       |
| `unit_price`            | decimal                | Optional                                                                       |
| `tags`                  | string\[]              | Optional                                                                       |
| `additional_attributes` | AdditionalAttribute\[] | Optional                                                                       |

</details>

<details>

<summary>Generated/managed by parcelLab</summary>

* `shipped_quantity`
* `original_quantity`
* `status`
* `change_reason`
* `updated_at`

</details>

#### Tracking Schema

Represent an individual shipment, package or parcel used to fulfill (parts of) an order.

<details>

<summary>Recommended fields to send</summary>

| Field                         | Type            | Notes                                                                                                                   |
| ----------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `tracking_number` + `courier` | string + string | Primary tracking identifier pair.                                                                                       |
| `external_reference`          | string          | Alternative identifier where applicable.                                                                                |
| `articles`                    | LineItem\[]     | Recommended for shipment-level line-item mapping. Keep `line_item_id` or `order_item_id` aligned with `articles_order`. |
| `destination_country_iso3`    | string          | Recommended                                                                                                             |
| `recipient_postal_code`       | string          | Recommended when full address is not sent.                                                                              |
| `shipping_address`            | AddressSchema   | Recommended if tracking-level address differs.                                                                          |
| `courier_service_level`       | string          | Optional                                                                                                                |
| `warehouse`                   | string          | Optional                                                                                                                |
| `origin_country_iso3`         | string          | Optional                                                                                                                |
| `origin_postal_code`          | string          | Optional                                                                                                                |
| `announced_delivery_date`     | date            | Optional ETA communication.                                                                                             |
| `announced_send_date`         | date            | Optional                                                                                                                |
| `delivery_method`             | string          | Optional                                                                                                                |
| `shipping_cost_total`         | decimal         | Optional                                                                                                                |
| `shipping_weight_total`       | float           | Optional                                                                                                                |
| `shipping_weight_unit`        | string          | Optional                                                                                                                |
| `requires_signature`          | boolean         | Optional                                                                                                                |
| `is_return`                   | boolean         | Optional                                                                                                                |
| `flags`                       | string\[]       | Optional                                                                                                                |
| `tags`                        | string\[]       | Optional                                                                                                                |
| `additional_fields`           | object          | Optional custom payload.                                                                                                |

</details>

{% hint style="info" %}
Customer-defined tracking keys must be sent inside `tracking.additional_fields` as key-value pairs. Do not send custom keys such as `seller_organization_code` or `enterprise_code` at the top level of the `tracking` object.
{% endhint %}

<details>

<summary>Example custom field structure</summary>

```json
{
  "type": "add_tracking",
  "tracking": {
    "tracking_number": "T100001903",
    "courier": "fedex",
    "delivery_number": "PO_S100001903",
    "external_reference": "PO_S100001903",
    "warehouse": "RKC_VENDOR",
    "additional_fields": {
      "enterprise_code": "13",
      "seller_organization_code": "RKC_VENDOR"
    }
  }
}
```

</details>

<details>

<summary>Generated/managed by parcelLab</summary>

* `cancelled_date` can be set by parcelLab when a `cancel_tracking` mutation is processed.

</details>

<details>

<summary>Example tracking payload as JSON</summary>

```json
{
  "tracking_number": "1234567890",
  "courier": "dhl",
  "external_reference": "SHIP-2024-001",
  "recipient_postal_code": "10001",
  "destination_country_iso3": "USA",
  "language_iso2": "en",
  "timezone": "America/New_York",
  "courier_service_level": "express",
  "warehouse": "WH-US-EAST",
  "origin_country_iso3": "USA",
  "origin_postal_code": "07001",
  "announced_delivery_date": "2024-01-18",
  "announced_send_date": "2024-01-16",
  "shipping_weight_total": 1500,
  "shipping_weight_unit": "g",
  "requires_signature": true,
  "articles": [
    {
      "line_item_id": "ITEM-001",
      "product_id": "PROD-123",
      "article_name": "Blue T-Shirt",
      "quantity": 2,
      "sku": "TSHIRT-BLUE-M"
    }
  ],
  "tags": ["express-delivery", "high-value"],
  "additional_fields": {
    "special_instructions": "Handle with care"
  }
}
```

</details>

#### Additional Data

parcelLab in general allows you to send additional attributes with custom data. For full data-element definitions, refer to the following page.

{% content-ref url="/pages/-LQpTnZA2sICcHRiB8fQ" %}
[Data Model](/docs/developers/data-elements/data-model.md)
{% endcontent-ref %}

## Mutations

Mutations allow you to perform actions on orders.

<details>

<summary><code>AddOrUpdateTrackingMutation</code></summary>

Adds or updates a tracking of an order. Update an existing tracking by running this mutation and using the same values for keys `courier` and `tracking_number`, as the combined value of those fields are idempotent.

```json
{
  "type": "add_tracking",
  "tracking": {
    // TrackingSchema fields
  }
}
```

</details>

<details>

<summary><code>CancelTrackingMutation</code></summary>

Cancel a tracking by identifying it by its `courier` and `tracking_number`.

```json
{
  "type": "cancel_tracking",
  "tracking": {
    "tracking_number": "1234567890",
    "courier": "dhl"
    // Only identifiers needed
  }
}
```

</details>

<details>

<summary><code>ChangeLineItemQuantityMutation</code></summary>

Cancel or reduce the open quantity of an order line item. Send the new absolute quantity for the line item. Quantities already assigned to a tracking are considered fulfilled and cannot be cancelled anymore.

This is a line-item mutation. Use it when a specific line should be reduced or cancelled by setting its `quantity` to `0`.

{% hint style="warning" %}
`change_line_item_quantity` targets one logical order line. Make sure the target line has a unique `line_item_id` in `articles_order`. If you also send shipment-level `tracking.articles`, keep `line_item_id` or `order_item_id` aligned between the order and tracking payloads so later line-item changes can be mapped correctly on the order status page.
{% endhint %}

```json
{
  "type": "change_line_item_quantity",
  "line_item_id": "ITEM-001",
  "quantity": 0,
  "current_quantity": 1,
  "reason": "customer_changed_mind"
}
```

If all order lines are changed to `quantity: 0`, downstream portals may end up displaying the order as cancelled because no active items remain. For an explicit full-order cancellation, use the `cancel_order` mutation instead of relying only on line-item mutations.

</details>

<details>

<summary><code>CancelOrderMutation</code></summary>

Cancel an entire order. The server sets `order_status` to `Cancelled` and generates `cancelled_date` when it is not provided. If the payload also contains conflicting top-level `order_status`, `cancelled_date`, or `cancelled_reason` fields, the mutation values take precedence.

```json
{
  "type": "cancel_order",
  "cancelled_reason": "customer",
  "cancelled_date": "2026-03-27T10:15:00Z"
}
```

Both `cancelled_reason` and `cancelled_date` are optional. Valid values for `cancelled_reason` are `customer`, `inventory`, `payment`, and `other`.

{% hint style="info" %}
`cancel_order` can be combined with other mutations in the same request. For example, sending `cancel_order` together with `add_tracking` will process both the tracking update and the order cancellation.
{% endhint %}

If shipment records already exist and should also be marked as cancelled, send `cancel_tracking` mutations for those trackings in the same request.

</details>

<details>

<summary><code>AddLineItemMutation</code></summary>

Adds a line item to an order.

```json
{
  "type": "add_line_item",
  "line_item": {
    "line_item_id": "ITEM-NEW",
    "product_id": "PROD-999",
    "article_name": "Green Hat",
    "quantity": 1,
    "unit_price": "19.99"
  }
}
```

</details>

<details>

<summary><code>ReplaceLineItemMutation</code></summary>

Replaces a line item with another line item. To cancel a line item, replace it with a `quantity: 0` line item.

```json
{
  "type": "replace_line_item",
  "old_line_item_id": "ITEM-001",
  "new_line_item": {
    "line_item_id": "ITEM-NEW2",
    "product_id": "PROD-888",
    "article_name": "Red Hat",
    "quantity": 1,
    "unit_price": "19.99"
  },
  "reason": "size_exchange"
}
```

</details>

## Typical Use Cases for OMS and WMS Integration

You can use the Order API to update parcelLab about all updates on the order from placement to cancellation or fulfillment.

### Integration Flow

1. **Order Placement**: Create the order with all known information
2. **Cancellations**: Handle partial cancellations with `change_line_item_quantity` or full-order cancellations with `cancel_order`
3. **Fulfillment**: Add trackings as items ship
4. **Delivery**: System automatically updates based on carrier events (outside of this API)

### Sample Mutations

<details>

<summary><i class="fa-file-circle-plus">:file-circle-plus:</i> Create a New Order</summary>

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "ORD-2024-001",
  "recipient_email": "customer@example.com",
  "recipient_name": "John Doe",
  "destination_country_iso3": "USA",
  "language_iso2": "en",
  "order_total_amount": "129.99",
  "order_currency": "USD",
  "order_date": "2024-01-15T10:30:00Z",
  "shipping_address": {
    "first_name": "John",
    "last_name": "Doe",
    "address_line": "123 Main St",
    "city": "New York",
    "postal_code": "10001",
    "country_iso3": "USA",
    "region_code": "NY"
  },
  "articles_order": [
    {
      "line_item_id": "ITEM-001",
      "product_id": "PROD-123",
      "article_name": "Blue T-Shirt",
      "quantity": 2,
      "unit_price": "29.99"
    },
    {
      "line_item_id": "ITEM-002",
      "product_id": "PROD-456",
      "article_name": "Black Jeans",
      "quantity": 1,
      "unit_price": "69.99"
    }
  ]
}
```

**Response:**

```json
{
  "external_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "order_number": "ORD-2024-001"
  // ... all order fields ...
}
```

</details>

<details>

<summary><i class="fa-file-pen">:file-pen:</i> Update an Existing Order</summary>

Only send the fields you want to update.

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "order_number": "ORD-2024-001",
  "account": 1234,
  "customer_number": "CUST-98765",
  "payment_method": "credit_card"
}
```

</details>

<details>

<summary><i class="fa-box-circle-check">:box-circle-check:</i> Add Tracking to an Order</summary>

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "order_number": "ORD-2024-001",
  "account": 1234,
  "mutations": [
    {
      "type": "add_tracking",
      "tracking": {
        "tracking_number": "1234567890",
        "courier": "dhl",
        "warehouse": "WH-01",
        "announced_delivery_date": "2024-01-18",
        "articles": [
          {
            "line_item_id": "ITEM-001",
            "quantity": 2
          }
        ]
      }
    }
  ]
}
```

</details>

<details>

<summary><i class="fa-file-circle-xmark">:file-circle-xmark:</i> Cancel a Tracking</summary>

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "order_number": "ORD-2024-001",
  "account": 1234,
  "mutations": [
    {
      "type": "cancel_tracking",
      "tracking": {
        "tracking_number": "1234567890",
        "courier": "dhl"
      }
    }
  ]
}
```

</details>

<details>

<summary><i class="fa-ban">:ban:</i> Cancel an Order</summary>

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "order_number": "ORD-2024-001",
  "account": 1234,
  "mutations": [
    {
      "type": "cancel_order",
      "cancelled_reason": "customer"
    }
  ]
}
```

**Notes on Order Cancellation:**

* `cancelled_date` is generated server-side when not provided
* The mutation sets `order_status` to `Cancelled`
* If the payload contains conflicting top-level cancellation fields, the mutation values take precedence
* To also cancel existing shipment records, include `cancel_tracking` mutations in the same request

</details>

<details>

<summary><i class="fa-cart-circle-xmark">:cart-circle-xmark:</i> Cancel Line Items (Partial Cancellation)</summary>

This allows cancelling specific quantities of line items at the order level.

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "order_number": "ORD-2024-001",
  "account": 1234,
  "mutations": [
    {
      "type": "change_line_item_quantity",
      "line_item_id": "ITEM-001",
      "quantity": 0,
      "current_quantity": 1,
      "reason": "customer_changed_mind"
    }
  ]
}
```

**Notes on Line Item Cancellation:**

* Cancellations are tracked at the order level in `articles_order`
* The system validates quantity constraints (including shipped quantity guards)
* When line items are cancelled, updates are sent to all trackings in the order
* Line item mutation metadata is stored on the item (for example `status`, `original_quantity`, `change_reason`, `updated_at`)

</details>

<details>

<summary><i class="fa-conveyor-belt-boxes">:conveyor-belt-boxes:</i> Complex Multi-Operation Update</summary>

You can combine multiple operations in a single request.

**Request:**

```
PUT /v4/track/orders/
```

```json
{
  "order_number": "ORD-2024-001",
  "account": 1234,
  "customer_number": "CUST-UPDATE",  // Update order field
  "mutations": [
    {
      "type": "add_tracking",
      "tracking": {
        "tracking_number": "9876543210",
        "courier": "ups",
        "articles": [
          {
            "line_item_id": "ITEM-002",
            "quantity": 1
          }
        ]
      }
    },
    {
      "type": "change_line_item_quantity",
      "line_item_id": "ITEM-001",
      "quantity": 0,
      "current_quantity": 1,
      "reason": "customer_changed_mind"
    }
  ]
}
```

</details>

<details>

<summary><i class="fa-boxes-packing">:boxes-packing:</i> OMS Mixed Status Example (2 Cancelled, 3 Shipped, 1 Remaining)</summary>

**Scenario:**

* `order_number`: `OMS-100045`
* Line `LINE-1` was ordered with quantity `6`
* OMS then cancels `2`
* FedEx ships `3`
* `1` remains open/backordered for later shipment

**Step 1: Create the order (minimal but valid create payload):**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "destination_country_iso3": "USA",
  "recipient_email": "customer@example.com",
  "articles_order": [
    {
      "line_item_id": "LINE-1",
      "sku": "SKU-RED-42",
      "quantity": 6
    },
    {
      "line_item_id": "LINE-2",
      "sku": "SKU-BLUE-10",
      "quantity": 1
    },
    {
      "line_item_id": "LINE-3",
      "sku": "SKU-GREEN-7",
      "quantity": 1
    }
  ]
}
```

**Step 2: OMS partial cancellation (6**→**4) using `change_line_item_quantity`:**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "change_line_item_quantity",
      "line_item_id": "LINE-1",
      "quantity": 4,
      "current_quantity": 6,
      "reason": "oms_partial_cancel"
    }
  ]
}
```

**Step 3: First FedEx shipment (`3` units) using `add_tracking`:**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "add_tracking",
      "tracking": {
        "tracking_number": "794600000001",
        "courier": "fedex",
        "articles": [
          {
            "line_item_id": "LINE-1",
            "quantity": 3
          }
        ]
      }
    }
  ]
}
```

**Step 4: Remaining quantity (`1`) is implicit.**

No additional mutation is required to represent "not yet shipped/backordered". At this point:

* Ordered/open quantity for `LINE-1` is `4`
* Shipped quantity recorded across trackings is `3`
* Remaining not-yet-shipped quantity is `1`

**Step 5a (later): If the remaining `1` ships, send another `add_tracking`:**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "add_tracking",
      "tracking": {
        "tracking_number": "794600000002",
        "courier": "fedex",
        "articles": [
          {
            "line_item_id": "LINE-1",
            "quantity": 1
          }
        ]
      }
    }
  ]
}
```

**Step 5b (alternative): If the remaining `1` is cancelled instead of shipped:**

```json
PUT /v4/track/orders/
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "change_line_item_quantity",
      "line_item_id": "LINE-1",
      "quantity": 3,
      "current_quantity": 4,
      "reason": "oms_cancel_remaining"
    }
  ]
}
```

</details>

<details>

<summary><i class="fa-cart-circle-exclamation">:cart-circle-exclamation:</i> Other Minimal Mutation Payloads (Same <code>order_number</code> Pattern)</summary>

**Add a line item:**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "add_line_item",
      "line_item": {
        "line_item_id": "LINE-4",
        "sku": "SKU-BLACK-9",
        "quantity": 1
      }
    }
  ]
}
```

**Replace a line item (substitution):**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "replace_line_item",
      "old_line_item_id": "LINE-2",
      "new_line_item": {
        "line_item_id": "LINE-2B",
        "sku": "SKU-BLUE-10-V2",
        "quantity": 1
      },
      "reason": "substitution"
    }
  ]
}
```

**Cancel an existing tracking (e.g., label voided):**

```
PUT /v4/track/orders/
```

```json
{
  "account": 1234,
  "order_number": "OMS-100045",
  "mutations": [
    {
      "type": "cancel_tracking",
      "tracking": {
        "tracking_number": "794600000001",
        "courier": "fedex"
      }
    }
  ]
}
```

</details>

## FAQs

<details>

<summary>Where do I get an API token?</summary>

Create it in the parcelLab App:

* Open <https://app.parcellab.com/service/account/apitoken/>
* Create a token with at least `read` and `write` scope
* Use the **non-encoded** token value in your API calls
  * If the UI shows both an “encoded” and “non-encoded” value, pick the **non-encoded** one
* Send it via this header: `Authorization: Parcellab-API-Token <token>`

</details>

<details>

<summary>Where do I find my Account ID?</summary>

Two common ways:

**In the parcelLab App (recommended)**

* Open <https://app.parcellab.com/service/account/account/>
* Select the account you want to use
* Copy the 7-digit number shown under `ID`

**From an encoded token (optional)**

* If you have an *encoded* token, it can be Base64-decoded into the format:\
  `<account_id>:<token>`

</details>

<details>

<summary>Why am I getting a <code>401</code> Unauthorized error when requesting with my token?</summary>

This is almost always one of these:

* Wrong header format. It must be exactly:\
  `Authorization: Parcellab-API-Token <token>`
* Using `Bearer` instead of `Parcellab-API-Token`
* Copy/paste issues (extra whitespace, surrounding quotes)
* Token scope missing `write` (required for this endpoint)
* Account mismatch: The token belongs to a different account than the `account` you send in the payload

</details>

<details>

<summary>I sent data and got a <code>2xx</code> response, but cannot see my data in the app?</summary>

Check these in order:

* You’re in the right account in the app (account switcher in the top-left)
* The `account` in your payload matches the account you’re viewing
* You’re looking at the right area and filters (orders, timeframe, status, etc.)

If everything matches and it still doesn’t show up, wait a few minutes. Under times of heavy load ingestion can be deferred in favor of critical events.

</details>


---

# Agent Instructions: 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:

```
GET https://docs.parcellab.com/docs/developers/orders/create-orders-trackings.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
