Returns & Credit Notes
Two API Versions Available
Returns are available in both the V1 API (stable) and the V3 Business Documents API (currently in beta). This guide covers both. V3 offers more flexibility but is currently in beta and may contain breaking changes.
Contents
- Overview
- ERP Context: How Returns Work in Xentral
- Endpoints Overview
- Prerequisites
- Before You Start
- V1: Create a Return from a Sales Order
- V1: Release a Return
- V1: Book Returned Goods into Stock
- V1: List and View Returns
- V3: Create a Return Order
- V3: Create a Return Order from a Delivery Note
- V3: Release a Return Order
- V3: Cancel a Return Order
- V3: List and View Return Orders
- V3: Create a Credit Note
- V3: Add Line Items to a Credit Note
- V3: Release a Credit Note
- Return Reasons
- Common Integration Patterns
- Error Handling
- Related Resources
Overview
This guide shows you how to process customer returns and create credit notes via the Xentral API. You will learn how to register a return, book returned goods back into stock, and issue a credit note for refund processing.
Use Cases:
- Process returns from an online shop (Shopify, WooCommerce, etc.) when customers send products back
- Automate return processing from a marketplace (Amazon, eBay) where returns are initiated externally
- Issue credit notes for returned or defective goods
- Track return reasons for quality analysis and product improvement
- Book returned items back into inventory after quality inspection
New to the Xentral API? Read first:
- Authentication - Create API Token
- Rate Limiting - Request limits
- Help Center: Managing your returns - General Xentral return documentation
ERP Context: How Returns Work in Xentral
Important: Important for developers without ERP experience: A return in an ERP is not just "customer sends product back and gets money." It is a multi-step business process with document trails, stock movements, and financial implications.
The return lifecycle
In a shop system, you might simply mark an order as "returned" and trigger a refund. In Xentral, a return is a formal business document that goes through several stages:
+----------------+ +----------------+ +----------------+ +----------------+
| 1. Return | --> | 2. Goods | --> | 3. Quality | --> | 4. Credit Note |
| registered | | received | | check | | issued |
+----------------+ +----------------+ +----------------+ +----------------+
| | | |
v v v v
Return document Stock increases Good/damaged? Refund triggered
created in ERP at warehouse Decision point Financial documentWhat happens at each stage?
| Stage | What happens | Stock impact | Financial impact |
|---|---|---|---|
| Return registered | Return document created, linked to original sales order | None yet | None yet |
| Return released | Return is officially active and can be processed | None yet | None yet |
| Goods received | Items booked back into stock (goods receipt) | Stock increases | None yet |
Note: Return label generation via API is currently not supported. This will be added in a future release (API-595).
| Stage | What happens | Stock impact | Financial impact |
|---|---|---|---|
| Credit note issued | Financial document for refund/reimbursement | None | Credit posted to customer account |
Key concepts for developers
Return vs. Credit Note: These are separate documents in Xentral. A return tracks the physical goods coming back. A credit note is the financial document for the refund. You can have a return without a credit note (e.g., exchange), or a credit note without a return (e.g., goodwill discount).
Return reasons: Every return position requires a reason. Return reasons are configured per project or globally in Xentral and must be queried first. They help with analytics (why are customers returning products?).
Goods receipt is separate: Creating a return does not automatically book items back into stock. You need to explicitly create a goods receipt for the return to increase stock levels. This allows for quality inspection before restocking.
Progress tracking: Returns have a progress field that tracks the physical processing: announced (customer said they will return) -> received (goods arrived at warehouse) -> checked (quality inspection done) -> done (fully processed). In V1, there is no possibility to set progress via API -- this is only possible in V3 or via the UI.
Endpoints Overview
V1 API (Stable)
| What do you want to do? | Endpoint | Method | Scope |
|---|---|---|---|
| Create a return | /api/v1/returns | POST | return:create |
| List returns | /api/v1/returns | GET | return:read |
| View a single return | /api/v1/returns/{id} | GET | return:read |
| Release a return | /api/v1/returns/{id}/actions/release | POST | No scope required |
| Book returned goods into stock | /api/v1/returns/{id}/goodsReceipts | POST | No scope required |
| List return reasons | /api/v1/returnReasons | GET | No scope required |
V3 Business Documents API (Beta)
Important: Beta: These endpoints are currently in Beta and available for testing. They may contain bugs, and breaking changes can occur at any time without prior notice. We do not recommend using Beta endpoints in production environments. Should you choose to use it in production, you assume full responsibility for any resulting issues.
| What do you want to do? | Endpoint | Method | Scope |
|---|---|---|---|
| Create a return order | /api/v3/returnOrders | POST | return:create |
| Create return from delivery note | /api/v3/returnOrders/actions/createFromDeliveryNote | POST | return:create |
| List return orders | /api/v3/returnOrders | GET | return:read |
| View a return order | /api/v3/returnOrders/{id} | GET | return:read |
| Update a return order | /api/v3/returnOrders/{id} | PATCH | return:update |
| Release a return order | /api/v3/returnOrders/{id}/actions/release | PATCH | return:release |
| Cancel a return order | /api/v3/returnOrders/{id}/actions/cancel | PATCH | return:cancel |
| Create a credit note | /api/v3/creditNotes | POST | creditNote:create |
| List credit notes | /api/v3/creditNotes | GET | creditNote:read |
| View a credit note | /api/v3/creditNotes/{id} | GET | creditNote:read |
| Release a credit note | /api/v3/creditNotes/{id}/actions/release | PATCH | creditNote:release |
| Add line item to credit note | /api/v3/creditNotes/{id}/lineItems | POST | creditNote:update |
Prerequisites
- Xentral account with API access
- Personal Access Token (PAT) with required scopes:
- V1:
return:create,return:read - V3 Return Orders:
return:create,return:read,return:update,return:release,return:cancel - V3 Credit Notes:
creditNote:create,creditNote:read,creditNote:update,creditNote:release
- V1:
- Sales orders must exist before you can create returns for them (V1)
- Return reasons must be configured in Xentral (per project or globally)
- Products referenced in returns must exist in the system
- For goods receipt: At least one warehouse with a storage location must be configured
Finding IDs you need:
- Sales order IDs and position IDs:
GET /api/v1/salesOrders/{id}-- API Reference- Return reasons:
GET /api/v1/returnReasons-- see Return Reasons section below- Warehouse / storage location IDs: See G4: Read Stock
Before You Start
Decision 1: V1 or V3 API?
Choose the API version based on your needs and instance configuration:
Option A: V1 API (Stable)
- Available on all Xentral instances
- Creates returns from sales order positions -- you reference the original order and specify which line items are returned
- Goods receipt (re-stocking) via dedicated endpoint
- No return label generation via API at this point
- No built-in credit note creation -- credit notes are handled separately in V3
Option B: V3 API (Beta)
- Currently in Beta -- may contain bugs and breaking changes without prior notice
- Creates return orders as standalone business documents with their own lifecycle (draft -> released -> completed)
- Can create returns from a delivery note (convenience method that auto-fills many fields). Creation from sales order/invoice will follow in the future.
- Links to related documents: sales order, credit note, delivery note, replacement sales order, invoice (currently no 1:1 link to sales order positions, only on sales order header level)
- Supports cancel, write protection, activity logging
| Criteria | V1 | V3 |
|---|---|---|
| Stability | Stable | Beta |
| Create from | Sales order positions | Address + line items, or delivery note |
| Lifecycle management | Release only | Draft -> Release -> Complete/Cancel |
| Credit note integration | Separate process | Linked via creditNote reference |
| Goods receipt (re-stocking) | Dedicated endpoint | Not in V3 spec (use V1 endpoint) |
| Line item management | Inline at creation | Separate CRUD endpoints |
Recommendation: If you only need basic return processing and goods receipt, use V1. If you need the full document lifecycle (draft, release, cancel), delivery note-based creation, or credit note linking, use V3. Note that V3 is currently in Beta and not recommended for production use.
Decision 2: Do you need a credit note?
Not every return needs a credit note. Decide based on your business process:
Scenario A: Return with refund -- Create return + create credit note + release both
Scenario B: Return with exchange -- Create return + create new sales order (no credit note needed)
Scenario C: Partial refund -- Create credit note with reduced quantities or amounts (does not require a return)
Scenario D: Goodwill credit -- Create credit note without a return (e.g., customer keeps the product but gets a refund)
Decision 3: When to book goods into stock?
For V1 returns, you decide when to create the goods receipt:
Option A: Immediate re-stocking -- Book goods receipt right after creating the return. Not recommended: you increase your stock levels in the software, but the goods have not been physically received and inspected yet.
Option B: Inspect first, then re-stock -- Create the return, inspect the goods, then book the goods receipt only for items that pass quality check.
Option C: Book into blocked warehouse -- Book the goods receipt into a blocked/quarantine warehouse on receipt, then inspect later and move to regular stock if the items pass quality check.
Tip: See G5: Update Stock for details on goods receipts from returns and quarantine storage locations.
V1: Create a Return from a Sales Order
Required Scope:
return:create
Creates a return linked to an existing sales order. You specify which sales order positions (line items) are being returned and why.
Prerequisite: You need the sales order ID, the IDs of the positions being returned, and a return reason ID. Query these first if you don't have them.
Step 1: Get the sales order and its positions (Scope: salesOrder:read)
curl -s "https://{instance}.xentral.biz/api/v1/salesOrders/{salesOrderId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: View Sales Order
The response includes positions[] with each position's id, product, and quantity.
Step 2: Get available return reasons (No scope required)
curl -s "https://{instance}.xentral.biz/api/v1/returnReasons" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: List Return Reasons
See Return Reasons for the full response format. Return reasons use standard V1 pagination (page[number], page[size]).
Step 3: Create the return
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"salesOrder": {
"id": "42",
"positions": [
{
"id": "101",
"quantity": 2,
"returnReason": {
"id": "1"
}
}
]
}
}'Response: 201 Created
The return ID is returned in the Location header (e.g., /api/v1/returns/5). No response body.
Returning multiple positions from the same order:
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"salesOrder": {
"id": "42",
"positions": [
{
"id": "101",
"quantity": 2,
"returnReason": {"id": "1"}
},
{
"id": "102",
"quantity": 1,
"returnReason": {"id": "3"}
}
]
}
}'Note: Each position can have a different return reason. You can optionally include a
shippingMethod(e.g.,"shippingMethod": {"id": "1"}) to define the return shipping method. Thequantitydoes not have to match the full ordered quantity -- partial returns are supported.
V1: Release a Return
Scope: No specific scope required for release.
After creating a return, you need to release it to make it active for processing.
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns/{returnId}/actions/release" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response: 204 No Content
The return status changes to released.
V1: Book Returned Goods into Stock
Once the returned goods have been received and inspected, book them back into stock with a goods receipt. This is the step that actually increases your inventory.
Scope: No specific scope required for goods receipt.
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns/{returnId}/goodsReceipts" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"positions": [
{
"product": {"id": "4"},
"quantity": 2,
"returnPosition": {"id": "1"},
"stockMovements": [
{
"quantity": 2,
"warehouse": {"id": "1"},
"storageLocation": {"id": "1"}
}
]
}
]
}'API Reference: Create Goods Receipt for Return
Response: 201 Created -- The goods receipt ID is in the Location header.
With quality control attributes (batch, serial numbers):
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns/{returnId}/goodsReceipts" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"positions": [
{
"product": {"id": "4"},
"quantity": 2,
"returnPosition": {"id": "1"},
"stockMovements": [
{
"quantity": 2,
"warehouse": {"id": "1"},
"storageLocation": {"id": "1"},
"qualityControlAttributes": {
"batch": "LOT-2026-001",
"serialNumbers": [
{"number": "SN-001"},
{"number": "SN-002"}
]
}
}
]
}
]
}'Splitting across storage locations:
If some items go to normal stock and some to quarantine:
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns/{returnId}/goodsReceipts" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"positions": [
{
"product": {"id": "4"},
"quantity": 5,
"returnPosition": {"id": "1"},
"stockMovements": [
{
"quantity": 3,
"warehouse": {"id": "1"},
"storageLocation": {"id": "1"}
},
{
"quantity": 2,
"warehouse": {"id": "1"},
"storageLocation": {"id": "3"}
}
]
}
]
}'Tip: The sum of
stockMovements[].quantityshould match the positionquantity. You can create multiple goods receipts for the same return to handle partial deliveries.
V1: List and View Returns
Required Scope:
return:read
List returns with filters:
curl -s "https://{instance}.xentral.biz/api/v1/returns?filter[0][key]=customerId&filter[0][op]=equals&filter[0][value]=4&page[number]=1&page[size]=10" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"For available filter keys, refer to the API Reference.
Response:
{
"data": [
{
"id": "1",
"date": "2026-03-11",
"status": "released",
"progress": "announced",
"documentNumber": "2026-500001",
"salesOrder": {"id": "2"},
"customer": {"id": "4", "number": "10000"},
"shippingMethod": {"id": "1", "name": "DHL"},
"project": {"id": "1", "name": "Standard Projekt"},
"internalComment": ""
}
],
"extra": {
"totalCount": 1,
"page": {"number": 1, "size": 10}
}
}View a single return (with positions):
curl -s "https://{instance}.xentral.biz/api/v1/returns/{returnId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Response:
{
"data": {
"id": "1",
"date": "2026-03-11",
"status": "released",
"progress": "announced",
"documentNumber": "2026-500001",
"salesOrder": {"id": "2"},
"shippingMethod": {"id": 1, "name": "DHL"},
"project": {"id": 1, "name": "Standard Projekt"},
"bodyOutroduction": "",
"internalComment": "",
"positions": [
{
"id": "1",
"quantity": 1,
"salesOrderPosition": {"id": "1"},
"product": {
"id": "1",
"number": "1000039",
"name": "slide overlay ph-neutral / klapp-photo mount / passepartout"
},
"returnReason": {
"designation": "14 Tage Rückgaberecht"
}
}
]
}
}Download return as PDF: (Scope: return:read)
curl -s "https://{instance}.xentral.biz/api/v1/returns/{returnId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/pdf" \
-o return-2026-000001.pdfV1 Return Status Values
| Status | Description |
|---|---|
created | Return created but not yet released |
released | Released for processing |
completed | All steps completed |
canceled | Return was cancelled |
V1 Return Progress Values
Progress tracks the physical processing of the return. In V1, progress cannot be set via API -- only in V3 or via the UI.
| Progress | Description |
|---|---|
announced | Return registered, goods not yet received |
received | Goods received at warehouse |
checked | Quality inspection completed |
done | Return fully processed |
V3: Create a Return Order
Important: Beta: This endpoint is currently in Beta and may contain breaking changes without prior notice.
Required Scope:
return:create
V3 return orders are full business documents. They start in draft status and must be released before they can be processed.
Minimal return order:
curl -s -X POST "https://{instance}.xentral.biz/api/v3/returnOrders" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {
"id": "4"
},
"lineItems": [
{
"product": {"id": "4"},
"quantity": 2,
"returnReason": {"id": "1"}
}
]
}'API Reference: Create Return Order V3
Response: 201 Created with the full return order object.
Return order linked to a sales order with progress tracking:
curl -s -X POST "https://{instance}.xentral.biz/api/v3/returnOrders" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {
"id": "4"
},
"salesOrder": {
"id": "42"
},
"progress": "announced",
"customerOrderNumber": "SHOP-12345",
"documentDate": "2026-03-11",
"internalComment": "Customer reported damaged packaging",
"lineItems": [
{
"product": {"id": "4"},
"quantity": 2,
"returnReason": {"id": "1"},
"description": "Outer packaging torn, inner product intact"
},
{
"product": {"id": "7"},
"quantity": 1,
"returnReason": {"id": "3"},
"description": "Wrong size delivered"
}
]
}'Key fields for V3 return orders
| Field | Purpose | When to use |
|---|---|---|
address.id | Customer/business partner (required) | Always |
salesOrder.id | Link to original sales order | When return is for a specific order |
creditNote.id | Link to associated credit note | When credit note already exists |
deliveryNote.id | Link to the delivery note | When you know which shipment is affected |
replacementSalesOrder.id | Link to replacement order | For exchange scenarios |
progress | Physical processing status | To track where in the return flow you are |
customerOrderNumber | External order reference | For matching with shop system |
isSupplierReturnOrder | Whether this is a supplier return | For B2B supplier returns. In this case, address.id must be a supplier ID. |
V3: Create a Return Order from a Delivery Note
This convenience endpoint creates a return order pre-filled with data from an existing delivery note. It automatically links the return to the correct sales order and fills in line item details.
Important: Beta: This endpoint is currently in Beta and may contain breaking changes without prior notice.
Scope: Currently no specific scope required.
curl -s -X POST "https://{instance}.xentral.biz/api/v3/returnOrders/actions/createFromDeliveryNote" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"deliveryNote": {
"id": "15"
},
"lineItems": [
{
"id": "201",
"quantity": 2,
"returnReason": {"id": "1"},
"description": "Item arrived damaged"
}
]
}'API Reference: Create Return Order from Delivery Note V3
Response: 201 Created with the full return order object.
What gets auto-resolved from the delivery note:
| Field | Auto-Resolved? | Details |
|---|---|---|
salesOrder | Yes (if linked) | Only if the delivery note is linked to a sales order. If the delivery note has no sales order reference, this will be null. |
address | Yes | Copied from the delivery note's address. |
project | Yes | Copied from the delivery note's project. |
documentAddress | Yes | Full postal address copied from the delivery note. |
invoice | No | Always null -- you must link the invoice separately if needed. |
preferredWarehouse | No | Always null -- not inherited from the delivery note. |
customerNumber | No | Not resolved via this endpoint (unlike manual POST /api/v3/returnOrders which does resolve it). |
Note: The
lineItems[].idhere refers to the delivery note line item ID, not the product ID. Thequantityspecifies how many items from that delivery note line are being returned. Each line item requires areturnReason.Tip: The main advantage of
createFromDeliveryNoteover manualPOST /api/v3/returnOrdersis thatsalesOrder,address,project, anddocumentAddressare automatically inherited from the delivery note -- you don't need to look them up or specify them in your request.
V3: Release a Return Order
Return orders start in draft status. Release them to make them active for processing.
Required Scope:
return:release
curl -s -X PATCH "https://{instance}.xentral.biz/api/v3/returnOrders/{returnOrderId}/actions/release" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: Release Return Order V3
Response: 204 No Content
The return order status changes from draft to released.
Note: Write protection does not block release. Even if write protection is enabled on a draft, release still works. However, if the status does not allow release, you will receive a
409 Conflicterror.
V3: Cancel a Return Order
Cancel a return order that is no longer needed. Only released return orders can be cancelled. Draft return orders cannot be cancelled -- they must be deleted instead.
Required Scope:
return:cancel
curl -s -X PATCH "https://{instance}.xentral.biz/api/v3/returnOrders/{returnOrderId}/actions/cancel" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: Cancel Return Order V3
Response: 204 No Content
Important: Only return orders in
releasedstatus can be cancelled. Draft return orders can only be deleted (not cancelled), and completed return orders cannot be cancelled either.
V3: List and View Return Orders
Required Scope:
return:read
List return orders with filters:
curl -s "https://{instance}.xentral.biz/api/v3/returnOrders?filter%5B0%5D%5Bkey%5D=status&filter%5B0%5D%5Bop%5D=equals&filter%5B0%5D%5Bvalue%5D=released&perPage=25&page=1" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"V3 Pagination: V3 endpoints use
pageandperPage(notpage[number]/page[size]like V1). The response containsmetaandlinksinstead ofextra.
API Reference: List Return Orders V3
For available filter keys, refer to the API Reference. Filter keys can change as more are added in the future.
With includes (to get line items and related data in a single call):
curl -s "https://{instance}.xentral.biz/api/v3/returnOrders?include=lineItems,project,address,tags&perPage=25" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"View a single return order with more details:
curl -s "https://{instance}.xentral.biz/api/v3/returnOrders/{returnOrderId}?include=lineItems,lineItems.product,project,address,tags,activity" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: View Return Order V3
Download return order as PDF: (Scope: return:read)
curl -s "https://{instance}.xentral.biz/api/v3/returnOrders/{returnOrderId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/pdf" \
-o return-order.pdfV3 Return Order Status Values
| Status | Description |
|---|---|
draft | Created, not yet released. Can be edited or deleted. |
released | Active, being processed. Can be cancelled. |
completed | Fully processed. Cannot be set via V3 API at this point. |
cancelled | Cancelled (only from released status). |
V3 Return Order Progress Values
| Progress | Description |
|---|---|
announced | Return registered, goods not yet received |
received | Goods received at warehouse |
checked | Quality inspection completed |
done | Return fully processed |
Note:
statustracks the document lifecycle (draft -> released -> completed).progresstracks the physical processing (announced -> received -> checked -> done). They are independent of each other.
V3: Create a Credit Note
Important: Beta: This endpoint is currently in Beta and may contain breaking changes without prior notice.
Required Scope:
creditNote:create
Credit notes are financial documents used for refunds or credits. They can be linked to a return order but can also be created independently.
Create a credit note:
curl -s -X POST "https://{instance}.xentral.biz/api/v3/creditNotes" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {
"id": "4"
},
"documentDate": "2026-03-11",
"lineItems": [
{
"product": {"id": "4"},
"quantity": 2,
"price": {
"net": {
"amount": 9.54,
"currency": "EUR"
}
}
}
]
}'API Reference: Create Credit Note V3
Response: 201 Created with the full credit note object, including calculated totals.
Credit note with more details:
curl -s -X POST "https://{instance}.xentral.biz/api/v3/creditNotes" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {
"id": "4"
},
"documentDate": "2026-03-11",
"language": "de",
"bodyIntroduction": "We are issuing this credit note for your return RET-2026-000001.",
"financials": {
"tax": {
"taxation": "domestic"
},
"currency": "EUR"
},
"costCenter": "Returns",
"lineItems": [
{
"product": {"id": "4"},
"quantity": 2,
"name": "BIO Kaffee Arabica 250g",
"number": "100001",
"price": {
"net": {
"amount": 9.54,
"currency": "EUR"
}
},
"description": "Credit for returned items (damaged packaging)"
},
{
"product": {"id": "7"},
"quantity": 1,
"name": "Teetasse Keramik",
"number": "200015",
"price": {
"net": {
"amount": 12.50,
"currency": "EUR"
}
},
"discount": 10.0,
"description": "Credit for wrong item delivered (10% discount applied)"
}
]
}'Key fields for credit notes
| Field | Purpose | When to use |
|---|---|---|
address.id | Customer/business partner (required) | Always |
financials.tax.taxation | Tax type: domestic, eu, export, exempt | When tax differs from customer default |
financials.currency | Currency code (e.g., EUR) | When not using default currency |
costCenter | Cost center for accounting | For cost tracking |
deliveryDate | Delivery date on the credit note | When credit relates to a specific delivery |
lineItems[].discount | Discount percentage on a line item | For partial credits |
lineItems[].price.net.amount | Net price per unit | Always (otherwise uses product master data price) |
V3: Add Line Items to a Credit Note
You can add line items to an existing credit note after creation. This works in both draft and released status, as long as write protection is not enabled.
Required Scope:
creditNote:update
curl -s -X POST "https://{instance}.xentral.biz/api/v3/creditNotes/{creditNoteId}/lineItems" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"product": {"id": "4"},
"quantity": 1,
"price": {
"net": {
"amount": 9.54,
"currency": "EUR"
}
},
"description": "Additional item credited"
}'API Reference: Create Credit Note Line Item V3
Response: 201 Created with the full line item object, including calculated values like taxRate, itemRevenue, lineItemRevenue, and contributionMargin.
V3: Release a Credit Note
Release the credit note to finalize it. This assigns a document number, makes it an official financial document, and activates write protection.
Required Scope:
creditNote:release
curl -s -X PATCH "https://{instance}.xentral.biz/api/v3/creditNotes/{creditNoteId}/actions/release" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: Release Credit Note V3
Response: 204 No Content
Important: Once released, a credit note cannot be edited unless you remove write protection first. Released credit notes are legal financial documents.
Return Reasons
Return reasons are configured per project or globally in Xentral. Query them before creating returns to get the correct IDs.
curl -s "https://{instance}.xentral.biz/api/v1/returnReasons?page%5Bnumber%5D=1&page%5Bsize%5D=10" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"API Reference: List Return Reasons
Response:
{
"data": [
{
"id": "1",
"designation": "Interne Reparatur",
"description": "Artikel ist als defekt eingeliefert worden und soll untersucht / repariert / nachgebessert werden.",
"language": "DE",
"project": {"id": "0"}
},
{
"id": "4",
"designation": "14 Tage Rückgaberecht",
"description": "Kunde macht von seinem 14tägigen Rückgaberecht Gebrauch.",
"language": "DE",
"project": {"id": "0"}
},
{
"id": "7",
"designation": "Falscher Artikel geliefert",
"description": "Der Artikel wurde falsch geliefert. Wiedereinlagerung und ggf. Rückfrage nach Ersatzartikel.",
"language": "DE",
"project": {"id": "0"}
}
],
"extra": {
"totalCount": 14,
"page": {"number": 1, "size": 10}
}
}Note: Return reasons with
project.id = "0"are global (available across all projects). Reasons with a specific project ID are only available for that project.
Optional query parameters:
project[id]-- filter by project (returns only reasons for that project + global reasons)language-- filter by language code (e.g.,de,en)
Caching: Return reasons rarely change. Query them once and cache the mapping
{reason_name: reason_id}in your integration.
Common Integration Patterns
Pattern 1: Shop Return (V1 -- Full Flow)
The most common integration: a customer initiates a return in your shop, and you process it in Xentral.
+-------------+ +-------------+ +------------+ +-----------+ +---------------+
| 1. Customer | --> | 2. Create | --> | 3. Release | --> | 4. Goods | --> | 5. Process |
| requests | | return (V1) | | return | | received | | refund in shop|
| return | | | | | | (goods | | |
+-------------+ +-------------+ +------------+ | receipt) | +---------------+
+-----------+Step 1: Create the return -- The return ID is returned in the Location header.
curl -s -D - -X POST "https://{instance}.xentral.biz/api/v1/returns" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"salesOrder": {
"id": "42",
"positions": [
{"id": "101", "quantity": 2, "returnReason": {"id": "1"}}
]
}
}'Step 2: Release the return
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns/{returnId}/actions/release" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Step 3: Book goods into stock (after physical receipt and inspection)
curl -s -X POST "https://{instance}.xentral.biz/api/v1/returns/{returnId}/goodsReceipts" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-11",
"positions": [
{
"product": {"id": "4"},
"quantity": 2,
"returnPosition": {"id": "1"},
"stockMovements": [
{
"quantity": 2,
"warehouse": {"id": "1"},
"storageLocation": {"id": "1"}
}
]
}
]
}'Pattern 2: V3 Return with Credit Note (Full Flow)
The complete V3 flow: create return order, release it, and optionally create a credit note if a refund is needed.
+-------------+ +-------------+ +------------+ +------------+ +---------------+
| 1. Create | --> | 2. Release | --> | 3. Create | --> | 4. Release | --> | 5. Link return|
| return order| | return order| | credit note| | credit note| | to credit note|
| (draft) | | | | (if needed)| | | | (update) |
+-------------+ +-------------+ +------------+ +------------+ +---------------+# Step 1: Create return order
curl -s -X POST "https://{instance}.xentral.biz/api/v3/returnOrders" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {"id": "4"},
"salesOrder": {"id": "42"},
"progress": "announced",
"lineItems": [
{"product": {"id": "4"}, "quantity": 2, "returnReason": {"id": "1"}}
]
}'
# Save the returned id for next steps
# Step 2: Release return order
curl -s -X PATCH "https://{instance}.xentral.biz/api/v3/returnOrders/{returnOrderId}/actions/release" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
# Step 3: Create credit note
curl -s -X POST "https://{instance}.xentral.biz/api/v3/creditNotes" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {"id": "4"},
"documentDate": "2026-03-11",
"lineItems": [
{
"product": {"id": "4"},
"quantity": 2,
"price": {"net": {"amount": 9.54, "currency": "EUR"}}
}
]
}'
# Save the returned credit note id
# Step 4: Release credit note
curl -s -X PATCH "https://{instance}.xentral.biz/api/v3/creditNotes/{creditNoteId}/actions/release" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
# Step 5: Link return order to credit note
curl -s -X PATCH "https://{instance}.xentral.biz/api/v3/returnOrders/{returnOrderId}" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"creditNote": {"id": "{creditNoteId}"}
}'Pattern 3: Delivery Note-Based Return (V3)
The simplest V3 flow: create a return directly from the delivery note. Xentral auto-fills all the details.
# One call creates the return with all linked data
curl -s -X POST "https://{instance}.xentral.biz/api/v3/returnOrders/actions/createFromDeliveryNote" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"deliveryNote": {"id": "15"},
"lineItems": [
{"id": "201", "quantity": 2, "returnReason": {"id": "1"}}
]
}'Pattern 4: Goodwill Credit (No Physical Return)
Credit the customer without requiring a physical return:
curl -s -X POST "https://{instance}.xentral.biz/api/v3/creditNotes" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {"id": "4"},
"documentDate": "2026-03-11",
"bodyIntroduction": "Goodwill credit for order SHOP-12345 due to shipping delay.",
"lineItems": [
{
"product": {"id": "4"},
"quantity": 1,
"price": {"net": {"amount": 5.00, "currency": "EUR"}},
"description": "Goodwill credit (50% of unit price)"
}
]
}'Error Handling
| Status | Meaning | Common Cause |
|---|---|---|
| 400 | Bad Request | Invalid JSON, missing required field, invalid return reason ID, sales order position ID does not exist, quantity exceeds ordered quantity |
| 401 | Unauthorized | Invalid or expired token |
| 403 | Forbidden | Missing required scope (e.g., return:create, creditNote:create) |
| 404 | Not Found | Return ID, sales order ID, or delivery note ID does not exist |
| 406 | Not Acceptable | Missing Accept: application/json header |
| 409 | Conflict | V3: Write-protected document (release/update blocked), or invalid status transition (e.g., cancelling a released return) |
| 415 | Unsupported Media Type | Missing Content-Type: application/json header |
| 429 | Too Many Requests | Rate limit exceeded |
Note: Xentral returns
400 Bad Requestfor validation errors, not422.
Common error scenarios
Invalid sales order position ID -- returns 400:
{
"type": "https://api.xentral.biz/problems/generic-validation",
"title": "Generic request validation failed.",
"messages": ["Sales order position not found"]
}Verify the position ID exists on the referenced sales order.
Return quantity exceeds ordered quantity -- returns 400:
You cannot return more items than were originally ordered on that position.
Cancelling a non-released return order (V3) -- returns 409:
{
"type": "https://api.xentral.biz/problems/invalid-status",
"title": "Invalid status transition",
"detail": "Only a draft BusinessDocument can be deleted."
}Only released return orders can be cancelled. Draft return orders can only be deleted, and completed return orders cannot be cancelled.
Missing scope:
{
"message": "Missing required scopes: return:create."
}Rate Limiting
Monitor the X-RateLimit-Remaining header. Rate limits vary by customer instance.
| Remaining | Recommended Action |
|---|---|
| Above 50% | Full speed (no delay) |
| Below 50% | Add a small delay (e.g., 50ms) between requests |
| Below 25% | Add a larger delay (e.g., 200ms) between requests |
Tip: Implement exponential backoff on
429responses. Wait for the time indicated in theRetry-Afterheader before retrying.
Related Resources
API Documentation
- Create Return (V1)
- List Returns (V1)
- View Return (V1)
- Release Return (V1)
- Create Goods Receipt for Return (V1)
- List Return Reasons (V1)
- View Sales Order (V1)
- Authentication
- Rate Limiting
Help Center
- Managing your returns - Return processing in Xentral
- Introduction to Order Management - Sales order overview
- Creating a warehouse structure - Warehouse setup (for goods receipt)
Related Guides
- G1: Create Sales Order - Create orders that may later need returns
- G4: Read Stock - Read stock levels and warehouse structure
- G5: Update Stock - Direct stock updates and goods receipts from returns
Updated 1 day ago