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

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:


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 document

What happens at each stage?

StageWhat happensStock impactFinancial impact
Return registeredReturn document created, linked to original sales orderNone yetNone yet
Return releasedReturn is officially active and can be processedNone yetNone yet
Goods receivedItems booked back into stock (goods receipt)Stock increasesNone yet

Note: Return label generation via API is currently not supported. This will be added in a future release (API-595).

StageWhat happensStock impactFinancial impact
Credit note issuedFinancial document for refund/reimbursementNoneCredit 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?EndpointMethodScope
Create a return/api/v1/returnsPOSTreturn:create
List returns/api/v1/returnsGETreturn:read
View a single return/api/v1/returns/{id}GETreturn:read
Release a return/api/v1/returns/{id}/actions/releasePOSTNo scope required
Book returned goods into stock/api/v1/returns/{id}/goodsReceiptsPOSTNo scope required
List return reasons/api/v1/returnReasonsGETNo 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?EndpointMethodScope
Create a return order/api/v3/returnOrdersPOSTreturn:create
Create return from delivery note/api/v3/returnOrders/actions/createFromDeliveryNotePOSTreturn:create
List return orders/api/v3/returnOrdersGETreturn:read
View a return order/api/v3/returnOrders/{id}GETreturn:read
Update a return order/api/v3/returnOrders/{id}PATCHreturn:update
Release a return order/api/v3/returnOrders/{id}/actions/releasePATCHreturn:release
Cancel a return order/api/v3/returnOrders/{id}/actions/cancelPATCHreturn:cancel
Create a credit note/api/v3/creditNotesPOSTcreditNote:create
List credit notes/api/v3/creditNotesGETcreditNote:read
View a credit note/api/v3/creditNotes/{id}GETcreditNote:read
Release a credit note/api/v3/creditNotes/{id}/actions/releasePATCHcreditNote:release
Add line item to credit note/api/v3/creditNotes/{id}/lineItemsPOSTcreditNote: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
  • 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
CriteriaV1V3
StabilityStableBeta
Create fromSales order positionsAddress + line items, or delivery note
Lifecycle managementRelease onlyDraft -> Release -> Complete/Cancel
Credit note integrationSeparate processLinked via creditNote reference
Goods receipt (re-stocking)Dedicated endpointNot in V3 spec (use V1 endpoint)
Line item managementInline at creationSeparate 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"
          }
        }
      ]
    }
  }'

API Reference: Create Return

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. The quantity does 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"

API Reference: Release Return

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[].quantity should match the position quantity. 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"

API Reference: List Returns

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"

API Reference: View Return

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.pdf

V1 Return Status Values

StatusDescription
createdReturn created but not yet released
releasedReleased for processing
completedAll steps completed
canceledReturn 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.

ProgressDescription
announcedReturn registered, goods not yet received
receivedGoods received at warehouse
checkedQuality inspection completed
doneReturn 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

FieldPurposeWhen to use
address.idCustomer/business partner (required)Always
salesOrder.idLink to original sales orderWhen return is for a specific order
creditNote.idLink to associated credit noteWhen credit note already exists
deliveryNote.idLink to the delivery noteWhen you know which shipment is affected
replacementSalesOrder.idLink to replacement orderFor exchange scenarios
progressPhysical processing statusTo track where in the return flow you are
customerOrderNumberExternal order referenceFor matching with shop system
isSupplierReturnOrderWhether this is a supplier returnFor 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:

FieldAuto-Resolved?Details
salesOrderYes (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.
addressYesCopied from the delivery note's address.
projectYesCopied from the delivery note's project.
documentAddressYesFull postal address copied from the delivery note.
invoiceNoAlways null -- you must link the invoice separately if needed.
preferredWarehouseNoAlways null -- not inherited from the delivery note.
customerNumberNoNot resolved via this endpoint (unlike manual POST /api/v3/returnOrders which does resolve it).

Note: The lineItems[].id here refers to the delivery note line item ID, not the product ID. The quantity specifies how many items from that delivery note line are being returned. Each line item requires a returnReason.

Tip: The main advantage of createFromDeliveryNote over manual POST /api/v3/returnOrders is that salesOrder, address, project, and documentAddress are 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 Conflict error.


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 released status 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 page and perPage (not page[number]/page[size] like V1). The response contains meta and links instead of extra.

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.pdf

V3 Return Order Status Values

StatusDescription
draftCreated, not yet released. Can be edited or deleted.
releasedActive, being processed. Can be cancelled.
completedFully processed. Cannot be set via V3 API at this point.
cancelledCancelled (only from released status).

V3 Return Order Progress Values

ProgressDescription
announcedReturn registered, goods not yet received
receivedGoods received at warehouse
checkedQuality inspection completed
doneReturn fully processed

Note: status tracks the document lifecycle (draft -> released -> completed). progress tracks 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

FieldPurposeWhen to use
address.idCustomer/business partner (required)Always
financials.tax.taxationTax type: domestic, eu, export, exemptWhen tax differs from customer default
financials.currencyCurrency code (e.g., EUR)When not using default currency
costCenterCost center for accountingFor cost tracking
deliveryDateDelivery date on the credit noteWhen credit relates to a specific delivery
lineItems[].discountDiscount percentage on a line itemFor partial credits
lineItems[].price.net.amountNet price per unitAlways (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

StatusMeaningCommon Cause
400Bad RequestInvalid JSON, missing required field, invalid return reason ID, sales order position ID does not exist, quantity exceeds ordered quantity
401UnauthorizedInvalid or expired token
403ForbiddenMissing required scope (e.g., return:create, creditNote:create)
404Not FoundReturn ID, sales order ID, or delivery note ID does not exist
406Not AcceptableMissing Accept: application/json header
409ConflictV3: Write-protected document (release/update blocked), or invalid status transition (e.g., cancelling a released return)
415Unsupported Media TypeMissing Content-Type: application/json header
429Too Many RequestsRate limit exceeded

Note: Xentral returns 400 Bad Request for validation errors, not 422.

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.

RemainingRecommended 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 429 responses. Wait for the time indicated in the Retry-After header before retrying.


Related Resources

API Documentation

Help Center

Related Guides