1. U4 ERPx
  2. API Reference
  3. Customers and sales
  4. Sales Orders

Sales Orders

Sales Orders API Reference This page provides a comprehensive reference for all parameters, endpoints, and behaviors of the Sales Orders API. Use this guide to understand request/response structures, validation rules, and integration best practices.

Purpose: The Sales Orders API manages all aspects of sales order data, including creation, updates, and termination. Each order contains a set of pre-configured products to be delivered to, and paid for by, a customer associated with the order.

Base URL: /v1/sales-orders

Authentication:
All APIs require a Client ID and Client Secret.
Refer to the global authentication documentation for details.

System Parameters:
System parameters for this API are available in Online Help → System parameters and values → System parameters → Logistics → Sales (SO)

   

Supported Methods

HTTP MethodEndpointDescriptionLimits & Notes
POST/v1/batch/sales-ordersCreates many sales orders in bulk.Asynchronous operation. Accepts a JSON file containing an array of sales orders following the POST /v1/sales-orders DTO format. Returns 201 Created immediately with a URL to track the batch operation. Hard limits depend on the optional skipWorkflow parameter value: 12 detail lines / 37,000 DB rows (skipWorkflow=false) or 1,000 detail lines / 1,550,000 DB rows (skipWorkflow=true). Automatic sales order number assignment is allowed if the order uses a number type with a number series that has an automatic assignment method.

   

Swagger / Schema

Version v1

   

Method Details

Sample Request

Header details:
- content-type: multipart/form-data;
Body details (only one row of the form-data):
- name: leave it empty
- value: attach the JSON file with the content
[
  {
    "customerId": "1000",
    "transactionType": "SO",
    "responsible": "FRED",
    "salesPerson": "SYSEN",
    "orderLines": [
      {
        "productCode": "1000",
        "price": 50.0,
        "quantity": 1,
        "glAnalysis": [
          {
            "accounting": {
              "dim1": {
                "dimValue": "120"
              },
              "dim2": {
                "dimValue": "1000"
              }
            }
          }
        ]
      }
    ]
  },
  {
    "customerId": "1015",
    "transactionType": "SO",
    "responsible": "FRED",
    "salesPerson": "SYSEN",
    "orderLines": [
      {
        "productCode": "NESP02",
        "price": 0.90,
        "quantity": 50,
        "glAnalysis": [
          {
            "accounting": {
              "dim1": {
                "dimValue": "120"
              },
              "dim2": {
                "dimValue": "1000"
              }
            }
          }
        ]
      }
    ]
  }
]
[
  {
    "accountable": "Fredrik Grinøy",
    "customerId": "1015",
    "isBackToBackOrderUsed": false,
    "isBilledAtProject": false,
    "currencyCode": "GBP",
    "isPartOfConsolidatedInvoice": false,
    "externalReference": "",
    "externalOrderId": "",
    "followUp": "2026-04-29",
    "notes": "",
    "orderDate": "2026-04-29",
    "orderNumber": 21990055,
    "orderType": "VS",
    "period": 202601,
    "responsible": "SYSEN",
    "salesPerson": "SYSEN",
    "orderStatus": "N",
    "transactionType": "SO",
    "defaultGLAnalysis": {
      "dim1": {
        "attributeId": "C1",
        "attributeIdDescription": "Cost centre",
        "dimValue": "",
        "dimValueDescription": ""
      },
      "dim2": {
        "attributeId": "B0",
        "attributeIdDescription": "Project code",
        "dimValue": "",
        "dimValueDescription": ""
      },
      "dim3": {},
      "dim4": {},
      "dim5": {},
      "dim6": {},
      "dim7": {}
    },
    "deliveryInformation": {
      "thirdPartyDeliveryId": "1015",
      "thirdPartyDeliveryAddressId": 449,
      "thirdPartyTypeDeliveryAddress": "R",
      "thirdPartyDeliveryAddress": "Alfheim 7\r\n1370 ASKER\r\nNorway",
      "deliveryMethodDescription": "Delivery by car",
      "deliveryTermsDescription": "Free on Board",
      "deliveryComment": "",
      "deliveryDate": "2026-04-29",
      "deliveryMethod": "CAR",
      "deliveryTerms": "FOB"
    },
    "invoicing": {
      "customerAddressId": 449,
      "invoiceRecipientId": "1015",
      "headerText": "",
      "footerText": "",
      "paymentMethod": "CH",
      "paymentTerms": "30",
      "text1": "",
      "text2": "3",
      "text3": "",
      "text4": ""
    },
    "orderLines": [
      {
        "distributionKey": 0,
        "productCode": "NESP02",
        "productDescription": "Dharkan",
        "isBackToBackOrderUsedOnLine": false,
        "backToBackOrderNumber": 0,
        "isCustomerAddressUsedOnBackToBackOrder": false,
        "currencyAmount": 45,
        "lineDiscountPercent": 0,
        "lineDeliveryDate": "2026-04-29",
        "status": "N",
        "backToBackOrderPriority": "2",
        "price": 0.9,
        "productText": "",
        "quantity": 50,
        "accountingTemplate": "",
        "unit": "UN",
        "glAnalysis": [
          {
            "accounting": {
              "dim1": {
                "attributeId": "C1",
                "attributeIdDescription": "Cost centre",
                "dimValue": "120",
                "dimValueDescription": "Purchase & Stock Control"
              },
              "dim2": {
                "attributeId": "B0",
                "attributeIdDescription": "Project code",
                "dimValue": "1000",
                "dimValueDescription": "Project 1000"
              },
              "dim3": {},
              "dim4": {
                "attributeId": "BF",
                "attributeIdDescription": "Work order code",
                "dimValue": "",
                "dimValueDescription": ""
              },
              "dim5": {
                "attributeId": "B1",
                "attributeIdDescription": "Activity code",
                "dimValue": "",
                "dimValueDescription": ""
              },
              "dim6": {},
              "dim7": {}
            },
            "account": "3013",
            "amount": 45,
            "percentageSplit": 100,
            "taxCode": "3N",
            "taxSystem": "EU"
          }
        ]
      }
    ]
  }
]

