Fulfillment
From dispatched sales order to shipment
V3 Delivery Notes Available
Delivery note endpoints are available in both V1 and V3. This guide uses V3 for delivery notes (richer responses, includes support) and V1 for shipments. See the V3 Delivery Notes documentation for details.
Contents
- Overview
- ERP Context: How Fulfillment Works in Xentral
- Endpoints Overview
- Prerequisites
- Before You Start
- Fulfillment Workflow
- Step 1: Listen for Dispatched Orders
- Step 2: Fetch the Sales Order
- Step 3: Get Delivery Note
- Step 4: Assign Quality Control Attributes
- Step 5: Create Tracking
- Step 6: Retrieve Shipment Details and Labels
- Download Delivery Note as PDF
- Common Integration Patterns
- Error Handling
- Related Resources
Overview
This guide walks you through the fulfillment process in Xentral from the perspective of an external fulfiller: listening for dispatched orders, fetching delivery notes, attaching tracking information, and retrieving shipping labels. The fulfiller does not dispatch orders — Xentral handles dispatch internally (either manually by warehouse staff or via auto-dispatch). The fulfiller reacts to the salesOrder.dispatched webhook event and takes over from there.
Use Cases:
- React to dispatched orders and fulfill them externally (3PL, own warehouse system)
- Sync tracking numbers from your carrier back to Xentral
- Build a fulfillment dashboard showing order-to-shipment progress
New to the Xentral API? Read first:
- Authentication - Create API Token
- Rate Limiting - Request limits
ERP Context: How Fulfillment Works in Xentral
Important for developers without ERP experience: Fulfillment in an ERP is not just "mark as shipped." It is a multi-step process that creates business documents, triggers stock movements, and generates accounting entries.
The fulfillment chain
In a shop system, you might just set order.status = "shipped" and send a tracking email. In Xentral, fulfillment is a chain of business events:
- Sales Order (Auftrag) - The starting point. Must be in status
releasedbefore it can be dispatched. - Dispatch (Versand auslösen) - Triggers Xentral's internal fulfillment workflow. This can create a delivery note AND an invoice, according to project settings. Dispatch validates against the "Auftragsampel" (sales order traffic lights) -- a set of configurable rules that check stock, address, payment, and other conditions.
- Delivery Note (Lieferschein) - The warehouse document. Lists what to pick, pack, and ship.
- Shipment (Sendung) - Tracking information attached to a delivery note. Contains carrier, tracking number, and optionally a shipping label.
What happens when an order is dispatched
When dispatch is triggered (by warehouse staff, auto-dispatch rules, or API), Xentral:
- Validates the order against the Auftragsampel (traffic lights)
- Books out stock from the warehouse depending on project settings (reservation happens earlier, on the sales order itself)
- Creates a delivery note with all line items
- Optionally creates an invoice (depending on project settings and
autoCreateDocuments)
Key Insight: The fulfiller does NOT dispatch orders. Dispatch is an internal Xentral process. The fulfiller listens for the
salesOrder.dispatchedordeliveryNote.createdwebhook event and starts fulfillment from there. After dispatch, the sales order is in statuscompleted.
One order, one delivery note
In Xentral's fulfillment model, partial deliveries are handled before dispatch by splitting the sales order into multiple sales orders. Each sales order then produces one delivery note. This means:
- After dispatch, expect a 1:1 relationship between sales order and delivery note
- If items need to ship separately, the order is split into multiple orders before dispatch
- Your integration should still verify this by querying delivery notes for the sales order ID
Endpoints Overview
| Step | Endpoint | Method | Purpose |
|---|---|---|---|
| Listen for events | Xentral Webhooks | - | Receive salesOrder.dispatched events |
| Fetch sales order | /api/v1/salesOrders/{id} | GET | Get order details (needed for export shipments) |
| Get delivery note | /api/v3/deliveryNotes/{id} | GET | Full delivery note with line items and includes |
| List delivery notes | /api/v3/deliveryNotes | GET | Query delivery notes (page-based, only released+) |
| Delivery note PDF | /api/v3/deliveryNotes/{id} | GET | Download as PDF document |
| Create tracking | /api/v1/shipments | POST | Attach tracking info to delivery note |
| Shipment details | /api/v1/shipments/{id} | GET | Tracking, label, additional packages |
| List shipments | /api/v1/shipments | GET | Query all shipments |
Prerequisites
- Xentral account with API access
- Personal Access Token (PAT) with required scopes:
delivery:read- Read delivery notes and shipment detailsshipment:create- Create shipment tracking
- Webhooks configured for
salesOrder.dispatchedevents (Settings > Webhooks in Xentral) - At least one sales order ready for dispatch
Scope note: Verify the exact scope names in your Xentral instance. Scope naming may vary -- check the API Reference for current requirements.
Before You Start
Decision 1: Who creates the shipping label?
This is the most important architectural decision for your integration.
Option A: Your system creates the label (Fulfiller generates label externally)
- You generate labels via your own carrier API or a 3PL provider
- You push the tracking number back to Xentral via
POST /api/v1/shipments - Best for: 3PL fulfillment, shops with existing carrier contracts, multi-channel sellers
- Label timing is flexible -- generate the label when it makes sense in your fulfillment process
Option B (Plan B): Xentral creates the label
- Xentral can generate labels via integrated carrier modules (DHL, DPD, GLS, etc.)
- You retrieve the label via
GET /api/v1/shipments/{id}(Base64-encoded) - Best for: Teams that manage shipping entirely within Xentral
- Not all carriers support pre-generating labels
Most common pattern: Option A. External fulfillers typically have their own carrier contracts and shipping workflows. They push tracking numbers to Xentral to keep the ERP in sync.
Decision 2: How to detect dispatched orders
Webhooks (recommended): Configure Xentral Webhooks to receive salesOrder.dispatched events. This is the primary trigger for your fulfillment workflow. Low latency, event-driven, no wasted API calls.
Polling (fallback/reconciliation): Query GET /api/v1/shipments periodically to find delivery notes that need tracking. Use this as a safety net to catch any events your webhook listener may have missed -- not as the primary trigger.
Recommendation: Use webhooks as the primary trigger and polling as a reconciliation mechanism. Configure webhooks in Xentral under Settings > Webhooks. The key event to listen for:
salesOrder.dispatched(shown as "Autoversand ausgefuehrt" in German UI) -- Order has been dispatched ordeliveryNote.created, delivery note created
Pagination
V3 endpoints use page-based pagination with page and perPage:
?page=1&perPage=25
Default perPage is 15. The response includes meta with currentPage, from, to, and perPage.
V3 filters use the same deepObject format as V1:
?filter[0][key]=salesOrder.id&filter[0][op]=equals&filter[0][value]=16
See the API documentation for available filter keys and operators.
Important: The V3 delivery notes list only returns delivery notes in status
releasedor later. Delivery notes indraftstatus are not included in default list results -- use the detail endpoint with a known ID to access draft delivery notes or filter for statusdraftexplicitly
V1 endpoints (shipments) use page-based pagination:
?page[number]=1&page[size]=10
| Parameter | Type | Range | Default |
|---|---|---|---|
page[number] | integer | >= 1 | 1 |
page[size] | integer | 10 - 50 | 10 |
Fulfillment Workflow
Xentral (internal) Fulfiller (external)
------------------ --------------------
Sales Order (released)
|
Auto-dispatch or
manual dispatch
|
V
Delivery Note -- Webhook: salesOrder.dispatched --> Receive event
(released) |
Fetch SO + DN
|
Pick & Pack
|
Generate Label
(external carrier)
|
POST tracking --> Xentral
|
Tracking synced to shop
Note on delivery note status: The delivery note status (
released,sent,canceled) is a document communication status, not a shipping status.sentmeans the PDF was sent to the customer (e.g., via email or printed at the packing station). It does not mean the physical package has been shipped. Whether this status is set depends on the project's dispatching configuration. Xentral does not have a dedicated shipping status -- use the shipment endpoint to track whether tracking information has been attached.
Step 1: Listen for Dispatched Orders
Configure a webhook to receive salesOrder.dispatched events from Xentral. When an order is dispatched, Xentral sends an event payload containing the sales order ID.
Webhook configuration: Set up in Xentral under Settings > Webhooks. Register your endpoint URL and subscribe to the salesOrder.dispatched event (shown as "Autoversand ausgefuehrt" in German UI).
Example event payload:
{
"event": "salesOrder.dispatched",
"data": {
"salesOrderId": "7"
}
}Fallback: Polling for shipments
If webhooks are not available, poll the shipments endpoint to find delivery notes that need tracking:
curl -X GET "https://{instance}.xentral.biz/api/v1/shipments?page%5Bnumber%5D=1&page%5Bsize%5D=50" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Use this as a reconciliation mechanism, not as the primary trigger.
Step 2: Fetch the Sales Order
After receiving the dispatched event, fetch the sales order. You need the sales order details for export shipments (customs data, destination country) and to find the associated delivery note. The sales order also contains the shop's order number (externalOrderNumber), which you need to map back to your system.
Request:
curl -X GET "https://{instance}.xentral.biz/api/v1/salesOrders/{salesOrderId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: View Sales Order
From the sales order response, extract:
externalOrderNumber-- the shop's order number (e.g., Shopify order ID)- Customer and shipping address information
- Line items and quantities
- The sales order ID to query delivery notes in the next step
Note:
externalOrderNumberon the sales order is the shop order reference. Do not confuse this withcustomerOrderNumberon the delivery note, which is a B2B field for the customer's own purchase order number.
Step 3: Get Delivery Note
Retrieve the delivery note for the dispatched sales order. On the V3 API, the list and detail endpoints return the same data structure, so you can use either approach.
Option A: Query by sales order ID (when you only have the SO ID)
curl -X GET "https://{instance}.xentral.biz/api/v3/deliveryNotes?filter%5B0%5D%5Bkey%5D=salesOrder.id&filter%5B0%5D%5Bop%5D=equals&filter%5B0%5D%5Bvalue%5D={salesOrderId}&include%5B0%5D=lineItems&include%5B1%5D=lineItems.product" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Option B: Get by ID (when you already know the delivery note ID)
curl -X GET "https://{instance}.xentral.biz/api/v3/deliveryNotes/{deliveryNoteId}?include%5B0%5D=lineItems&include%5B1%5D=lineItems.product" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: List Delivery Notes V3 | View Delivery Note V3
Use the include query parameter to fetch related entities in a single request:
?include[0]=lineItems&include[1]=project&include[2]=lineItems.product
Available includes: lineItems, project, address, lineItems.product, tags, activity, lineItems.customFields.
The lineItems include returns desiredQualityControlAttributes (batch, bestBeforeDate) for each line item -- useful for QC workflows (Step 4).
Important: The V3 list only returns delivery notes in status
releasedor later, for statusdraftyou need to filter explicitly. In a dispatch-triggered workflow, delivery notes are typically already released when you query them.
Key fields in the response
| Field | Description |
|---|---|
salesOrder.id | Links back to the originating sales order |
documentNumber | The delivery note number (assigned on release) |
status | Current status: released, sent, canceled |
shippingMethod.id | Which carrier/shipping method is assigned |
effectiveAddresses.shipTo | Full shipping address for this delivery |
lineItems[].quantity | How many units to ship |
lineItems[].deliveredQuantity | How many units have been shipped so far |
lineItems[].desiredQualityControlAttributes | Batch, BBD, serial requirements |
Step 4: Assign Quality Control Attributes
Before shipping, you may need to assign quality control (QC) attributes to the delivery note. QC attributes track batch numbers, best-before dates (BBD), serial numbers, and other item-specific data that must be recorded for compliance or traceability.
This step is relevant when:
- Products have batch tracking enabled
- Products require serial numbers
- Products have best-before dates (BBD)
- Your warehouse process includes a QC check before packing
Note: QC attribute assignment depends on your Xentral product configuration. If your products do not use batch/BBD/serial tracking, you can skip this step. See Update Stock for details on stock tracking modes.
Important: A delivery note must remain in
releasedstatus while quality control attributes are being assigned.
Step 5: Create Tracking
After picking and packing, attach tracking information to the delivery note. This tells Xentral "this delivery note has been shipped with this tracking number."
Request:
curl -X POST "https://{instance}.xentral.biz/api/v1/shipments" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"type": "deliveryNote",
"deliveryNote": {"id": "{deliveryNoteId}"},
"shippingMethod": {"id": "1"},
"trackingNumber": "00340434161094015902",
"trackingLink": "https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?piececode=00340434161094015902",
"sendTrackingMail": true
}'API Reference: Create Tracking
Response: 204 No Content
The shipment is created but no body is returned. To get the shipment ID, query shipments for the delivery note.
Important:
shippingMethod.idis required if the delivery note does not already have a shipping method assigned. If the DN has a shipping method (e.g., from the sales order), you can omit it. Without it, you get a 400 error: "ShippingMethodEntity for IDs type() was not found".
Commonly used optional fields:
| Field | Description |
|---|---|
sendTrackingMail | If true, Xentral sends the tracking email to the customer. Optional but often desired. |
updateDeliveryNoteShippingMethod | Overwrites the shipping method on the delivery note level. Useful when the actual carrier differs from the one on the order. |
For the full list of request fields (parcel count, weight, sentAt, etc.), see the API documentation.
Minimal example -- just mark as shipped without tracking:
{
"type": "deliveryNote",
"deliveryNote": {"id": "1"},
"sentAt": "2026-03-04T10:00:00+00:00"
}What happens after creating tracking
When you create a shipment with a tracking number:
- Xentral records the tracking information on the delivery note
- If a shop integration is configured, the tracking info is automatically pushed to your shop system (Shopify, WooCommerce, etc.)
- The customer receives a tracking email (if
sendTrackingMailistrueor enabled in project settings)
Querying shipments for a delivery note
After creating a shipment, retrieve it via the delivery note:
curl -X GET "https://{instance}.xentral.biz/api/v1/deliveryNotes/{deliveryNoteId}/shipments?page%5Bnumber%5D=1&page%5Bsize%5D=10" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Step 6: Retrieve Shipment Details and Labels
Get full shipment details including the shipping label (if generated by Xentral).
Request:
curl -X GET "https://{instance}.xentral.biz/api/v1/shipments/{shipmentId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: View Shipment
Response:
{
"data": {
"id": "1",
"tracking": {
"number": "00340434161094015902",
"link": "https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?piececode=00340434161094015902",
"carrier": "DHL"
},
"deliveryNote": {"id": "1"},
"salesOrder": {"id": "7"},
"shippingMethod": {"id": "1"},
"sentAt": "2026-03-04",
"sentAtTimestamp": "2026-03-04 10:00:00",
"label": {
"fileType": "image/gif",
"fileContent": "R0lGODlhAQABAIAAAP///wAAACH5BAE..."
},
"additionalPackages": [
{
"id": "1",
"trackingNumber": "00340434161094015903",
"weight": 2.5,
"createdAt": "2026-03-04 10:00:00",
"updatedAt": "2026-03-04 10:00:00"
}
]
}
}Key fields
| Field | Description |
|---|---|
tracking.number | The carrier tracking number |
tracking.link | Direct link to carrier tracking page |
tracking.carrier | Carrier name (e.g., "DHL", "DPD") |
label.fileType | MIME type of the label (e.g., image/gif, application/pdf) |
label.fileContent | Base64-encoded shipping label |
additionalPackages | For multi-parcel shipments -- each package has its own tracking number |
Decoding the shipping label
The label is Base64-encoded. Decode it to get the image or PDF file:
# Save label to file (example for image/gif)
echo "{base64Content}" | base64 --decode > shipping-label.gifNote: The
labelfield is only populated when Xentral generated the label via an integrated carrier module. If you created the shipment with just a tracking number (Option A from "Before You Start"), the label field will benull.
Download Delivery Note as PDF
You can download the delivery note as a PDF document using the V3 endpoint:
curl -X GET "https://{instance}.xentral.biz/api/v3/deliveryNotes/{deliveryNoteId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/pdf" \
-o delivery-note.pdfThe response is a binary PDF file. Use -o to save it directly to a file.
Common Integration Patterns
Pattern 1: Event-driven fulfillment (recommended)
The recommended pattern for external fulfillers:
Xentral Fulfiller
-------- --------
1. Auto-dispatch triggers -> Webhook: salesOrder.dispatched
|
2. Fetch sales order (GET /api/v1/salesOrders/{id})
|
3. Fetch delivery note (GET /api/v3/deliveryNotes?filter...)
|
4. Pick, pack, generate label (external carrier API)
|
5. POST tracking to Xentral (POST /api/v1/shipments)
|
6. Tracking synced to shop (via Xentral integration)
This pattern also applies when using a 3PL: your middleware receives the webhook, fetches SO + DN, exports to the 3PL, and pushes tracking back to Xentral when the 3PL ships.
Pattern 2: Batch reconciliation
For periodic synchronization as a safety net (not primary trigger):
# Find all recent shipments
curl -X GET "https://{instance}.xentral.biz/api/v1/shipments?page%5Bnumber%5D=1&page%5Bsize%5D=50" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Use this to verify that all dispatched orders have tracking numbers. Compare against your internal fulfillment records to catch any missed webhook events.
Caching strategy
| Data | Cache | Reason |
|---|---|---|
| Delivery notes | Cache after tracking is attached | Content will not change after shipment |
| Shipments | Cache after tracking is attached | Tracking data is final once created |
Error Handling
| Status | Meaning | Common Cause |
|---|---|---|
| 400 | Bad Request | Missing required fields, invalid filter format, missing shippingMethod |
| 401 | Unauthorized | Invalid or expired token |
| 403 | Forbidden | Missing required scope |
| 404 | Not Found | Invalid resource ID or endpoint URL |
| 429 | Too Many Requests | Rate limit exceeded |
Scope errors
If your token is missing a required scope:
{
"type": "https://api.xentral.biz/problems/token-scopes",
"title": "Token does not have the required scopes.",
"scopes": ["delivery:read"]
}Rate Limiting: Monitor
X-RateLimit-Remainingheader. Slow down requests when remaining < 25. See Rate Limiting.
Related Resources
API Documentation
Help Center
Related Guides
- Create Sales Order - Create orders to be fulfilled
- Read Stock - Check stock availability before dispatch
- Update Stock - Manual stock corrections and QC attributes
- Returns & Credit Notes - Handle returns after fulfillment
Updated 1 day ago