Orders
Create orders from your app, check an order without creating it, read an order of your shop or change it.
Create an order
/orders
Scope: orders.write
Creates an order from your app. The order is created in the shop assigned to your API client.
Duplicate protection. external_order_id is unique per API client. Sending the same
number again never creates a second order, not even for two simultaneous requests. The repeat
answers 200 with duplicate: true and the current state of the existing order. After a
connection error, a timeout, 429 or 5xx, resend the unchanged request (doubling the wait,
for example 2, 4, 8 seconds; respect Retry-After on 429). Do not resend unchanged after
422 or 409.
Customer matching.
- Our customer number (
customer.customer_id) of an active, registered customer in your shop, or your customer ID (customer.external_id) if it was used before through your client: the order goes to that customer. Only the ID is then needed; the email comes from the stored customer, the billing address is the customer's default billing address (the one marked as default for invoices in the address book, otherwise the main customer address). Abillingsent anyway applies to this order only and does not change the stored customer. - Email: only if the shop operator enabled matching by email for your client and you send
email_verified: true. Then a registered, active customer with this email in your shop is used. Guest and blocked customers are never matched. Sendemail_verified: trueonly for emails you actually confirmed. - Otherwise a new customer is created.
Prices. A sent unit_price_gross is used as a fixed price; without it, the shop's own
price applies. A customer class discount may apply to the order, also to sent prices, so the
grand_total_gross in the response is authoritative. A sent shipping_cost_gross applies
(also 0); without it, shipping costs are calculated by the shop's rules.
After creation. The order starts in the shop's incoming order status, or directly in the
status you send as order_status_id. Stock is reserved and the shop's usual processes start
(confirmation email, payment, shipping). Orders sent with a test key (omn_test_...) are created
normally and marked as test orders.
Guarantee. If the response is an error, nothing was created: no order and no customer.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
external_order_id | string | required | Your order number. Unique per API client and case-sensitive. The same number never creates a second order. max length 191 |
ordered_at | string | null | optional | Time of the order. Use ISO 8601 with a time zone (Z or +02:00). Must not be in the future
and at most 30 days in the past. Without it, the time of receipt is used. |
payment_method_id | integer | required | ID of a payment method from listPaymentMethods. Any other ID is rejected with
payment_method_not_available (or unknown_payment_method if it is not active). For the
collective invoice, the customer must also be approved for it. |
referrer_id | integer | null | optional | ID of a referrer (order origin). Must be active and assigned to the shop of your API client
(see listReferrers). Without it, the default referrer of your API client is used. |
order_status_id | integer | null | optional | ID of an order status from listOrderStatuses. The order is created directly in this
status; every status of the shop is accepted, including cancelled and shipped statuses.
Without it, the order starts in the shop's incoming order status. Any other ID is rejected
with unknown_order_status. |
currency | string | required | Currency code. Only EUR is supported. one of: EUR · min length 3 · max length 3 |
comment | string | null | optional | Message of the customer about the order. max length 2000 |
shipping_cost_gross | number | null | optional | Shipping costs including tax, at most 2 decimal places. If sent, it applies (also 0). If
missing, shipping costs are calculated by the shop's rules. min 0 · max 999999.99 · multiple of 0.01 |
customer | object | required | The customer of the order. For an existing customer, the ID alone is
enough ({"external_id": "u-55871"} or {"customer_id": 9021}). For a new customer, email and
billing are required. |
external_id | string | null | optional | Your customer ID. Required unless customer_id is sent. Case-sensitive; the same ID always leads to the same customer. max length 191 |
customer_id | integer | null | optional | Our customer number, for example from data.customer_id of an earlier response or given to
you by the shop operator. Any active, registered customer of your shop can be referenced;
guest, blocked or deleted customers and customers of other shops fail with unknown_customer.
Referencing a customer by number does not link your external_id to it. min 1 |
id | integer | null | optional | Same as customer_id. If both are sent, they must have the same value, otherwise the request
fails with invalid_value on customer.id. Errors about the customer number are reported on
customer.customer_id. min 1 |
email | string (email) | null | optional | Email address. Required for a new customer. max length 191 |
email_verified | boolean | null | optional | true if you confirmed the email (for example by a link). Only then can the order be matched
to an existing customer by email, and only if the shop operator enabled this for your client. default false |
telephone | string | null | optional | Phone number. max length 191 |
billing | object | null | optional | Billing address. Required for a new customer. For a known customer it applies to this order only; the stored customer is not changed. |
shipping | object | null | optional | Delivery address. If missing, null or {}, the order is delivered to the billing address.
A sent delivery address is stored in the order and added to the customer's address book (the
same address only once). |
items[] | array of object | required | Order items, 1 to 200. min 1 items · max 200 items |
sku | string | null | optional | Our article number. Not case-sensitive. max length 191 |
article_id | integer | null | optional | Our number of the main article. All variants of an article (for example sizes) share this
number; for articles with variants use sku. min 1 |
quantity | integer | required | min 1 · max 9999 |
unit_price_gross | number | null | optional | Unit price including tax, at most 2 decimal places. If sent, it is used as a fixed price; if missing, the shop's price applies. min 0 · max 999999.99 · multiple of 0.01 |
Example request
curl -X POST "https://shop.example.com/api/v1/orders" \
-H "Authorization: Bearer $API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"external_order_id": "APP-100234",
"ordered_at": "2026-10-14T12:05:00Z",
"payment_method_id": 3,
"referrer_id": 17,
"currency": "EUR",
"comment": "Please ring the bell",
"shipping_cost_gross": 4.9,
"customer": {
"external_id": "u-55871",
"email": "alex.sample@example.com",
"email_verified": true,
"telephone": "+49 30 0000000",
"billing": {
"salutation": "Mr",
"first_name": "Alex",
"last_name": "Sample",
"street": "Sample Street",
"house": "5",
"additional": "2nd floor",
"postcode": "10115",
"city": "Berlin",
"country": "DE"
},
"shipping": {
"first_name": "Alex",
"last_name": "Sample",
"street": "Packstation",
"house": "123",
"postcode": "10117",
"city": "Berlin",
"country": "DE",
"telephone": "+49 170 0000000",
"packstation": true,
"postnumber": "12345678"
}
},
"items": [
{
"sku": "SAMPLE-1KG",
"quantity": 2,
"unit_price_gross": 29.9
},
{
"article_id": 101683,
"quantity": 1
}
]
}' Responses
200 OK An order with this external_order_id already exists. Nothing new was created; data
shows the existing order with duplicate: true, and warnings is empty.
{
"data": {
"id": 48211,
"order_number": "48211",
"external_order_id": "APP-100234",
"duplicate": true,
"customer_id": 9021,
"customer_created": false,
"status_id": 1,
"status": "Incoming order",
"payment_method_id": 3,
"referrer_id": 17,
"shipping_method_id": 4,
"shipping_method": "Parcel",
"shipping_cost_gross": 4.9,
"shipping_cost_source": "app",
"items": [
{
"sku": "SAMPLE-1KG",
"quantity": 2,
"unit_price_gross": 29.9,
"price_source": "app"
}
],
"grand_total_gross": 64.7,
"currency": "EUR"
},
"warnings": []
} Response fields
| Field | Type | Required | Description |
|---|---|---|---|
data | object | required | |
id | integer | required | Our order number. Store it on your side. |
order_number | string | required | Our order number as text (same value as id). |
external_order_id | string | required | Your order number. |
duplicate | boolean | required | true if the order already existed and nothing new was created. |
customer_id | integer | required | Our customer number. Can be sent as customer.customer_id in later orders. |
customer_created | boolean | required | true if a new customer was created for this order. |
status_id | integer | required | ID of the order status. |
status | string | required | Name of the order status as named in the shop. |
payment_method_id | integer | required | |
referrer_id | integer | null | required | |
shipping_method_id | integer | null | required | Shipping method chosen by the shop's rules; null if none matched (then a no_shipping_method warning is given). |
shipping_method | string | null | required | Name of the shipping method; null if none matched. |
shipping_cost_gross | number | required | Shipping costs including tax. |
shipping_cost_source | string | required | app = your value, system = calculated by the shop. one of: app, system |
items[] | array of object | required | |
sku | string | required | Our article number. |
quantity | integer | required | |
unit_price_gross | number | required | Unit price including tax. |
price_source | string | required | app = your price, system = the shop's price. one of: app, system |
grand_total_gross | number | required | Total of the order including tax. This value is authoritative. |
currency | string | required | |
warnings[] | array of object | required | Always present. Empty means everything is fine. Always empty for a duplicate. |
code | string | required | - no_shipping_method: no shipping method matched; the order was created without one and the
shop operator sets it by hand.
- customer_already_linked: the customer was found by email, but is already linked to a
different customer ID of your app.
- collective_invoice_single_order: the order uses the collective invoice, but its billing
address differs from the address stored for the customer. The order is created and
invoiced on its own, not on the collective invoice.
- status_not_changed (updateOrder): the status could not be changed because of an
unexpected error. All other changes of the request were saved; the order shows its old
status. Send order_status_id again, or pass reference to the shop operator. one of: no_shipping_method, customer_already_linked, collective_invoice_single_order, status_not_changed |
message | string | required | Human-readable English text. It may change; evaluate code instead. |
reference | string | optional | Only with status_not_changed. Identifies the case in our log. |
201 Created The order was created.
{
"data": {
"id": 48211,
"order_number": "48211",
"external_order_id": "APP-100234",
"duplicate": false,
"customer_id": 9021,
"customer_created": true,
"status_id": 1,
"status": "Incoming order",
"payment_method_id": 3,
"referrer_id": 17,
"shipping_method_id": 4,
"shipping_method": "Parcel",
"shipping_cost_gross": 4.9,
"shipping_cost_source": "app",
"items": [
{
"sku": "SAMPLE-1KG",
"quantity": 2,
"unit_price_gross": 29.9,
"price_source": "app"
},
{
"sku": "SAMPLE-SHAKER",
"quantity": 1,
"unit_price_gross": 5,
"price_source": "system"
}
],
"grand_total_gross": 69.7,
"currency": "EUR"
},
"warnings": []
} Response fields
| Field | Type | Required | Description |
|---|---|---|---|
data | object | required | |
id | integer | required | Our order number. Store it on your side. |
order_number | string | required | Our order number as text (same value as id). |
external_order_id | string | required | Your order number. |
duplicate | boolean | required | true if the order already existed and nothing new was created. |
customer_id | integer | required | Our customer number. Can be sent as customer.customer_id in later orders. |
customer_created | boolean | required | true if a new customer was created for this order. |
status_id | integer | required | ID of the order status. |
status | string | required | Name of the order status as named in the shop. |
payment_method_id | integer | required | |
referrer_id | integer | null | required | |
shipping_method_id | integer | null | required | Shipping method chosen by the shop's rules; null if none matched (then a no_shipping_method warning is given). |
shipping_method | string | null | required | Name of the shipping method; null if none matched. |
shipping_cost_gross | number | required | Shipping costs including tax. |
shipping_cost_source | string | required | app = your value, system = calculated by the shop. one of: app, system |
items[] | array of object | required | |
sku | string | required | Our article number. |
quantity | integer | required | |
unit_price_gross | number | required | Unit price including tax. |
price_source | string | required | app = your price, system = the shop's price. one of: app, system |
grand_total_gross | number | required | Total of the order including tax. This value is authoritative. |
currency | string | required | |
warnings[] | array of object | required | Always present. Empty means everything is fine. Always empty for a duplicate. |
code | string | required | - no_shipping_method: no shipping method matched; the order was created without one and the
shop operator sets it by hand.
- customer_already_linked: the customer was found by email, but is already linked to a
different customer ID of your app.
- collective_invoice_single_order: the order uses the collective invoice, but its billing
address differs from the address stored for the customer. The order is created and
invoiced on its own, not on the collective invoice.
- status_not_changed (updateOrder): the status could not be changed because of an
unexpected error. All other changes of the request were saved; the order shows its old
status. Send order_status_id again, or pass reference to the shop operator. one of: no_shipping_method, customer_already_linked, collective_invoice_single_order, status_not_changed |
message | string | required | Human-readable English text. It may change; evaluate code instead. |
reference | string | optional | Only with status_not_changed. Identifies the case in our log. |
Error responses
401 Unauthorized The API key is missing, malformed, wrong, paused, expired or revoked. The body is always the same and never names the reason.
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key.",
"details": []
}
} 403 Forbidden The API key is valid but lacks a scope this endpoint needs. details.required lists the scopes
the endpoint requires, details.missing the ones your key lacks. Ask the shop operator to add
the scope.
{
"error": {
"code": "insufficient_scope",
"message": "The API key is missing a required scope.",
"details": {
"required": [
"orders.write"
],
"missing": [
"orders.write"
]
}
}
} 404 Not Found The path does not exist, the API is not enabled on this system, the order does not belong to the shop of your API client, or the customer, address or label value is not known to your API client.
{
"error": {
"code": "not_found",
"message": "The requested resource does not exist.",
"details": []
}
} 409 Conflict An order existed for this external_order_id, but it was deleted in the meantime. Do not retry.
{
"error": {
"code": "order_deleted",
"message": "Order 48211 was created for this external order ID and has since been deleted.",
"details": []
}
} 422 Unprocessable Content The order was not accepted. Nothing was created.
- validation_failed: the order data is invalid. details lists every problem at once: per
field a list of {code, message}. Field names use dots, for example items.1.sku is the field
sku of the second item (counting from 0).
- client_not_configured: your API client is not fully set up (no shop, deleted shop, or its
default referrer is inactive or not assigned to the shop). Contact the shop operator.
{
"error": {
"code": "validation_failed",
"message": "The order was not created.",
"details": {
"items.1.sku": [
{
"code": "unknown_article",
"message": "Article 'SAMPLE-XYZ' is not known."
}
],
"payment_method_id": [
{
"code": "unknown_payment_method",
"message": "Payment method 99 does not exist or is inactive."
}
]
}
}
} 429 Too Many Requests Too many requests. Either your API client used up its requests per minute
(message Too many requests., with all rate limit headers), or too many failed authentications
came in a short time (message Too many authentication attempts., only Retry-After). Both
carry the code rate_limited.
{
"error": {
"code": "rate_limited",
"message": "Too many requests.",
"details": []
}
} 500 Internal Server Error An unexpected error occurred; the order was not created. details.reference identifies the
case. Resend the unchanged request later; if the error persists, give the reference to the shop
operator.
{
"error": {
"code": "server_error",
"message": "An unexpected error occurred. The order was not created.",
"details": {
"reference": "3f2a9c1e-7b4d-4e8a-9f61-2d5c8b0a7e13"
}
}
} All error codes: error code reference.
Check an order without creating it
/orders/validate
Scope: orders.write
Takes the same body as POST /orders and applies the same rules and error codes, but creates
nothing: no order, no customer, no stock reservation. Useful during development.
The response shows how the order would be resolved. Prices, shipping method and totals are only
calculated when the order is really created. A customer that would be matched by email and a
customer that would be created both appear as new_or_email without a customer ID; which of
the two applies is only decided when the order is created.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
external_order_id | string | required | Your order number. Unique per API client and case-sensitive. The same number never creates a second order. max length 191 |
ordered_at | string | null | optional | Time of the order. Use ISO 8601 with a time zone (Z or +02:00). Must not be in the future
and at most 30 days in the past. Without it, the time of receipt is used. |
payment_method_id | integer | required | ID of a payment method from listPaymentMethods. Any other ID is rejected with
payment_method_not_available (or unknown_payment_method if it is not active). For the
collective invoice, the customer must also be approved for it. |
referrer_id | integer | null | optional | ID of a referrer (order origin). Must be active and assigned to the shop of your API client
(see listReferrers). Without it, the default referrer of your API client is used. |
order_status_id | integer | null | optional | ID of an order status from listOrderStatuses. The order is created directly in this
status; every status of the shop is accepted, including cancelled and shipped statuses.
Without it, the order starts in the shop's incoming order status. Any other ID is rejected
with unknown_order_status. |
currency | string | required | Currency code. Only EUR is supported. one of: EUR · min length 3 · max length 3 |
comment | string | null | optional | Message of the customer about the order. max length 2000 |
shipping_cost_gross | number | null | optional | Shipping costs including tax, at most 2 decimal places. If sent, it applies (also 0). If
missing, shipping costs are calculated by the shop's rules. min 0 · max 999999.99 · multiple of 0.01 |
customer | object | required | The customer of the order. For an existing customer, the ID alone is
enough ({"external_id": "u-55871"} or {"customer_id": 9021}). For a new customer, email and
billing are required. |
external_id | string | null | optional | Your customer ID. Required unless customer_id is sent. Case-sensitive; the same ID always leads to the same customer. max length 191 |
customer_id | integer | null | optional | Our customer number, for example from data.customer_id of an earlier response or given to
you by the shop operator. Any active, registered customer of your shop can be referenced;
guest, blocked or deleted customers and customers of other shops fail with unknown_customer.
Referencing a customer by number does not link your external_id to it. min 1 |
id | integer | null | optional | Same as customer_id. If both are sent, they must have the same value, otherwise the request
fails with invalid_value on customer.id. Errors about the customer number are reported on
customer.customer_id. min 1 |
email | string (email) | null | optional | Email address. Required for a new customer. max length 191 |
email_verified | boolean | null | optional | true if you confirmed the email (for example by a link). Only then can the order be matched
to an existing customer by email, and only if the shop operator enabled this for your client. default false |
telephone | string | null | optional | Phone number. max length 191 |
billing | object | null | optional | Billing address. Required for a new customer. For a known customer it applies to this order only; the stored customer is not changed. |
shipping | object | null | optional | Delivery address. If missing, null or {}, the order is delivered to the billing address.
A sent delivery address is stored in the order and added to the customer's address book (the
same address only once). |
items[] | array of object | required | Order items, 1 to 200. min 1 items · max 200 items |
sku | string | null | optional | Our article number. Not case-sensitive. max length 191 |
article_id | integer | null | optional | Our number of the main article. All variants of an article (for example sizes) share this
number; for articles with variants use sku. min 1 |
quantity | integer | required | min 1 · max 9999 |
unit_price_gross | number | null | optional | Unit price including tax, at most 2 decimal places. If sent, it is used as a fixed price; if missing, the shop's price applies. min 0 · max 999999.99 · multiple of 0.01 |
Example request
curl -X POST "https://shop.example.com/api/v1/orders/validate" \
-H "Authorization: Bearer $API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"external_order_id": "APP-100235",
"payment_method_id": 3,
"currency": "EUR",
"customer": {
"external_id": "u-55871"
},
"items": [
{
"sku": "SAMPLE-1KG",
"quantity": 2
}
]
}' Responses
200 OK The order is valid and would be accepted.
{
"data": {
"valid": true,
"duplicate": false,
"order_id": null,
"resolved": {
"customer": {
"match": "existing",
"customer_id": 9021
},
"items": [
{
"variation_id": 3311,
"sku": "SAMPLE-1KG",
"article_id": 812,
"quantity": 2,
"price_source": "system"
}
],
"payment_method_id": 3,
"referrer_id": 17,
"order_status_id": 1,
"shipping_cost_source": "system"
},
"warnings": []
}
} Response fields
| Field | Type | Required | Description |
|---|---|---|---|
data | object | required | |
valid | boolean | required | Always true in a 200 response; invalid orders answer 422. always true |
duplicate | boolean | required | true if an order already exists for this external_order_id. |
order_id | integer | null | required | Our order number of the existing order if duplicate is true, otherwise null. |
resolved | object | required | |
customer | object | required | |
match | string | required | existing: the customer is already known through your customer ID or our customer
number; customer_id is set. new_or_email: the customer would be created or
matched by email; customer_id is null. one of: existing, new_or_email |
customer_id | integer | null | required | |
items[] | array of object | required | |
variation_id | integer | null | required | Our ID of the matched article variant. |
sku | string | null | required | Our article number of the matched variant. |
article_id | integer | null | required | Our number of the main article. |
quantity | integer | required | |
price_source | string | required | app if you sent unit_price_gross, otherwise system. one of: app, system |
payment_method_id | integer | required | |
referrer_id | integer | null | required | The referrer that would be used (yours or the default of your API client). |
order_status_id | integer | required | The status the order would start in (yours or the shop's incoming order status). |
shipping_cost_source | string | required | app if you sent shipping_cost_gross, otherwise system. one of: app, system |
warnings[] | array of object | required | Reserved for notes about the order. Currently always empty on this endpoint. |
code | string | required | - no_shipping_method: no shipping method matched; the order was created without one and the
shop operator sets it by hand.
- customer_already_linked: the customer was found by email, but is already linked to a
different customer ID of your app.
- collective_invoice_single_order: the order uses the collective invoice, but its billing
address differs from the address stored for the customer. The order is created and
invoiced on its own, not on the collective invoice.
- status_not_changed (updateOrder): the status could not be changed because of an
unexpected error. All other changes of the request were saved; the order shows its old
status. Send order_status_id again, or pass reference to the shop operator. one of: no_shipping_method, customer_already_linked, collective_invoice_single_order, status_not_changed |
message | string | required | Human-readable English text. It may change; evaluate code instead. |
reference | string | optional | Only with status_not_changed. Identifies the case in our log. |
Error responses
401 Unauthorized The API key is missing, malformed, wrong, paused, expired or revoked. The body is always the same and never names the reason.
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key.",
"details": []
}
} 403 Forbidden The API key is valid but lacks a scope this endpoint needs. details.required lists the scopes
the endpoint requires, details.missing the ones your key lacks. Ask the shop operator to add
the scope.
{
"error": {
"code": "insufficient_scope",
"message": "The API key is missing a required scope.",
"details": {
"required": [
"orders.write"
],
"missing": [
"orders.write"
]
}
}
} 404 Not Found The path does not exist, the API is not enabled on this system, the order does not belong to the shop of your API client, or the customer, address or label value is not known to your API client.
{
"error": {
"code": "not_found",
"message": "The requested resource does not exist.",
"details": []
}
} 422 Unprocessable Content The order was not accepted. Nothing was created.
- validation_failed: the order data is invalid. details lists every problem at once: per
field a list of {code, message}. Field names use dots, for example items.1.sku is the field
sku of the second item (counting from 0).
- client_not_configured: your API client is not fully set up (no shop, deleted shop, or its
default referrer is inactive or not assigned to the shop). Contact the shop operator.
{
"error": {
"code": "validation_failed",
"message": "The order was not created.",
"details": {
"items.1.sku": [
{
"code": "unknown_article",
"message": "Article 'SAMPLE-XYZ' is not known."
}
],
"payment_method_id": [
{
"code": "unknown_payment_method",
"message": "Payment method 99 does not exist or is inactive."
}
]
}
}
} 429 Too Many Requests Too many requests. Either your API client used up its requests per minute
(message Too many requests., with all rate limit headers), or too many failed authentications
came in a short time (message Too many authentication attempts., only Retry-After). Both
carry the code rate_limited.
{
"error": {
"code": "rate_limited",
"message": "Too many requests.",
"details": []
}
} 500 Internal Server Error An unexpected error occurred on our side. Retry later.
{
"error": {
"code": "server_error",
"message": "An unexpected error occurred.",
"details": []
}
} All error codes: error code reference.
Get an order
/orders/{orderId}
Scope: orders.read
Returns an order by our order number (id from the response of createOrder). Every order of
the shop assigned to your API client can be read, no matter how it was placed (shop, marketplace,
other API clients, manual entry). type tells the kind of document, for example Auftrag
(order), Gutschrift (credit note) or Retoure (return).
external_order_id is your order number only if the order was created through your API client;
for any other order it is null.
An unknown order number, a deleted order and an order of another shop all answer 404. If no
shop is assigned to your API client, the answer is 422 with client_not_configured.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orderId | integer | required | Our order number (id from the response of createOrder). min 1 |
Example request
curl "https://shop.example.com/api/v1/orders/104233" \
-H "Authorization: Bearer $API_KEY" \
-H "Accept: application/json" Responses
200 OK The order.
{
"data": {
"id": 104233,
"order_number": "104233",
"customer_id": 9021,
"status_id": 4,
"status": "Payment received",
"payment_method_id": 3,
"referrer_id": 12,
"shipping_method_id": 2,
"shipping_method": "DHL Parcel",
"shipping_cost_gross": 4.99,
"shipping_cost_source": "system",
"items": [
{
"item_id": 88120,
"sku": "TS-BLUE-M",
"quantity": 2,
"unit_price_gross": 19.9,
"price_source": "app",
"article_id": 5512,
"variation_id": 7741,
"name": "T-shirt blue M",
"total_gross": 39.8
}
],
"grand_total_gross": 44.79,
"currency": "EUR",
"external_order_id": "APP-2026-000187",
"type": "Auftrag",
"created_at": "2026-10-15T09:12:44.000000Z",
"updated_at": "2026-10-15T11:30:02.000000Z",
"email": "alex.sample@example.com",
"telephone": null,
"paid_status": "paid",
"payment_method": "PayPal",
"shipping_cost_net": 4.19,
"tax_total": 7.15,
"grand_total_net": 37.64,
"billing": {
"salutation": "Mr",
"title": null,
"first_name": "Alex",
"last_name": "Sample",
"company": null,
"street": "Sample Street",
"house": "5",
"additional": null,
"postcode": "10115",
"city": "Berlin",
"country": "DE"
},
"shipping": null,
"shipments": [
{
"shipment_number": "00340434161094042557",
"tracking_url": "https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?piececode=00340434161094042557",
"delivered_at": null
}
]
}
} Response fields
| Field | Type | Required | Description |
|---|---|---|---|
data | object | required | An order of your shop. Addresses use the format of customer.billing and customer.shipping
in createOrder; empty fields are null. |
id | integer | required | Our order number. |
order_number | string | required | Our order number as text (same value as id). |
external_order_id | string | null | required | Your order number if the order was created through your API client, otherwise null. |
type | string | required | Kind of document as named in the shop, for example Auftrag (order), Gutschrift (credit note), Retoure (return), Angebot (offer) or Sammelauftrag (collective invoice order). |
created_at | string (date-time) | null | required | Order date (UTC). |
updated_at | string (date-time) | null | optional | Last change (UTC). |
customer_id | integer | required | Our customer number. |
email | string | required | |
telephone | string | null | optional | |
status_id | integer | required | ID of the order status (see listOrderStatuses). |
status | string | required | Name of the order status as named in the shop. |
paid_status | string | null | required | Payment state: unpaid, in_payment (partly paid), paid or canceled. |
payment_method_id | integer | required | |
payment_method | string | null | required | Name of the payment method at the time of the order. |
referrer_id | integer | null | required | |
currency | string | required | |
billing | object | required | Billing address. Has no state. |
salutation | string | null | optional | |
title | string | null | optional | |
first_name | string | null | optional | |
last_name | string | null | optional | |
company | string | null | optional | |
street | string | null | optional | |
house | string | null | optional | |
additional | string | null | optional | |
postcode | string | null | optional | |
city | string | null | optional | |
country | string | null | optional | ISO 3166-1 alpha-2 country code. |
shipping | object | null | required | Delivery address; null if the order is delivered to the billing address. |
items[] | array of object | required | |
item_id | integer | required | Our number of the item. Use it in updateOrder (items.update, items.remove). |
sku | string | required | Our article number of the variant. |
article_id | integer | null | required | Our number of the main article. |
variation_id | integer | null | required | Our number of the variant; null for items without an article (for example a free text item). |
name | string | required | |
quantity | integer | required | |
unit_price_gross | number | required | Unit price including tax. |
total_gross | number | required | Item total including tax. |
price_source | string | required | app = fixed price, system = the shop's price. one of: app, system |
shipping_method_id | integer | null | required | |
shipping_method | string | null | required | |
shipping_cost_gross | number | required | |
shipping_cost_net | number | required | |
shipping_cost_source | string | required | one of: app, system |
tax_total | number | required | Total tax of the order. |
grand_total_gross | number | required | Total of the order including tax. |
grand_total_net | number | required | Total of the order without tax. |
shipments[] | array of object | required | Parcels of the order with a tracking number (cancelled labels excluded). Empty until the order is shipped. |
shipment_number | string | required | |
tracking_url | string | null | required | Tracking link of the shipping method; null if none is configured. |
delivered_at | string (date-time) | null | required | Delivery time reported by the carrier (UTC), if known. |
Error responses
401 Unauthorized The API key is missing, malformed, wrong, paused, expired or revoked. The body is always the same and never names the reason.
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key.",
"details": []
}
} 403 Forbidden The API key is valid but lacks a scope this endpoint needs. details.required lists the scopes
the endpoint requires, details.missing the ones your key lacks. Ask the shop operator to add
the scope.
{
"error": {
"code": "insufficient_scope",
"message": "The API key is missing a required scope.",
"details": {
"required": [
"orders.write"
],
"missing": [
"orders.write"
]
}
}
} 404 Not Found The path does not exist, the API is not enabled on this system, the order does not belong to the shop of your API client, or the customer, address or label value is not known to your API client.
{
"error": {
"code": "not_found",
"message": "The requested resource does not exist.",
"details": []
}
} 422 Unprocessable Content No shop is assigned to your API client (client_not_configured).
{
"error": {
"code": "client_not_configured",
"message": "No shop is configured for this API client.",
"details": []
}
} 429 Too Many Requests Too many requests. Either your API client used up its requests per minute
(message Too many requests., with all rate limit headers), or too many failed authentications
came in a short time (message Too many authentication attempts., only Retry-After). Both
carry the code rate_limited.
{
"error": {
"code": "rate_limited",
"message": "Too many requests.",
"details": []
}
} 500 Internal Server Error An unexpected error occurred on our side. Retry later.
{
"error": {
"code": "server_error",
"message": "An unexpected error occurred.",
"details": []
}
} All error codes: error code reference.
Update an order
/orders/{orderId}
Scope: orders.update
Changes an order of the shop assigned to your API client: status, payment method, billing and delivery address, and items. Send only the blocks you want to change; at least one is required. Every order of the shop can be changed, no matter how it was placed.
All checks run before anything is written, and every problem is reported at once. If one entry
is invalid, nothing is changed. Unknown fields are rejected (unknown_field), not ignored.
Items: items.add adds items like createOrder (with price the item gets a fixed price,
without it the shop's price applies). items.update changes quantity and/or price of an
item, addressed by its item_id from getOrder. A quantity change alone works like a change in
the shop's back office: an item with a fixed price keeps it, all other items are priced again by
the shop's price rules (including volume prices). items.remove removes items by item_id. At most 100 entries
per request; the order must keep at least one item. To empty an order, change its status to a
cancelled status.
If the order is finalised (invoiced), cancelled or shipped (also when all its goods are booked out,
whatever its status), items, addresses and the payment method can no longer be changed
(409 order_locked); the status can, sent as order_status_id alone.
The status is changed last, after the other changes are saved. If that fails, the other changes
stay saved: on an unexpected error the answer is 200 with the old status and the warning
status_not_changed; send order_status_id again to retry.
Sending the current state again changes nothing and answers 200. Sending items.add again
adds the items again, unless you send the same Idempotency-Key with exactly the same body.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orderId | integer | required | Our order number (id from the response of createOrder). min 1 |
Headers
| Header | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | optional | Your own unique key for this change, at most 191 characters, for example a UUID. If you send the
same key with exactly the same body again within 24 hours, you get the stored answer and nothing
is changed a second time; the answer then carries the header Idempotent-Replayed: true. The same
key with a different body answers 422 idempotency_key_reused. Answers with status 5xx and
409 stock_locked are not stored, so a retry with the same key runs again. All other answers are
stored, also errors such as 422 validation_failed or 409 order_locked: after you correct the
request, send it with a new key. max length 191 |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
order_status_id | integer | optional | New order status, an ID from listOrderStatuses. Allowed on every order, also a finalised, cancelled or shipped one. |
payment_method_id | integer | optional | New payment method, an ID from listPaymentMethods. Same rules as in createOrder; for the collective invoice the customer of the order must be approved. |
billing | object | optional | Address. last_name or company is required. |
salutation | string | null | optional | max length 191 |
title | string | null | optional | max length 50 |
first_name | string | null | optional | max length 191 |
last_name | string | null | optional | Required unless company is set. max length 191 |
company | string | null | optional | max length 191 |
street | string | required | max length 191 |
house | string | null | optional | House number. For a parcel locker, the number of the parcel locker. max length 191 |
additional | string | null | optional | Additional address line. max length 191 |
postcode | string | required | max length 191 |
city | string | required | max length 191 |
state | string | null | optional | State or region as text. max length 191 |
country | string | required | Country code according to ISO 3166-1 alpha-2, for example DE or AT. min length 2 · max length 2 |
shipping | object | null | optional | New delivery address; replaces the old one completely. null or {} removes it, the order then goes to the billing address. |
items | object | optional | At most 100 entries in add, update and remove together. An item_id may appear only once. |
add[] | array of object | optional | |
sku | string | null | optional | Our article number. Not case-sensitive. max length 191 |
article_id | integer | null | optional | Our number of the main article; for articles with variants use sku. min 1 |
quantity | integer | required | min 1 · max 9999 |
price | number | null | optional | Unit price including tax, at most 2 decimal places. If sent, it is used as a fixed price, also 0 (the item is then free of charge); if missing or null, the shop's price applies. min 0 · max 999999.99 · multiple of 0.01 |
update[] | array of object | optional | |
item_id | integer | required | item_id of the item, from getOrder. min 1 |
quantity | integer | null | optional | New quantity. It cannot be lower than the quantity already delivered. min 1 · max 9999 |
price | number | null | optional | New unit price including tax; the item gets a fixed price. 0 is allowed and makes the item free of charge. The tax rate is the rate of the delivery country after this request, also when the same request changes the country; without a rate there, article_tax_unresolved. min 0 · max 999999.99 · multiple of 0.01 |
remove | array of integer | optional | item_ids of the items to remove. An item that is already partly delivered cannot be removed. items: min 1 |
Example request
curl -X PATCH "https://shop.example.com/api/v1/orders/104233" \
-H "Authorization: Bearer $API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"order_status_id": 4,
"items": {
"add": [
{
"sku": "TS-BLUE-L",
"quantity": 1
}
],
"update": [
{
"item_id": 88120,
"quantity": 3
}
],
"remove": [
88121
]
}
}' Responses
200 OK The changed order, in the format of getOrder.
{
"warnings": [],
"data": {
"id": 104233,
"order_number": "104233",
"customer_id": 9021,
"status_id": 4,
"status": "Payment received",
"payment_method_id": 3,
"referrer_id": 12,
"shipping_method_id": 2,
"shipping_method": "DHL Parcel",
"shipping_cost_gross": 4.99,
"shipping_cost_source": "system",
"items": [
{
"item_id": 88120,
"sku": "TS-BLUE-M",
"quantity": 3,
"unit_price_gross": 19.9,
"price_source": "app",
"article_id": 5512,
"variation_id": 7741,
"name": "T-shirt blue M",
"total_gross": 59.7
},
{
"item_id": 88122,
"sku": "TS-BLUE-L",
"quantity": 1,
"unit_price_gross": 19.9,
"price_source": "system",
"article_id": 5512,
"variation_id": 7742,
"name": "T-shirt blue L",
"total_gross": 19.9
}
],
"grand_total_gross": 84.59,
"currency": "EUR",
"external_order_id": "APP-2026-000187",
"type": "Auftrag",
"created_at": "2026-10-15T09:12:44.000000Z",
"updated_at": "2026-10-15T12:01:10.000000Z",
"email": "alex.sample@example.com",
"telephone": null,
"paid_status": "unpaid",
"payment_method": "Invoice",
"shipping_cost_net": 4.19,
"tax_total": 13.51,
"grand_total_net": 71.08,
"billing": {
"salutation": "Mr",
"title": null,
"first_name": "Alex",
"last_name": "Sample",
"company": null,
"street": "Sample Street",
"house": "5",
"additional": null,
"postcode": "10115",
"city": "Berlin",
"country": "DE"
},
"shipping": null,
"shipments": []
}
} Response fields
| Field | Type | Required | Description |
|---|---|---|---|
data | object | required | An order of your shop. Addresses use the format of customer.billing and customer.shipping
in createOrder; empty fields are null. |
id | integer | required | Our order number. |
order_number | string | required | Our order number as text (same value as id). |
external_order_id | string | null | required | Your order number if the order was created through your API client, otherwise null. |
type | string | required | Kind of document as named in the shop, for example Auftrag (order), Gutschrift (credit note), Retoure (return), Angebot (offer) or Sammelauftrag (collective invoice order). |
created_at | string (date-time) | null | required | Order date (UTC). |
updated_at | string (date-time) | null | optional | Last change (UTC). |
customer_id | integer | required | Our customer number. |
email | string | required | |
telephone | string | null | optional | |
status_id | integer | required | ID of the order status (see listOrderStatuses). |
status | string | required | Name of the order status as named in the shop. |
paid_status | string | null | required | Payment state: unpaid, in_payment (partly paid), paid or canceled. |
payment_method_id | integer | required | |
payment_method | string | null | required | Name of the payment method at the time of the order. |
referrer_id | integer | null | required | |
currency | string | required | |
billing | object | required | Billing address. Has no state. |
salutation | string | null | optional | |
title | string | null | optional | |
first_name | string | null | optional | |
last_name | string | null | optional | |
company | string | null | optional | |
street | string | null | optional | |
house | string | null | optional | |
additional | string | null | optional | |
postcode | string | null | optional | |
city | string | null | optional | |
country | string | null | optional | ISO 3166-1 alpha-2 country code. |
shipping | object | null | required | Delivery address; null if the order is delivered to the billing address. |
items[] | array of object | required | |
item_id | integer | required | Our number of the item. Use it in updateOrder (items.update, items.remove). |
sku | string | required | Our article number of the variant. |
article_id | integer | null | required | Our number of the main article. |
variation_id | integer | null | required | Our number of the variant; null for items without an article (for example a free text item). |
name | string | required | |
quantity | integer | required | |
unit_price_gross | number | required | Unit price including tax. |
total_gross | number | required | Item total including tax. |
price_source | string | required | app = fixed price, system = the shop's price. one of: app, system |
shipping_method_id | integer | null | required | |
shipping_method | string | null | required | |
shipping_cost_gross | number | required | |
shipping_cost_net | number | required | |
shipping_cost_source | string | required | one of: app, system |
tax_total | number | required | Total tax of the order. |
grand_total_gross | number | required | Total of the order including tax. |
grand_total_net | number | required | Total of the order without tax. |
shipments[] | array of object | required | Parcels of the order with a tracking number (cancelled labels excluded). Empty until the order is shipped. |
shipment_number | string | required | |
tracking_url | string | null | required | Tracking link of the shipping method; null if none is configured. |
delivered_at | string (date-time) | null | required | Delivery time reported by the carrier (UTC), if known. |
warnings[] | array of object | required | Notes about the change. Empty if everything was applied. |
code | string | required | - no_shipping_method: no shipping method matched; the order was created without one and the
shop operator sets it by hand.
- customer_already_linked: the customer was found by email, but is already linked to a
different customer ID of your app.
- collective_invoice_single_order: the order uses the collective invoice, but its billing
address differs from the address stored for the customer. The order is created and
invoiced on its own, not on the collective invoice.
- status_not_changed (updateOrder): the status could not be changed because of an
unexpected error. All other changes of the request were saved; the order shows its old
status. Send order_status_id again, or pass reference to the shop operator. one of: no_shipping_method, customer_already_linked, collective_invoice_single_order, status_not_changed |
message | string | required | Human-readable English text. It may change; evaluate code instead. |
reference | string | optional | Only with status_not_changed. Identifies the case in our log. |
Error responses
401 Unauthorized The API key is missing, malformed, wrong, paused, expired or revoked. The body is always the same and never names the reason.
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key.",
"details": []
}
} 403 Forbidden The API key is valid but lacks a scope this endpoint needs. details.required lists the scopes
the endpoint requires, details.missing the ones your key lacks. Ask the shop operator to add
the scope.
{
"error": {
"code": "insufficient_scope",
"message": "The API key is missing a required scope.",
"details": {
"required": [
"orders.write"
],
"missing": [
"orders.write"
]
}
}
} 404 Not Found The path does not exist, the API is not enabled on this system, the order does not belong to the shop of your API client, or the customer, address or label value is not known to your API client.
{
"error": {
"code": "not_found",
"message": "The requested resource does not exist.",
"details": []
}
} 409 Conflict Nothing was changed, with one exception noted below.
- order_locked: the order is finalised (invoiced), cancelled or shipped and the request changes
items, addresses or the payment method; to change only the status, send order_status_id
alone. Or the new status would cancel a credit note that is settled in a collective invoice. If the credit note was settled only while the other changes
of the request were being saved, those changes stay saved and only the status is not changed;
the message says so.
- stock_locked: a running stocktake locks the stock. Retry later.
- conflict: a request with the same Idempotency-Key is still running. Retry in a few seconds.
{
"error": {
"code": "order_locked",
"message": "Order 104233 is finalised. Items, addresses and the payment method can no longer be changed. Send order_status_id alone to change the status.",
"details": []
}
} 422 Unprocessable Content Nothing was changed.
- validation_failed: the request data is invalid. details lists every problem at once,
per field a list of {code, message}. Detail codes of this endpoint:
- required: in body, no block was sent; in items, no entry in add, update or
remove; otherwise a required field is missing.
- invalid_format, too_long: wrong type or format, or a text that is too long. An
Idempotency-Key longer than 191 characters is reported as too_long in
idempotency_key.
- out_of_range: a number outside the allowed range, or more than 100 entries in items
(add, update and remove together).
- duplicate_value: an item_id appears twice, or in items.update and items.remove
at the same time.
- unknown_item: the item_id is not an item of this order.
- unknown_field: a field of the body is not known on its level, usually a typo (for
example items.update.0.qty instead of quantity, or billing.zip instead of
postcode). Unknown fields are never ignored.
- item_already_delivered: the item is partly delivered; it cannot be removed, and its
quantity cannot be lower than the quantity already delivered.
- order_empty: the order would have no items left.
- unknown_order_status, unknown_payment_method, payment_method_not_available,
unknown_country, required_for_packstation, unknown_article, ambiguous_article,
article_inactive, article_tax_unresolved, article_reserved: as for createOrder.
- client_not_configured: no shop is assigned to your API client.
- idempotency_key_reused: the Idempotency-Key was already used with a different body.
With an Idempotency-Key, this answer is stored for 24 hours like every 4xx answer except
409 stock_locked: sending the same key again returns it unchanged. Send the corrected request
with a new key.
{
"error": {
"code": "validation_failed",
"message": "The order was not changed.",
"details": {
"order_status_id": [
{
"code": "unknown_order_status",
"message": "Order status 99 does not exist."
}
]
}
}
} 429 Too Many Requests Too many requests. Either your API client used up its requests per minute
(message Too many requests., with all rate limit headers), or too many failed authentications
came in a short time (message Too many authentication attempts., only Retry-After). Both
carry the code rate_limited.
{
"error": {
"code": "rate_limited",
"message": "Too many requests.",
"details": []
}
} 500 Internal Server Error An unexpected error occurred; the order was not created. details.reference identifies the
case. Resend the unchanged request later; if the error persists, give the reference to the shop
operator.
{
"error": {
"code": "server_error",
"message": "An unexpected error occurred. The order was not created.",
"details": {
"reference": "3f2a9c1e-7b4d-4e8a-9f61-2d5c8b0a7e13"
}
}
} All error codes: error code reference.