Important Notes

The Batch API does not receive a JSON object in the request body, but instead, it expects a JSON file (GZIP-compressed files containing the JSON are also accepted, for cases where the file size exceeds the batch framework’s upload limit). Please refer to the “POST Structure Details” tab above to understand how to include the file in the request, and to the “Simple/Basic Example” tab above for the minimal expected file content, or to the “Complete Example” tab above for a full example with all available fields.

The call is asynchronous. The endpoint returns a 201 Created response immediately, containing a URL to track the batch operation (this is found in the response header, under the ’location’ property). Use the Batch Operations API endpoints to follow up:

  • GET /v1/batch-operations/{batchRequestId}/status — Check if the process is pending, in progress, completed, or failed.
  • GET /v1/batch-operations/{batchRequestId}/results — Download the results file with details on any failed orders. Use the optional type=success parameter to retrieve a summary of successfully created orders instead.
  • POST /v1/batch-operations/{batchRequestId}/cancel — Cancel a running process.

Valid orders are saved per page (100 sales orders at a time) directly into the Sales Orders tables as they are processed.

Invalid orders are not saved to the system. Error details for these orders are available via the results endpoint. To retry, correct the errors in the failed entries and resubmit them in a new Sales Order Batch request.

Multi-client capability: All sales orders in a batch are created in the same company. The company is determined by the optional companyId URL query parameter, supplied in the request URL as ?companyId={companyId} (for example: POST /v1/sales-orders/batch?companyId=123). If companyId is omitted in the query string, the authenticated user’s default company is used for all orders. If companyId is provided in the query string, all orders are created in that company, provided the authenticated user has access to it. Any companyId field present in individual order DTOs is ignored. Only the URL query parameter and the authenticated user’s default company are considered.

Limits & Notes

There are two types of hard limits for the batch endpoint of the Sales Orders API:

  • On the number of detail lines per sales order.
  • On the total number of database items to be stored. Database items are the sum of order header, detail, and GL rows generated in total. This can be estimated using the following formula:
    • Database_Rows = SUM(1 + SalesOrderDetails * 3)
    • Example: The total number of database rows for a batch of 2 orders (one with 4 and the other with 5 details) is (1+4*3) + (1+5*3) = 13+16 = 29 items

Note: The formula above is an approximation based on average order complexity. The actual number of database rows may vary depending on the specific configuration of each order.

These limits vary depending on the value of the skipWorkflow flag.

With skipWorkflow=false (or by default when the parameter is not provided):

  • Maximum order detail lines: 12 detail lines per sales order.
  • Maximum database items: 37,000 items per call.
    • Using the formula above, if all orders have 12 details, you can create up to 1,000 sales orders per call.
  • Workflow tasks are generated for each detail line of successfully created sales orders.

With skipWorkflow=true:

  • Maximum order detail lines: 1,000 detail lines per sales order.
  • Maximum database items: 1,550,000 items per call.
    • Using the formula above, if all orders have 1,000 details, you can create up to 516 sales orders per call. If all orders have 10 details, you can create up to 50,000 total orders.
  • No workflow tasks are generated. Orders can be printed, picked, and invoiced normally.

General:

  • The file must be a valid JSON array, where each element follows the POST /v1/sales-orders request body structure.
  • Automatic sales order number assignment is allowed if the order uses a number type with a number series that has an automatic assignment method.
  • Ensure sufficient posting cycles are available for the volume of orders being created.

   

Validation Rules for POST Batch Method

Hard limits or content validation errors are not captured by the asynchronous call, but rather when calling the batch-operations endpoint to get results.

