Backend API: Create an order
Edit on GitHubThe orders resource of the Backend API lets Back Office integrations place a sales order from an intake payload. This document describes how to create an order and which validations the request has to pass.
Order intake does not reimplement checkout: the payload is assembled into a quote and handed to the same checkout flow the Storefront uses, so an API-placed order goes through the same pre-condition plugins, calculation, order-management bootstrapping, and mail as one placed by a customer.
Installation
The endpoints are provided by the OrderExperienceManagement module, which delegates to the existing Checkout, Sales, Oms, and pricing modules rather than reimplementing them. For details on installing it, see Install the Orders Backend API feature.
Create an order
To place an order, send the request:
POST /orders
Request
| HEADER KEY | HEADER VALUE | REQUIRED | DESCRIPTION |
|---|---|---|---|
| Authorization | string | ✓ | Alphanumeric string that authorizes the Back Office user to send requests to protected resources. Get it by authenticating as a Back Office user. |
Request sample: create an order for an existing customer
POST https://glue-backend.mysprykershop.com/orders
{
"data": {
"type": "orders",
"attributes": {
"customerReference": "DE--6",
"store": "DE",
"currency": "EUR",
"paymentMethod": "dummyPaymentInvoice",
"shipment": {
"shipmentMethod": "Standard",
"shippingAddress": {
"salutation": "Ms",
"firstName": "Ada",
"lastName": "Lovelace",
"address1": "Julie-Wolfthorn-Strasse",
"address2": "1",
"zipCode": "10115",
"city": "Berlin",
"iso2Code": "DE"
}
},
"billingAddress": {
"salutation": "Ms",
"firstName": "Ada",
"lastName": "Lovelace",
"address1": "Julie-Wolfthorn-Strasse",
"address2": "1",
"zipCode": "10115",
"city": "Berlin",
"iso2Code": "DE"
},
"items": [
{
"sku": "001_25904006",
"quantity": 1
}
]
}
}
}
| ATTRIBUTE | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
| customerReference | String | ✓ | Reference of the customer the order belongs to. Must reference an existing customer—intake never registers one. |
| store | String | ✓ | Store to place the order in. |
| currency | String | ✓ | ISO 4217 currency code. |
| paymentMethod | String | ✓ | Payment method key—for example, dummyPaymentInvoice—not the display name. For an order with no payment charged, use the platform’s zero-payment method key—for example, Nopayment. |
| billingAddress | Object | ✓ | Billing address. Give uuid to reference one of the customer’s saved addresses, or supply firstName, lastName, zipCode, city, and iso2Code inline. |
| billingAddress.uuid | String | Reference to one of the customer’s saved addresses; must belong to the order’s customer. The other billingAddress fields are ignored when set. |
|
| billingAddress.iso2Code | String | ISO 3166-1 alpha-2 country code. | |
| shipment | Object | ✓ | Default delivery for every item that doesn’t override it with its own shipment. |
| shipment.shipmentMethod | String | ✓ | Shipment method name applied to every item that doesn’t override it. |
| shipment.shippingAddress | Object | ✓ | Delivery address for the order. Same shape as billingAddress. Individual lines can override this with items.shipment.shippingAddress. |
| shipment.requestedDeliveryDate | String | Requested delivery date applied to every item that doesn’t override it. | |
| items | Array | ✓ | Order line items. At least one is required. |
| items.sku | String | ✓ | Concrete product SKU. |
| items.quantity | Integer | Ordered quantity, in the product’s base measurement unit. Required, except when items.salesUnit.amount is supplied—the quantity is then derived from it, and must either be omitted or match what it derives to. |
|
| items.salesUnit | Object | The measurement unit the line is ordered in—“2 metres” rather than “200 base units”. Omit it for a product sold in base units. | |
| items.salesUnit.code | String | Measurement unit code—for example, METR, KILO. Must be a unit the line’s product is sold in, and available in the order’s store. |
|
| items.salesUnit.amount | Number | How many of code are ordered. The base-unit quantity is derived as amount * conversion; the order is rejected when that is not a whole number of base units. Omit it to supply quantity directly instead. |
|
| items.unitCustomPrice | Integer | Unit price in cents to charge instead of the resolved catalog price—a deliberate admin capability, and the required override when the catalog has no price for the line at all (see Price resolution below). Omitted lines are priced from the catalog. | |
| items.merchantReference | String | Merchant fulfilling the line, for a marketplace line. Supply with sku; omit for an operator-sold line. |
|
| items.productOfferReference | String | The specific offer to buy, when a merchant holds several offers for the SKU. | |
| items.cartNote | String | Free-text note carried on the line. | |
| items.packagingAmount | Object | For a product sold as a package, how much of the contained product the package holds. Omit it to order the package’s configured default amount, and omit the whole object for a product that isn’t sold as a package. | |
| items.packagingAmount.amount | Number | Amount per package, not for the whole line—3 boxes of 250 is quantity: 3 with packagingAmount.amount: 250. Must respect the package’s configured minimum, maximum, and step, and can differ from the default only when the package allows a variable amount. |
|
| items.packagingAmount.salesUnitCode | String | Measurement unit the amount is expressed in—a unit of the contained product, not of the package itself. Defaults to the contained product’s default unit when omitted. | |
| items.productOptions | Array | Product options selected for the line, as [{"sku": "..."}]. Options are per line, so the same product ordered twice with different options is two lines. |
|
| items.productOptions.sku | String | Product option SKU. The option must be active, offered for the line’s product, and priced in the order’s store and currency. | |
| items.shipment | Object | Per-line delivery override. Same shape as the order-level shipment. Falls back to the order-level shipment when omitted. |
|
| orderCustomReference | String | The caller’s own reference for the order—for example, a purchase-order number or EDI document ID. Shown in the Back Office. | |
| companyBusinessUnitUuid | String | Business unit to place the order for. Selects which merchant-relationship contract prices apply, and is recorded on the order. Must be one the order’s customer belongs to through an active company user. Resolved automatically when the customer belongs to exactly one business unit, and required when they belong to several. | |
| priceMode | String | Whether submitted unit prices are gross or net: GROSS_MODE or NET_MODE. Default: GROSS_MODE. |
|
| locale | String | Locale to place the order in—for example, de_DE. Also selects the language of the order-confirmation email. Falls back to whatever checkout resolves by default when omitted. Must be a locale known to the platform. |
|
| cartCodes | Array | Codes to apply to the order at placement—gift cards, vouchers, or any other code a registered cart-code plugin resolves. Every code must actually apply: one that is unknown, inactive, or not applicable to this order rejects the whole request with a 422 rather than being dropped from it. See payments in the response for how much a redeemed gift card actually covered. |
Passing companyBusinessUnitUuid also decides whose place-order permission is checked. Naming a business unit whose company user lacks that permission gets the order rejected as requiring approval, even though the named business unit is a valid one for the customer.
Price resolution
Each line is priced individually, and “the product’s own price” is not one fixed number—it depends on who is buying:
- When
companyBusinessUnitUuidis set, the price is looked up in that business unit’s merchant-relationship contract prices first. Different business units can be entitled to different negotiated prices for the same SKU, store, and currency. - Otherwise, the standard catalog price for the order’s store and currency applies.
priceMode selects whether the resolved figure is read as gross or net; it does not change which price list is consulted.
When the catalog has no price for a line at all—in the resolved business unit’s contract or, absent one, the standard price list—the item is rejected rather than defaulted to zero, unless you supply items.unitCustomPrice for it. See items[<index>].unitCustomPrice in Possible errors.
Response
The response contains the created order in the same shape as retrieving a single order, except comments is always empty—a freshly placed order has none yet.
Response sample: create an order
{
"data": {
"id": "DE--1235",
"type": "orders",
"attributes": {
"orderReference": "DE--1235",
"customerReference": "DE--6",
"store": "DE",
"currency": "EUR",
"createdAt": "2026-09-04 09:12:31",
"priceMode": "GROSS_MODE",
"itemsCount": 1,
"itemStates": ["new"],
"availableEvents": ["ship", "cancel"],
"customer": {
"email": "[email protected]",
"salutation": "Ms",
"firstName": "Ada",
"lastName": "Lovelace"
},
"totals": {
"subtotal": 34500,
"expenseTotal": 490,
"discountTotal": 0,
"taxTotal": 4658,
"taxBreakdown": [],
"grandTotal": 29176,
"canceledTotal": 0,
"refundableTotal": 29176,
"remunerationTotal": 0
},
"expenses": [
{
"type": "SHIPMENT_EXPENSE_TYPE",
"name": "Standard",
"sumPrice": 490,
"taxRate": 19,
"sumTaxAmount": 78,
"sumDiscountAmountAggregation": 0,
"sumPriceToPayAggregation": 490,
"canceledAmount": 0
}
],
"calculatedDiscounts": [],
"payments": [
{
"paymentProvider": "DummyPayment",
"paymentMethod": "dummyPaymentInvoice",
"amount": 29176,
"meta": {}
}
],
"items": [
{
"uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"sku": "001_25904006",
"name": "Canon PowerShot SC620",
"quantity": 1,
"unitPrice": 34500,
"sumPrice": 34500,
"taxRate": 19,
"sumTaxAmount": 4658,
"refundableAmount": 29176,
"canceledAmount": 0,
"calculatedDiscounts": [],
"sumSubtotalAggregation": 34500,
"sumDiscountAmountFullAggregation": 0,
"sumPriceToPayAggregation": 29176,
"state": "new",
"availableEvents": ["ship", "cancel"]
}
],
"comments": []
},
"links": {
"self": "https://glue-backend.mysprykershop.com/orders/DE--1235"
}
}
}
| ATTRIBUTE | TYPE | DESCRIPTION |
|---|---|---|
| orderReference | String | Sales order reference. Identifies the order everywhere—for example, GET /orders/{orderReference}—and is also the resource id. |
| customerReference | String | Reference of the customer the order belongs to. |
| store | String | Store the order was placed in. |
| currency | String | ISO 4217 currency code. |
| createdAt | String | ISO 8601 creation timestamp. |
| orderCustomReference | String | The caller’s own reference for the order, if one was supplied at creation—for example, a purchase-order number. Shown in the Back Office. |
| companyBusinessUnitUuid | String | Business unit the order was placed for, if any. |
| companyUuid | String | Company the order was placed for. Derived from companyBusinessUnitUuid at placement; absent for an order placed by a customer with no company user. |
| priceMode | String | Whether the order’s unit prices are gross or net: GROSS_MODE or NET_MODE. |
| locale | String | Locale the order was placed in—for example, de_DE. |
| itemsCount | Integer | Number of line items on the order (line count, not ordered units). Always present, even when items itself is omitted. |
| itemStates | Array | Distinct OMS state names currently held by the order’s items. An order has no state of its own—its items advance independently. |
| availableEvents | Array | OMS events an operator can currently trigger on the order—the union over its line items. items[].availableEvents says which lines each one applies to. Empty when every item is in a terminal state. |
| customer | Object | Read-only snapshot of the buyer, taken when the order was placed—not a live customer lookup. |
| customer.email | String | Email recorded on the order. |
| customer.salutation | String | Salutation recorded on the order: Mr, Mrs, Dr, Ms, or n/a. |
| customer.firstName | String | First name recorded on the order. |
| customer.lastName | String | Last name recorded on the order. |
| totals | Object | Order totals, in cents, using the same keys as the Storefront orders API. |
| totals.subtotal | Integer | Sum of item prices before discounts, expenses, or tax, in cents. |
| totals.expenseTotal | Integer | Total expenses (shipment, order-threshold surcharges), in cents. See expenses for the breakdown. |
| totals.discountTotal | Integer | Total discount applied across the order, in cents. See calculatedDiscounts for the breakdown. |
| totals.taxTotal | Integer | Total tax across the order, in cents. See totals.taxBreakdown for the per-rate detail. |
| totals.taxBreakdown | Array | taxTotal split by rate, since an order can mix rates. Empty on the response to POST /orders; present once the order is read back. |
| totals.taxBreakdown.taxRate | Number | The rate, in percent. |
| totals.taxBreakdown.taxAmount | Integer | Tax charged at this rate across the whole order, in cents. |
| totals.grandTotal | Integer | subtotal - discountTotal + expenseTotal + tax. What the order was placed at, in cents. |
| totals.canceledTotal | Integer | Value of the order’s canceled items, in cents. |
| totals.refundableTotal | Integer | Amount still refundable on the order, in cents—not what has already been refunded. Starts at the grand total and falls as parts of the order are canceled. |
| totals.remunerationTotal | Integer | Amount settled by remuneration rather than payment, in cents. |
| expenses | Array | Shipment and surcharge lines that make up totals.expenseTotal. |
| expenses.type | String | Expense type—for example, SHIPMENT_EXPENSE_TYPE. |
| expenses.name | String | Display name—for example, the shipment method name. |
| expenses.sumPrice | Integer | Expense price in cents before discounts. |
| expenses.taxRate | Number | Tax rate applied to the expense, in percent. |
| expenses.sumTaxAmount | Integer | Tax charged on the expense, in cents. |
| expenses.sumDiscountAmountAggregation | Integer | Discount applied to the expense, in cents—a free-delivery rule shows here. |
| expenses.sumPriceToPayAggregation | Integer | What the expense actually costs after discounts, in cents. |
| expenses.canceledAmount | Integer | Canceled portion of the expense, in cents. |
| calculatedDiscounts | Array | Rules and vouchers applied to the order, one entry per discount with its total across the order. Per-line amounts are on items[].calculatedDiscounts. |
| calculatedDiscounts.displayName | String | Name of the discount as configured. Entries sharing a display name are grouped into one. |
| calculatedDiscounts.description | String | Description of the discount as configured. |
| calculatedDiscounts.voucherCode | String | The voucher code that triggered the discount. null for a cart rule. On a grouped entry, reflects only one of the merged discounts. |
| calculatedDiscounts.quantity | Integer | Ordered units the discount applied to, totaled across every line it applied to. |
| calculatedDiscounts.sumAmount | Integer | Discount total across the order, in cents, including any part applied to shipping or product options. |
| payments | Array | How the order was actually charged, one row per payment method used. |
| payments.paymentProvider | String | Payment provider key—for example, DummyPayment or GiftCard. |
| payments.paymentMethod | String | Payment method key—for example, dummyPaymentInvoice or GiftCard. |
| payments.amount | Integer | Amount charged to this payment method, in cents. |
| payments.meta | Object | Free-form, method-specific data for this payment—for example, giftCard carrying the redeemed code and its value. Only properties actually populated for this payment appear. |
| comments | Array | Back Office comments on the order, oldest first—the same thread retrieved and appended to via the order-comments resource. Included only on the single-order response; omitted from the order collection response. |
| ATTRIBUTE | TYPE | DESCRIPTION |
|---|---|---|
| items.uuid | String | Public identifier of the line item, and the value every other endpoint addresses a line by—for example, itemUuids on firing an OMS event. The internal ID is never exposed. |
| items.sku | String | Concrete product SKU. |
| items.name | String | Product name, snapshotted onto the line at order time. |
| items.quantity | Integer | Ordered quantity, in the product’s base measurement unit. |
| items.salesUnit | Object | The measurement unit the line is ordered in—for example, “2 metres” rather than “200 base units”. Absent for a product sold in base units. |
| items.salesUnit.code | String | Measurement unit code—for example, METR, KILO. |
| items.salesUnit.amount | Number | How many of code are ordered. |
| items.salesUnit.name | String | Measurement unit name, snapshotted onto the line at order time. |
| items.salesUnit.baseUnitName | String | Name of the base unit quantity is expressed in. |
| items.salesUnit.conversion | Number | Base units per one code. quantity = amount * conversion. |
| items.salesUnit.precision | Integer | Smallest fraction of code that can be ordered, as a divisor. |
| items.unitPrice | Integer | Unit price actually charged, in cents. |
| items.merchantReference | String | Merchant fulfilling the line, for a marketplace line. |
| items.productOfferReference | String | The specific offer the line was bought from, if the merchant holds several offers for the SKU. |
| items.cartNote | String | Free-text note carried on the line. |
| items.packagingAmount | Object | For a product sold as a package, how much of the contained product the line’s packages hold. Absent for a product that is not sold as a package. |
| items.packagingAmount.amount | Number | Amount per package, not for the whole line—3 boxes of 250 is quantity: 3 with amount: 250. |
| items.packagingAmount.salesUnitCode | String | Measurement unit the amount is expressed in—a unit of the contained product, not of the package itself. |
| items.packagingAmount.salesUnitName | String | Name of the unit the amount is expressed in. |
| items.packagingAmount.leadProductSku | String | SKU of the product contained in the package. |
| items.productOptions | Array | Product options selected for the line. |
| items.productOptions.groupName | String | Option group name, snapshotted onto the line at order time. |
| items.productOptions.value | String | The selected option value, snapshotted at order time. |
| items.productOptions.unitPrice | Integer | Option surcharge per unit, in cents. |
| items.productOptions.sumPrice | Integer | Option surcharge across all units of the line, in cents. Included in items.sumSubtotalAggregation. |
| items.productOptions.taxRate | Number | Tax rate applied to the option, in percent. |
| items.shipment | Object | Per-line delivery override. Falls back to the order-level shipment when absent. |
| items.shipment.shipmentMethod | String | Shipment method name for the line. |
| items.shipment.shippingAddress | Object | Delivery address for the line. Same shape as the order-level shipment.shippingAddress. |
| items.shipment.requestedDeliveryDate | String | Requested delivery date for the line. |
| items.sumPrice | Integer | Line price in cents before discounts. |
| items.taxRate | Number | Tax rate applied to the line, in percent. |
| items.sumTaxAmount | Integer | Tax charged on the line, in cents. |
| items.refundableAmount | Integer | Amount still refundable on the line, in cents. |
| items.canceledAmount | Integer | Canceled portion of the line, in cents. |
| items.calculatedDiscounts | Array | Rules and vouchers applied to the line. The order-level calculatedDiscounts reports the same discounts totaled per discount. |
| items.calculatedDiscounts.displayName | String | Name of the discount as configured. |
| items.calculatedDiscounts.voucherCode | String | The voucher code that triggered the discount. null for a cart rule. |
| items.calculatedDiscounts.unitAmount | Integer | Discount per unit, in cents. Rounded for display—use sumAmount for any calculation. |
| items.calculatedDiscounts.sumAmount | Integer | Discount for the line, in cents. |
| items.sumSubtotalAggregation | Integer | Line subtotal in cents. |
| items.sumDiscountAmountFullAggregation | Integer | Discount applied to the line, in cents. |
| items.sumPriceToPayAggregation | Integer | What the line actually costs after discounts, in cents. |
| items.state | String | Current OMS state of the item. |
| items.availableEvents | Array | Events an operator can currently trigger on this line item. This is the per-line detail behind the order-level availableEvents, which reports the union over all lines. Empty when the item sits in a terminal state. Returned only by retrieving a single order—the collection endpoint omits items entirely. |
Possible errors
The request is validated as a whole: if any check fails, nothing is created and all failed checks are returned in the errors array, each detail naming the offending field path—for example, items[1].sku => Product with SKU "nope" was not found..
| STATUS | CODE | REASON |
|---|---|---|
| 422 | 901 | A required attribute is missing, is blank, or has a wrong type—for example, customerReference => This value should not be blank.. |
| 422 | N/A | The customer referenced by customerReference doesn’t exist. |
| 422 | N/A | companyBusinessUnitUuid doesn’t belong to the named customer, or the customer’s company user lacks the place-order permission for it. |
| 422 | N/A | A line item’s sku doesn’t exist, or isn’t available in the order’s store. |
| 422 | N/A | The catalog has no price for a line’s sku in the resolved price list, store, and currency—for example, items[1].unitCustomPrice => No price found for "001_25904006" in DE EUR. Send a unitCustomPrice to override.. Supply items.unitCustomPrice for that line. |
| 422 | N/A | A line item’s productOptions.sku doesn’t exist, isn’t offered for the product, or isn’t priced in the order’s store and currency. |
| 422 | N/A | A line item’s salesUnit.code isn’t a unit the product is sold in, or salesUnit.amount doesn’t derive to a whole number of base units. |
| 422 | N/A | A line item’s packagingAmount.amount violates the package’s configured minimum, maximum, or step. |
| 422 | N/A | A referenced address uuid doesn’t belong to the order’s customer. |
| 422 | N/A | A cartCodes entry didn’t apply—the code is unknown, inactive, or not applicable to this order. The order isn’t placed; resend without the code, or with one that applies. |
| 401 | N/A | The Authorization header is missing, or the access token is invalid or expired. |
| 403 | N/A | The authenticated Back Office user is not allowed to access the orders resource. |
Checkout errors are translated into the caller’s Accept-Language where a glossary translation exists. Use the standard hyphenated form—Accept-Language: de-DE or Accept-Language: de. An underscored value such as de_DE isn’t valid in this header and silently falls back to the default locale.
To view generic errors and status codes of the Backend API, see Backend API request and response reference.
Thank you!
For submitting the form