---
updatedAt: 2026-02-18T14:03:43.000Z
agentTools:
  projectIndex: https://developer.xentral.com/llms.txt
---

# Create a sales order

## Contents

* [Overview](#overview)
* [ERP Context](#erp-context)
* [Order Lifecycle](#order-lifecycle)
* [At a Glance](#at-a-glance)
* [Prerequisites](#prerequisites)
* [Before You Start](#before-you-start)
* [Workflow](#workflow)
* [Step-by-Step Guide](#step-by-step-guide)
* [Auto Shipping Control](#auto-shipping-control)
* [Price Matching with setTotalAmount](#price-matching-with-settotalamount)
* [Discount Handling](#discount-handling)
* [Tax Settings](#tax-settings)
* [Data Source Hierarchy](#data-source-hierarchy)
* [Preventing Duplicates](#preventing-duplicates)
* [Error Handling](#error-handling)
* [Related Resources](#related-resources)

***

## Overview

This guide shows you how to create a sales order via the Xentral API. You'll learn which data you need beforehand, how to find it, and how the creation process works.

**Use Cases:**

* Import orders from an online shop (Shopify, WooCommerce, etc.) into Xentral
* Automatically create B2B portal orders
* Synchronize marketplace orders (Amazon, eBay, Kaufland)
* Custom order app for sales representatives

> **New to the Xentral API?** Read first:
>
> * [Authentication](https://developer.xentral.com/reference/authentication) - Create API Token
> * [Rate Limiting](https://developer.xentral.com/reference/rate-limiting) - Request limits
> * [Help Center: Order Management](https://help.xentral.com/hc/en-us/articles/6113604302620-Introduction-to-Order-Management) - General Xentral sales order documentation

***

## ERP Context

> **Important for developers without ERP experience:** A sales order in Xentral is not simply an "order" as you know it from a shop. It's the starting point for many downstream processes.

### What can happen when you create a sales order?

In Xentral, a sales order can potentially trigger:

* **Stock Reservations** - Inventory is reserved (actual bookings happen on the delivery note)
* **Invoice Creation** - Via [auto dispatch](https://developer.xentral.com/reference/salesorderactionsdispatch) or manual trigger (not automatic on order creation)
* **Delivery Note Creation** - Via [auto dispatch](https://developer.xentral.com/reference/salesorderactionsdispatch), not automatic on order creation
* **Statistics** - Revenue, customer history, product statistics
* **Auto Dispatch** - Not automatic! Triggered via [API](https://developer.xentral.com/reference/salesorderactionsdispatch), UI, or cron job

### Why is this important?

> **Important:** The import endpoint creates the sales order **and immediately releases it**. If auto dispatch is enabled (via project settings or cron job), processing may start immediately. Use the `autoShipping: false` parameter if you need to do additional steps before fulfillment.

Understanding this helps you:

* Know which data **must** be present (customer, project, payment method, etc.)
* Know which data **overrides** default values
* Handle **errors** appropriately

***

## Order Lifecycle

A sales order in Xentral follows a defined lifecycle. Understanding these statuses is essential for building reliable integrations — especially when deciding how to handle errors, cancellations, and retries.

### Status Overview

| API Status (V1/V2) | API Status (V3) | Xentral UI (DE) | Xentral UI (EN) | Description                                                                                                                       |
| ------------------ | --------------- | --------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `created`          | `draft`         | Angelegt        | Created         | Draft order. **No document number assigned yet.** Can be edited and deleted freely.                                               |
| `released`         | `released`      | Freigegeben     | Released        | Order is active and has a document number. Stock reservations are active. Ready for dispatch. Cannot be deleted, only canceled.   |
| `completed`        | `completed`     | Abgeschlossen   | Completed       | Fully processed — delivery note and/or invoice have been created. No further changes. Can still be canceled.                      |
| `canceled`         | `cancelled`     | Storniert       | Canceled        | Order is canceled. Remains in the system for traceability. Documents created earlier (invoices, delivery notes) are not affected. |

> **Note on the V1 import endpoint:** The import endpoint (`POST /api/v1/salesOrders/actions/import`) creates orders directly in `released` status — it skips the `created` (draft) phase entirely. The order immediately receives a document number. If you need a draft state where orders can be reviewed before release, use the V3 API.
>
> **Note on spelling:** V1/V2 uses `canceled` (single l), V3 uses `cancelled` (double l). Make sure your integration handles the correct spelling for the API version you use.

### Status Transitions

```
           ┌─────────────┐  Release  ┌─────────────┐ Dispatch  ┌─────────────┐
           │   created   │ ────────▶ │  released   │ ────────▶ │  completed  │
           │  (Angelegt) │           │(Freigegeben)│           │(Abgeschloss.)│
           └──────┬──────┘           └──────┬──────┘           └──────┬──────┘
                  │                         │                         │
            Delete│  Cancel                 │ Cancel                  │ Cancel
                  │                         │                         │
                  ▼                         ▼                         ▼
           ┌──────────┐  ┌──────────────────────────────────────────────────┐
           │ DELETED   │  │              canceled (Storniert)                │
           │(permanent)│  │  Cancellation can be undone in the UI.          │
           └──────────┘  └──────────────────────────────────────────────────┘
```

**Key rules:**

* **Forward only.** Once released, an order cannot go back to `created`. Once completed, it cannot go back to `released`.
* **Cancel from any active status.** Orders in status `created`, `released`, or `completed` can be canceled. (Tested: cancel on `released` returns `204`.)
* **Canceled is final via API.** A canceled order cannot be canceled again (`409 Conflict`). However, cancellation **can be undone in the Xentral UI** (Action menu > "Storno aufheben").
* **Delete only from draft.** Only orders in `created` (draft) status can be deleted. Released or completed orders return `409 Conflict` with: `"Only Sales Order with status draft can be deleted."`
* **Canceling a draft deletes it.** When you cancel a draft order (status `created`), Xentral automatically deletes it instead of marking it as canceled.

### The Order Status Indicator (Ampel)

Before an order can be dispatched, all status indicator lights ("Ampeln") must be green. The indicator checks:

| Indicator          | What it checks                                                                                                                                                                         |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Payment**        | Has payment been received? Payment methods configured as "Rechnung" (invoice) or similar automatically pass this check. Prepayment methods (Vorkasse) block until payment is recorded. |
| **Stock**          | Are all ordered items available in the warehouse?                                                                                                                                      |
| **Address**        | Is the shipping address complete and valid?                                                                                                                                            |
| **Credit limit**   | Is the customer within their credit limit?                                                                                                                                             |
| **Delivery block** | Is there a manual delivery block on the order?                                                                                                                                         |

> **Tip:** If dispatch fails, check the order status indicator in the Xentral UI to see which light is red. See [Help Center: Using the order status indicator](https://help.xentral.com/hc/en-us/articles/6113604302620-Introduction-to-Order-Management).
>
> **Controlling the payment indicator via API:** The payment check is controlled by the payment method type. If your payment method behaves like "Rechnung" (invoice), the payment indicator is automatically green. For prepayment types (PayPal, credit card, etc.), you can either:
>
> * Record a payment in Xentral before dispatching
> * Configure the payment method to behave like "Rechnung" in your project settings
> * Set `"vorab als bezahlt markieren"` (mark as pre-paid) on the order — this can also be passed from the shop

### Cancel vs. Delete

|                        | Cancel                                                           | Delete                                       |
| ---------------------- | ---------------------------------------------------------------- | -------------------------------------------- |
| **Allowed from**       | `created`, `released`, `completed`                               | Only `created` (draft)                       |
| **Result**             | Status changes to `canceled`. Order stays in system.             | Order is **permanently removed**.            |
| **Document number**    | Kept (gap in number sequence)                                    | Freed up (no number was assigned yet)        |
| **Existing documents** | Delivery notes and invoices created earlier are **not affected** | N/A (no documents exist for drafts)          |
| **Reversible?**        | Yes, in Xentral UI ("Storno aufheben")                           | No                                           |
| **API use case**       | Order was released or known to external systems                  | Order was created by mistake, never released |

> **Important:** The V1 import endpoint creates orders directly in `released` status. These orders **cannot be deleted** — they can only be canceled.

### Cancel an Order

```bash
curl -X POST "https://{instance}.xentral.biz/api/v1/salesOrders/{orderId}/actions/cancel" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json"
```

> [API Reference: Cancel Sales Order](https://developer.xentral.com/reference/salesorderactionscancel)

**Response:** `204 No Content` — The order is now canceled.

**Error responses:**

If the order is already canceled:

```json
{
  "type": "https://api.xentral.biz/problems/conflict",
  "title": "Sales order cannot be cancelled.",
  "messages": ["SalesOrder with id 6 could not be processed. Transition to storniert is not valid for this orders current status"]
}
```

Status: `409 Conflict`

### Delete a Draft Order

> **Required Scope:** `salesOrder:delete`

```bash
curl -X DELETE "https://{instance}.xentral.biz/api/v1/salesOrders/{orderId}" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

**Response:** `204 No Content` — The order is permanently removed.

**Error response** (if order is not in draft status):

```json
{
  "type": "https://api.xentral.biz/problems/conflict",
  "title": "Sales order cannot be deleted.",
  "messages": ["SalesOrder with id 8 could not be processed. Only Sales Order with status draft can be deleted."]
}
```

Status: `409 Conflict`

### Dispatch an Order

Dispatching moves an order from `released` to `completed`. During dispatch, items are booked out of the warehouse and documents (delivery note, invoice) are created.

> **Required Scope:** `salesOrder:update`
>
> **Prerequisite:** All order status indicator lights must be green. See [The Order Status Indicator](#the-order-status-indicator-ampel).

```bash
curl -X POST "https://{instance}.xentral.biz/api/v1/salesOrders/{orderId}/actions/dispatch" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"createDocuments": "deliveryNote"}'
```

> [API Reference: Dispatch Sales Order](https://developer.xentral.com/reference/salesorderactionsdispatch)

**Document creation options:**

* `"deliveryNote"` — Create delivery note only
* `"invoice"` — Create invoice only
* `"deliveryNoteAndInvoice"` — Create both

**Response:** `204 No Content` — The order is now completed.

**Common dispatch errors:**

| HTTP | Error                                                                 | Cause                                                                                                                                            |
| ---- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| 400  | `"Sales order needs to be in status released. Dispatching rejected."` | Order is not in `released` status (e.g., already completed or canceled)                                                                          |
| 400  | `"Check payment not passed. Dispatching rejected"`                    | Payment indicator is red. Configure payment method as "Rechnung" type or record payment first.                                                   |
| 400  | `"Check stock not passed. Dispatching rejected"`                      | Stock indicator is red. Not enough inventory for one or more positions.                                                                          |
| 422  | `"Unknown error while trying to dispatch the sales order."`           | Generic error — typically a missing configuration (warehouse, dispatch center, or project settings). Check the order status indicator in the UI. |

> **Note:** Dispatch is **not automatic** by default. It must be triggered via:
>
> * **API:** `POST /api/v1/salesOrders/{id}/actions/dispatch`
> * **Xentral UI:** Action menu > "Auto dispatch: hand over to dispatch center"
> * **Cron job:** Process starter `autoversand_plus` (fully automated) or `autoversand_manuell` (semi-automated via Delivery handover tab)
>
> The `autoShipping` parameter on the order controls whether the cron job will pick up the order. Setting `autoShipping: false` prevents automatic dispatch even if the cron job is running.

### Completing an Order Without Dispatch

An order can also be marked as completed manually without going through the dispatch process. This is useful for service orders or orders that don't require warehouse operations.

In the Xentral UI: Action menu > "Mark as completed"

> **Note:** There is no dedicated API endpoint for manually completing an order. Orders are completed through the dispatch process or manually in the UI.

### Filter Orders by Status

```bash
curl -s "https://{instance}.xentral.biz/api/v1/salesOrders?page[number]=1&page[size]=10&filter[0][key]=status&filter[0][op]=equals&filter[0][value]=released" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: List Sales Orders](https://developer.xentral.com/reference/salesorderlist)

Valid filter values: `created`, `released`, `completed`, `canceled`

### Document Status vs. Order Status

The statuses above (`created`, `released`, `completed`, `canceled`) are the **active order statuses**. These are the only statuses that current Xentral processes set on sales orders.

**About the `sent` status on sales orders:**

The `sent` status on sales orders is set by the [Send Sales Order V3 endpoint](https://developer.xentral.com/reference/salesorderactionsdispatch). When you call this endpoint, the order status transitions to `sent`. While this status is not part of the V2 OpenAPI specification, it is actively used in the V3 API workflow.

> **Note:** If you encounter `sent` on older sales orders, it may also be legacy data from a previous system version. For new integrations using V3, the Send endpoint is the standard way to mark an order as sent.

**Documents have their own status lifecycle.** Business documents created from the order (delivery note, invoice) **do** actively use the `sent` status:

| Document Status | German    | Description                                                                                                                                                                                            |
| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `created`       | Erstellt  | Document has been generated but not yet sent to the customer.                                                                                                                                          |
| `sent`          | Versendet | Document has been transmitted to the customer — via the [Send endpoint](https://developer.xentral.com/reference/salesorderactionsdispatch), email in auto-dispatch, or printed at the packing station. |

> **Note:** Automatic processes like logistics (auto-dispatch, packing station printing) can also set the `sent` status on documents. For a full overview of document statuses and transitions, see the Business Documents Lifecycle guide (planned).

### V1 Import vs. V3 Create

| Aspect                    | V1 Import                                       | V3 Create                                              |
| ------------------------- | ----------------------------------------------- | ------------------------------------------------------ |
| **Endpoint**              | `POST /api/v1/salesOrders/actions/import`       | `POST /api/v3/salesOrders`                             |
| **Initial status**        | `released` (immediately, with document number)  | `draft` (no document number yet)                       |
| **Separate release step** | No (automatic)                                  | Yes (`PATCH /api/v3/salesOrders/{id}/actions/release`) |
| **Can be deleted**        | No (already released)                           | Yes (while in `draft`)                                 |
| **Use case**              | Shop imports where orders are already confirmed | Workflows where orders need review before release      |

***

## At a Glance

|                    |                                                                                        |
| ------------------ | -------------------------------------------------------------------------------------- |
| **Endpoint**       | `POST /api/v1/salesOrders/actions/import`                                              |
| **Method**         | POST                                                                                   |
| **Auth**           | Bearer Token ([Documentation](https://developer.xentral.com/reference/authentication)) |
| **Required Scope** | `salesOrder:create`                                                                    |

```bash
curl -X POST "https://{instance}.xentral.biz/api/v1/salesOrders/actions/import" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-01-28",
    "customer": {"id": "4"},
    "project": {"id": "1"},
    "financials": {
      "paymentMethod": {"id": "8"},
      "currency": "EUR"
    },
    "delivery": {
      "shippingMethod": {"id": "1"},
      "autoShipping": false
    },
    "positions": [{
      "product": {"id": "1"},
      "quantity": 2,
      "price": {"amount": "19.99", "currency": "EUR"}
    }]
  }'
```

**Response:** `201 Created` - The new order ID is in the `Location` header (e.g., `/api/v1/salesOrders/2`).

> [Full API Reference: Import Sales Order](https://developer.xentral.com/reference/salesorderimport)

***

## Prerequisites

* [ ] Xentral account with API access
* [ ] Personal Access Token (PAT) with scope `salesOrder:create` ([Guide](https://developer.xentral.com/reference/authentication))
* [ ] At least one **customer** in the system (or permission to create)
* [ ] At least one **project** in the system (projects **cannot** be created via API!)
* [ ] At least one **payment method** configured (can be listed via API, but **cannot** be created via API)
* [ ] At least one **shipping method** configured (can be listed and created via API)
* [ ] At least one **product** in the system (or permission to create)

***

## Before You Start

### Decision 1: One-time buyers or regular customers?

**B2C / One-time buyers (e.g., Amazon, eBay):**

* Customers will likely only order once
* You can specify all addresses directly in the order
* Customer master data doesn't need to be perfectly maintained
* Recommendation: Check if customer exists, if not → create, pass addresses in order

**B2B / Regular customers:**

* Same customers order regularly
* Clean master data is important (delivery addresses, payment terms)
* Recommendation: Store customer mapping in your own database/middleware
* Maintain addresses in customer master data, not in every order

### Decision 2: Prices from Xentral or from the shop?

**Option A: Xentral calculates the price**

* You don't specify a price in the position
* Xentral uses the stored sales price (possibly customer-specific)
* Advantage: Consistent prices
* Disadvantage: Possible deviations from shop

**Option B: Use shop price (recommended)**

* You explicitly specify the price in the position
* The shop price is taken 1:1
* Advantage: No price deviations
* Disadvantage: You must always provide the price

> **Important:** If the customer purchased something with a confirmed price in the shop, that price **MUST** be used. Otherwise, payment matching (Zahlungseingang) will fail and DATEV amounts will be incorrect.

### Decision 3: Cache payment methods and shipping methods?

**Check once (recommended for fixed integrations):**

* Payment methods and shipping methods rarely change
* Query IDs once and store in your integration
* Use stored ID for each order
* Fewer API calls, faster processing
* Could be refreshed once a day

**Check every time (for dynamic scenarios):**

* If payment methods/shipping methods change frequently
* If you serve different Xentral instances
* More API calls, potential rate limit issues, slower performance

> **Best Practice:** Store payment methods and shipping methods in a mapping table: `{"paypal": "8", "dhl": "1"}`. This saves 2 API calls per order.

***

## Workflow

```
┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  1. Check   │ ──▶ │  2. Find    │ ──▶ │ 3. Payment/ │ ──▶ │ 4. Check    │ ──▶ │  5. Create  │
│  Customer   │     │   Project   │     │  Shipping   │     │  Products   │     │    Order    │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘
       │                                       │                   │
       ▼                                       ▼                   ▼
┌─────────────┐                         ┌─────────────┐     ┌─────────────┐
│ Not found?  │                         │   Cache!    │     │ Not found?  │
│  Create!    │                         │             │     │  Create!    │
└─────────────┘                         └─────────────┘     └─────────────┘
```

***

## Step-by-Step Guide

### Step 1: Check/Find Customer

Before creating an order, you need the **customer ID**. The API is completely ID-based.

**Search customer (V2 API):**

> **Required Scope:** `customer:read`

```bash
curl -s "https://{instance}.xentral.biz/api/v2/customers?filter[0][key]=name&filter[0][op]=equals&filter[0][value]=Max%20Mustermann" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> **Note:** The V2 filter syntax requires `key`, `op`, and `value` parameters. For customers, only the `equals` operator is supported for the `name` field.
>
> [API Reference: List Customers](https://developer.xentral.com/reference/customerlistv2)

**Response:**

```json
{
  "data": [{
    "id": "4",
    "number": "10000",
    "customerType": "person",
    "name": "Max Mustermann",
    "firstname": "Max",
    "lastname": "Mustermann"
  }],
  "extra": {"page": {"number": 1, "size": 10}, "totalCount": 1}
}
```

***

### Step 2: Create Customer (if not found)

If the customer doesn't exist, you need to create them first.

**Request (V2 API):**

> **Required Scope:** `customer:create`

```bash
curl -s -X POST "https://{instance}.xentral.biz/api/v2/customers" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "customerType": "person",
    "firstname": "Max",
    "lastname": "Mustermann"
  }'
```

> [API Reference: Create Customer](https://developer.xentral.com/reference/customercreatev2)

**Response:** `201 Created` - No body, customer ID is in the `Location` header.

> **Note:** For `customerType: "person"`, `firstname` and `lastname` are required. For `customerType: "company"`, `name` is required.

**Add addresses separately (V2):**

> **Required Scope:** `customer:create`

```bash
curl -s -X POST "https://{instance}.xentral.biz/api/v2/customers/{customerId}/addresses" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "deliveryaddress",
    "name": "Max Mustermann",
    "street": "Musterstraße 1",
    "zip": "10115",
    "city": "Berlin",
    "country": "DE"
  }'
```

> [API Reference: Create Customer Address](https://developer.xentral.com/reference/customeraddresscreatev2)
>
> **Address types:** `masterdata` (master data), `billingaddress` (invoice), `deliveryaddress` (shipping)

***

### Step 3: Find Project

Projects control important process settings (warehouse processes, number ranges, etc.). You **cannot create projects via API** - they must exist in Xentral.

**List projects (V1):**

> **Note:** This endpoint has no scope requirements.

```bash
curl -s "https://{instance}.xentral.biz/api/v1/projects" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: List Projects](https://developer.xentral.com/reference/projectlist)

**Response:**

```json
{
  "data": [{
    "id": "1",
    "name": "Standard Project",
    "keyName": "STANDARD",
    "currency": "EUR",
    "normalTaxRate": 19,
    "reducedTaxRate": 7
  }],
  "extra": {"page": {"number": 1, "size": 10}, "totalCount": 1}
}
```

> **Why specify the project?** In the UI, the project is automatically pulled from the customer. Via API it's intentionally different: Depending on the sales channel (Shopify vs. eBay vs. B2B portal), you might need different logistics processes → different projects.

***

### Step 4: Find Payment Method

**List payment methods (V1):**

> **Note:** This endpoint has no scope requirements.

```bash
curl -s "https://{instance}.xentral.biz/api/v1/paymentMethods" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: List Payment Methods](https://developer.xentral.com/reference/paymentmethodlist)

**Response:**

```json
{
  "data": [
    {"id": "8", "type": "paypal", "designation": "Paypal"},
    {"id": "9", "type": "bar", "designation": "Cash"},
    {"id": "10", "type": "lastschrift", "designation": "Direct Debit"}
  ],
  "extra": {"page": {"number": 1, "size": 10}, "totalCount": 14}
}
```

> **Why specify this?** The same customer can pay with PayPal once, by invoice another time. This information comes from the shop - Xentral can't guess it.

***

### Step 5: Find Shipping Method

**List shipping methods (V1):**

> **Note:** This endpoint has no scope requirements.

```bash
curl -s "https://{instance}.xentral.biz/api/v1/shippingMethods" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: List Shipping Methods](https://developer.xentral.com/reference/shippingmethodlist)

**Response:**

```json
{
  "data": [
    {"id": "1", "designation": "DHL", "type": "DHL"},
    {"id": "3", "designation": "DPD", "type": "DPD"},
    {"id": "6", "designation": "GLS", "type": "gls"}
  ],
  "extra": {"page": {"number": 1, "size": 10}, "totalCount": 11}
}
```

***

### Step 6: Check Product

Before creating the order, ensure all products exist in Xentral.

**Search product (V2 API):**

> **Required Scope:** `product:read`

```bash
curl -s "https://{instance}.xentral.biz/api/v2/products?filter[0][key]=number&filter[0][op]=equals&filter[0][value]=1000039" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: List Products](https://developer.xentral.com/reference/productlistv2)

**Search alternatives:**

* By product number: `filter[0][key]=number&filter[0][op]=equals&filter[0][value]=1000039`
* By name (contains): `filter[0][key]=name&filter[0][op]=contains&filter[0][value]=Kaffee`
* By EAN: `filter[0][key]=ean&filter[0][op]=equals&filter[0][value]=4260123456789`

**If product not found:**

> **Required Scope:** `product:create`

```bash
curl -s -X POST "https://{instance}.xentral.biz/api/v2/products" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "number": "NEW-001",
    "name": "New Product",
    "project": {"id": "1"},
    "salesPrice": {"amount": "19.99", "currency": "EUR"}
  }'
```

> [API Reference: Create Product](https://developer.xentral.com/reference/productcreatev2)
>
> **Best Practice:** Like with customers - store the mapping between shop product number and Xentral ID in your middleware. This saves API calls per order.

***

### Step 7: Create Order

Now you have all IDs and can create the order.

**With explicit price and external order number (recommended):**

```bash
curl -s -X POST "https://{instance}.xentral.biz/api/v1/salesOrders/actions/import" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-01-28",
    "externalOrderNumber": "SHOP-12345",
    "customer": {"id": "4"},
    "project": {"id": "1"},
    "financials": {
      "paymentMethod": {"id": "8"},
      "currency": "EUR"
    },
    "delivery": {
      "shippingMethod": {"id": "1"},
      "autoShipping": false
    },
    "positions": [{
      "product": {"id": "1"},
      "quantity": 2,
      "price": {"amount": "19.99", "currency": "EUR"}
    }]
  }'
```

> [API Reference: Import Sales Order](https://developer.xentral.com/reference/salesorderimport)
>
> **Important:**
>
> * Without a price, Xentral calculates from product master data - if no price exists there, import fails!
> * The order ID is returned in the `Location` response header
> * The order is immediately in status `released` (see [Order Lifecycle](#order-lifecycle))

**Response:** `201 Created`

The order ID is in the `Location` header:

```
Location: https://{instance}.xentral.biz/api/v1/salesOrders/2
```

***

### Step 8: Validate Order (optional)

> **Required Scope:** `salesOrder:read`

```bash
curl -s "https://{instance}.xentral.biz/api/v1/salesOrders/2" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: Get Sales Order](https://developer.xentral.com/reference/salesorderview)

**Response (shortened):**

```json
{
  "data": {
    "id": "2",
    "documentNumber": "200002",
    "externalOrderNumber": "SHOP-12345",
    "date": "2026-01-28",
    "status": "released",
    "customer": {"id": "4", "number": "10000"},
    "netSales": {"amount": "39.98", "currency": "EUR"},
    "total": {"amount": "47.58", "currency": "EUR"}
  }
}
```

> **Tip:** Check the `status` field to confirm the order was created successfully. After import, it should be `released`. See [Order Lifecycle](#order-lifecycle) for all possible statuses and transitions.

***

## Auto Shipping Control

The import endpoint creates the order **and immediately releases it**. If you need to do additional processing before fulfillment, disable auto shipping:

```json
{
  "delivery": {
    "shippingMethod": {"id": "1"},
    "autoShipping": false
  }
}
```

**Multi-step workflow example:**

1. Create the sales order with `autoShipping: false`
2. Do calculations, determine correct warehouse or shipping method, prepare purchase orders...
3. Update the order via PATCH to set final values
4. Activate auto shipping via API or let cron job pick it up

**Control document creation:**

```json
{
  "autoCreateDocuments": "deliveryNote"
}
```

Allowed values:

* `"deliveryNote"` - Create delivery note only
* `"invoice"` - Create invoice only
* `"deliveryNote+invoice"` - Create both

> **Note:** If you want to prevent automatic document creation, simply **omit this parameter** entirely. The field is optional and defaults to no automatic creation.

***

## Price Matching with setTotalAmount

When using **auto dispatch**, Xentral needs to match calculated prices with external prices for payment reconciliation and DATEV.

**The problem:**

* Your shop calculates with gross prices
* Xentral calculates with net prices
* Different rounding can cause cent differences
* Payment matching (Zahlungseingang) will fail if amounts don't match

**The solution - `setTotalAmount`:**

```json
{
  "date": "2026-01-28",
  "customer": {"id": "4"},
  "project": {"id": "1"},
  "financials": {
    "paymentMethod": {"id": "8"},
    "currency": "EUR"
  },
  "positions": [...],
  "setTotalAmount": {
    "isActive": true,
    "maximumDifferenceToCalculatedSum": 0.05,
    "totalGrossAmountFromExternal": 47.58
  }
}
```

> **Important:** `setTotalAmount` only sets the total amount for the **order**, not for individual positions. It's used for:
>
> * Payment matching (Zahlungseingang)
> * Correct amounts for DATEV export

**Fields:**

| Field                              | Type    | Description                                                                        |
| ---------------------------------- | ------- | ---------------------------------------------------------------------------------- |
| `isActive`                         | boolean | Enables the setTotalAmount logic. If set to `false`, this entire block is ignored. |
| `maximumDifferenceToCalculatedSum` | float   | Maximum allowed difference in EUR (e.g., `0.05` = 5 cents)                         |
| `totalGrossAmountFromExternal`     | float   | Gross total from the shop                                                          |

***

## Discount Handling

Xentral supports two types of discounts:

### 1. Line Item Discount

Apply a percentage discount to a specific position:

```json
"positions": [{
  "product": {"id": "1"},
  "quantity": 2,
  "price": {"amount": "19.99", "currency": "EUR"},
  "discount": 0.15
}]
```

This applies 15% discount to this line item only.

### 2. Discount Position (Order-level)

For order-wide discounts, use `discountPositions`:

```json
{
  "positions": [
    {"product": {"id": "1"}, "quantity": 2, "price": {"amount": "19.99", "currency": "EUR"}},
    {"product": {"id": "2"}, "quantity": 1, "price": {"amount": "29.99", "currency": "EUR"}}
  ],
  "discountPositions": [{
    "product": {"id": "99"},
    "discount": 0.10
  }]
}
```

> **Note:** Discount products must be configured in Xentral as discount articles. They cannot be added as regular positions.

For detailed information on how Xentral handles discounts, see the [Help Center](https://help.xentral.com/).

***

## Tax Settings

By default, VAT settings are taken from the product. You can override this per position.

> **Note:** If you define tax as `normal` or `reduced`, Xentral applies the tax rates configured in the **Lieferschwellen** (delivery thresholds) and **Steuersätze** (tax rates) modules. Make sure these are properly configured in your Xentral instance.

**Using VAT category:**

```json
"positions": [{
  "product": {"id": "1"},
  "quantity": 2,
  "tax": {
    "vatCategory": "reduced"
  }
}]
```

Categories: `normal`, `reduced`, `taxfree`

**Using custom rate:**

```json
"positions": [{
  "product": {"id": "1"},
  "quantity": 2,
  "tax": {
    "rate": 7.0,
    "taxText": "7% VAT"
  }
}]
```

> **Use case:** When selling in different countries with different tax rules, or when the same product has different taxation depending on context (e.g., food for takeaway vs. dine-in).

***

## Data Source Hierarchy

Xentral uses a fallback system. Values in your request always win:

### Addresses

1. **Request** (if provided) → used
2. **Customer** (if nothing in request) → Billing/Shipping address from master data
3. **Default** → Master data address

> **Important for delivery addresses:** Xentral only uses the delivery address marked as "default". If no address has this flag, none is used - even if the customer has 10 delivery addresses!

### Payment Terms

1. **Request** → `paymentTerms` in request
2. **Customer** → Payment terms in master data
3. **Payment Method** → Default of payment method
4. **System Settings** → System-wide defaults

***

## Preventing Duplicates

In integrations, an order may be sent multiple times (network errors, retry logic, etc.). Use the **external order number** to prevent duplicates.

### externalOrderNumber

```json
{
  "externalOrderNumber": "SHOP-12345",
  "date": "2026-01-28",
  "customer": {"id": "4"},
  ...
}
```

**Benefits:**

* Unique mapping between shop order and Xentral order
* You can check before import if the order already exists
* Easy troubleshooting: "Which Xentral order belongs to shop order X?"

**Check before import:**

```bash
curl -s "https://{instance}.xentral.biz/api/v1/salesOrders?filter[0][key]=externalOrderNumber&filter[0][op]=equals&filter[0][value]=SHOP-12345" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

> [API Reference: List Sales Orders](https://developer.xentral.com/reference/salesorderlist)

If `totalCount > 0` → Order already exists, don't create again.

### Best Practice for High Volume

For many orders per day (>100):

| Strategy                     | Recommendation                              |
| ---------------------------- | ------------------------------------------- |
| **Customer IDs**             | Cache in middleware/database                |
| **Product IDs**              | Cache in middleware/database                |
| **Payment/Shipping methods** | Query once, store statically, refresh daily |
| **Duplicate check**          | Always set `externalOrderNumber`            |

This reduces API calls per order from \~6 to 1-2.

***

## Error Handling

| Status | Meaning           | Common Cause                                                                              |
| ------ | ----------------- | ----------------------------------------------------------------------------------------- |
| 400    | Bad Request       | Invalid JSON or validation error (missing required fields)                                |
| 401    | Unauthorized      | Invalid or expired token                                                                  |
| 403    | Forbidden         | Missing required scope (e.g., `salesOrder:create`)                                        |
| 404    | Not Found         | Invalid URL or resource ID doesn't exist                                                  |
| 409    | Conflict          | Action not allowed on resource in current state (see [Order Lifecycle](#order-lifecycle)) |
| 429    | Too Many Requests | Rate limit exceeded                                                                       |

> **Note:** Validation errors return `400 Bad Request`, not `422`. The `409 Conflict` error occurs when performing an action that is not valid for the current order status — for example, deleting a released order or canceling an already canceled order.

**Rate Limiting Best Practice:**

Monitor the `X-RateLimit-Remaining` header to avoid hitting limits:

| Remaining | Recommended Action                                |
| --------- | ------------------------------------------------- |
| 100-50    | Full speed (no delay)                             |
| 50-25     | Add a small delay (e.g., 50ms) between requests   |
| < 25      | Add a larger delay (e.g., 200ms) between requests |

> **Note:** These are recommendations. Adjust delay values based on your specific rate limit and use case.

This way you'll never hit the rate limit while maximizing throughput.

***

## Related Resources

### API Documentation

* [salesorderimport](https://developer.xentral.com/reference/salesorderimport) - Import/Create Sales Order
* [salesorderlist](https://developer.xentral.com/reference/salesorderlist) - List Sales Orders
* [salesorderview](https://developer.xentral.com/reference/salesorderview) - View Sales Order
* [salesorderactionscancel](https://developer.xentral.com/reference/salesorderactionscancel) - Cancel Sales Order
* [salesorderactionsdispatch](https://developer.xentral.com/reference/salesorderactionsdispatch) - Dispatch Sales Order
* [customerlistv2](https://developer.xentral.com/reference/customerlistv2) - List Customers
* [customercreatev2](https://developer.xentral.com/reference/customercreatev2) - Create Customer
* [customeraddresscreatev2](https://developer.xentral.com/reference/customeraddresscreatev2) - Create Customer Address
* [projectlist](https://developer.xentral.com/reference/projectlist) - List Projects
* [paymentmethodlist](https://developer.xentral.com/reference/paymentmethodlist) - List Payment Methods
* [shippingmethodlist](https://developer.xentral.com/reference/shippingmethodlist) - List Shipping Methods
* [productlistv2](https://developer.xentral.com/reference/productlistv2) - List Products
* [productcreatev2](https://developer.xentral.com/reference/productcreatev2) - Create Product
* [Authentication](https://developer.xentral.com/reference/authentication)
* [Rate Limiting](https://developer.xentral.com/reference/rate-limiting)

### Help Center

* [Introduction to Order Management](https://help.xentral.com/hc/en-us/articles/6113604302620-Introduction-to-Order-Management) - Order lifecycle, statuses, and creation methods
* [Steps for manual sales order processing](https://help.xentral.com/hc/en-us/articles/5355802990236) - Cancel, copy, dispatch, and more
* [Transferring sales orders to logistics (Auto-shipping)](https://help.xentral.com/hc/en-us/articles/5697692402204) - Dispatch center and automation
* [Using the order status indicator](https://help.xentral.com/) - Traffic light system for dispatch readiness
* [Sales Price Determination](https://help.xentral.com/)
* [Discount Handling](https://help.xentral.com/)

### Related Guides

* [G2: Create Customer](./G2_create-customer.md) - Create customers for orders
* [G3: Create Product](./G3_create-product.md) - Create products for order positions