POST_001 - User is not authorised
ElementDetails
Scenario IDPOST_001
Scenario NameUser is not authorised
HTTP Code401
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
BUTUser does NOT have permissions
THENAPI is not reached; 401 Unauthorized response is returned
Example Error Message"Unauthorized."
POST_002 - File not sent with the request
ElementDetails
Scenario IDPOST_002
Scenario NameFile not sent with the request
HTTP Code400
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
BUTUser has not attached the JSON file into the call
THENAPI is not reached; 400 Bad Request response is returned
Example Error Message"File not present in MIME multipart content."
POST_003 - Hard limit exceeded: detail lines per order
ElementDetails
Scenario IDPOST_003
Scenario NameHard limit exceeded: detail lines per order
HTTP Code201
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
BUTOne or more sales orders in the file contain more detail lines than the configured hard limit
THEN201 Created is returned immediately; once the process finishes, the GET /v1/batch-operations/{batchRequestId}/status endpoint returns a processorResult of SuccessWithValidationErrors; the GET /v1/batch-operations/{batchRequestId}/results endpoint returns the failing sales orders with a per-order error message
Example Error Message Without SkipWorkflow"The number of detail lines per order exceeds the maximum allowed limit of 12."
Example Error Message With SkipWorkflow"The number of detail lines per order exceeds the maximum allowed limit of 1000."
POST_004 - Hard limit exceeded: database items per call
ElementDetails
Scenario IDPOST_004
Scenario NameHard limit exceeded: database items per call
HTTP Code201
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
BUTThe overall number of database items to be stored for the batch exceeds the configured hard limit
THEN201 Created is returned immediately; once the process finishes, the GET /v1/batch-operations/{batchRequestId}/status endpoint returns a processorResult of SuccessWithValidationErrors; the GET /v1/batch-operations/{batchRequestId}/results endpoint returns the failing sales orders with a per-order error message
Example Error Message Without SkipWorkflow"The number of items to be saved will exceed the maximum allowed limit of 37000."
Example Error Message With SkipWorkflow"The number of items to be saved will exceed the maximum allowed limit of 1550000."
POST_005 - Happy Path: all orders are valid
ElementDetails
Scenario IDPOST_005
Scenario NameHappy Path: all orders are valid
HTTP Code201
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
THEN201 Created is returned immediately with a URL to track the batch operation; once the process finishes, the GET /v1/batch-operations/{batchRequestId}/status endpoint returns a processorResult of Success; the GET /v1/batch-operations/{batchRequestId}/results endpoint returns an empty array by default; using the optional type=success parameter on the results endpoint returns an array of summarized DTOs for the orders that were stored
POST_006 - Partial success: some orders are invalid
ElementDetails
Scenario IDPOST_006
Scenario NamePartial success: some orders are invalid
HTTP Code201
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
BUTOne or more orders in the file contain validation errors (e.g., invalid customer, missing required field, invalid product)
THEN201 Created is returned immediately; once the process finishes, the GET /v1/batch-operations/{batchRequestId}/status endpoint returns a processorResult of SuccessWithValidationErrors, along with a validationErrorCount indicating how many orders failed and a processedItems value with the total number of orders processed; the GET /v1/batch-operations/{batchRequestId}/results endpoint returns only the failing orders with their specific per-order errors; using the optional type=success parameter on the results endpoint returns only the successfully created orders as summarized DTOs
POST_007 - Duplicate order number
ElementDetails
Scenario IDPOST_007
Scenario NameDuplicate order number
HTTP Code201
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API
BUTOne or more orders use a transaction type that requires manual order number assignment, and the specified order number already exists in the system
THEN201 Created is returned immediately; once the process finishes, the GET /v1/batch-operations/{batchRequestId}/status endpoint returns a processorResult of SuccessWithValidationErrors; the GET /v1/batch-operations/{batchRequestId}/results endpoint returns the failing sales orders with a per-order error message
Example Error Message"Order number in use !"
POST_008 - User does not have access to the specified company
ElementDetails
Scenario IDPOST_008
Scenario NameUser does not have access to the specified company
HTTP Code403
GIVENA batch of new sales orders needs to be created
WHENCalling the POST batch method of the API with a companyId URL parameter
BUTThe authenticated user does not have access to the specified company
THENThe request is rejected before the batch operation is processed, and a 403 Forbidden response is returned immediately
Example Error Message"User is not authorized"

   

   

Best Practices

  • Use the single-order endpoint for individual orders: If only one sales order needs to be created, use the synchronous POST /v1/sales-orders endpoint instead. Reserve the batch endpoint for scenarios where multiple sales orders need to be created at once.
  • Handle partial failures by checking results: When the GET /v1/batch-operations/{batchRequestId}/status endpoint reports failures, call GET /v1/batch-operations/{batchRequestId}/results to retrieve the list of sales orders that were not saved. Fix the reported errors and resubmit those orders in a new batch API call.
  • Use the same transactionType for all orders in a batch when possible: A known issue in the API can cause abnormal behavior in order number assignments when orders with different transactionType values are mixed within the same batch request. Where possible, group orders by transaction type and submit them in separate batch calls.

   

Action APIs


Query APIs (Read-Only)