Orders
The order object and the allowed CRUD operations on the related resource endpoint
Last updated
The order object and the allowed CRUD operations on the related resource endpoint
Last updated
Orders get created in draft
status and become pending
when they have a customer and some line items.
Draft orders act as shopping carts — see our on how to manage shopping carts. Draft orders that aren't associated with a customer are automatically deleted after 2 months since the latest update.
For performance reasons (and to make sure no to hit the API rate limits), we we strongly advise against dealing with empty carts — just create a new order right before adding the first line item to it.
pending
orders can be recovered or cancelled when abandoned. The status of an order is closely linked to the related payment and fulfillment statuses. Orders are placed synchronously by default, if you need to place them asychronously and transit through the placing
status use the place_async
attribute. When an order is placed
, it can either get approved
or cancelled
.
Placed orders cannot be deleted. To archive them you can patch them passing the _archive
trigger attribute. You can filter them using the query filter[q][archived_at_null]=false
, for them using the Metrics API, or see them in the related section of the Dashboard Orders app.
An approved order becomes fulfilled
when paid and shipped. Cancelling an order automatically voids its payment source's authorization. Captured payments can be refunded, either fully or partially.
Empty order creation
draft
unpaid
unfulfilled
Association with a customer and addition of a purchasable item
pending
unpaid
unfulfilled
Async order placement with errors
placing
unpaid
unfulfilled
Order placement
placed
authorized
unfulfilled
Order editing
editing
authorized
unfulfilled
Order cancellation
cancelled
voided
unfulfilled
Order approval
approved
authorized
unfulfilled
Payment capture
approved
paid
in_progress
Refund (partial)
approved
partially_refunded
No changes to the previous fulfillment status.
Refund (full)
cancelled
refunded
unfulfilled
if in progress, otherwise fulfilled
.
All shipments shipped
approved
paid
fulfilled
The payment status of the orders that have a total amount equal to zero is automatically set to free
. If the order contains items flagged as do_not_ship
only, its fulfillment status is automatically not_required
.
The table above describes the most common order's lifecycle scenario. Some specific use cases (e.g. the ones involving manual actions on orders and shipments) might slightly differ.
To place an order asynchronously, you just need to set the place_async
flag to true
(default is false
). In this scenario, only a subset of the standard synchronous validations (needed to check the order integrity) is performed when passing the _place
trigger attribute:
Customer — the correct association with an existing customer is checked.
Billing — the correct association with an existing billing address is checked.
Items — the presence of at least one SKU, bundle, positive gift card (i.e. purchasing a gift card), or positive adjustment is checked.
Shipping — the correct association with an existing shipping method and shipping address is checked.
Payment — the correct association with an existing payment method and payment source is checked.
If some errors occur at this stage, the order stays pending
and cannot be placed. If those validations are successful, the order is moved to an intermediate status (placing
) where the remaining validations are added:
Coupons — the validity of the associated coupon code (if any) is checked.
Stock — the availability of the necessary stock to fulfill the order is checked.
Authorization — the selected payment gateway is called to get the payment authorized.
External validation — if any (i.e. if and external_order_validation_url
is set at the market level).
If also those validations are successful and no errors come from the gateway, the order is safely placed and moved through the next steps of its lifecycle. If some of the additional validations throw an error you need to fix it (e.g. adding the missing stock) and manually re-trigger the _place
(which will be again performed asynchronously unless the place_async
flag is not set back to false
).
The orders that are in placing
status can be fetched but not edited by a sales channel. To patch them you need to use integration API credentials. If you need the customer to fix the error that's keeping the order in placing
you can pass the _pending
trigger attribute and move it back to the pending
status.
Since 3D Secure (3DS) payments require real-time user interaction during the authorization process, they cannot be supported when choosing an asynchronous order placement flow.
Draft and pending orders are always editable by a sales channel before placement. Once an order is placed but still not approved can be moved to the editing
status by passing the _start_editing
trigger attribute. As soon as the editing operations are finished, the order must be moved back to the placed
status by passing the _stop_editing
trigger attribute.
For security reasons, only integrations are allowed to change the _start_editing
and _stop_editing
attributes of an order. When an order is in the editing
status it can be updated by the customer that placed it.
When an order is in editing you can make almost any change you need (e.g. adding or removing line items, coupon or gift cards, adjustment, etc.) except replace the payment source and payment method, on the condition that the updates don't lead to a total order amount that exceeds the previously authorized (or already captured, if that's the case) amount, otherwise the API will return an error on the _stop_editing
. If, after the order editing, the total amount is less than the authorized amount, the new amount will be captured. If the authorized amount was already captured, a partial refund will be performed and no further edit to the order will be allowed.
The discounts due to the active promotions applied at placement time are refreshed according to the changes applied to the order, even if the promotions should have expired in the meanwhile. New promotions (if any) triggered by the changes due to the order editing are not applied. Coupons and/or gift cards applied at placement time are still valid (even single-use ones). New coupons or gift cards can be applied, as long as one of them wasn't already present at the time of placement.
Orders can be edited multiple times before approval. Please note that once an editing operation is started, it can't be reverted. It can always be aborted by cancelling the order.
Integrations can edit almost every order attribute or relationship even if the order is in a non-editable status (i.e. a different one from draft
, pending
, or editing
— see Roles and permissions for more information), with a few exceptions, listed below. If the order is no longer editable, the following attributes and relationships cannot be edited using any API credentials:
market
customer
shipping_address
payment_method
payment_source
gift_card_code
coupon_code
You can still edit the attributes above if the order is in the placed
status by entering order editing, otherwise they are considered frozen and not editable anymore.
Altering the non-editable attributes during the order's placement process is not permitted, since they can trigger collateral effects after the order has been placed (e.g. promotions application, shipments rebuild, etc.) and cause an inconsistent order status. If you patch the order passing the _place
trigger attribute together with some attribute or relationship that would alter any of the non-editable ones, no error is raised (to guarantee the order's placement), but the changes are silently ignored.
The default order numeric identifier can be changed according to your needs as long as the passed value is unique within the specific organization environment.
This feature is available for enterprise plans only and can be activated by environment (meaning you can request to enable it in test mode, in live mode or both — inspect the related organization's flags order_number_editable_test
and order_number_editable_live
to check your configuration).
When an order is placed the stock reservations needed to block the whole order's stock are automatically created and the associated stock is reserved without decrementing the stock item quantities. Once the order is approved the stock item quantities are decremented. If the order is cancelled the reserved stock is released becoming available again. You can temporarily reserve the stock associated with a line item before the order placement by sending a specific trigger attribute when adding the line item to the order.
By default, payments are required to be captured before being able to start fulfilling the related orders. You can override this constraint by allowing a delayed capture at the payment method level. This way, the fulfillment status can become in_progress
even if the payment status is not paid
yet.
Automatic order validation is performed at the time of the order placement. Sometimes, you may need to implement custom validation (e.g. you want to support more complex validation rules specific to your business logic) on some orders, as an additional step before the order placement. To do that, you can leverage Commerce Layer's external order validation feature — just make sure to correctly set up the URL of your external service (that will be in charge of computing the validation logic) at the market level and update the order(s) in question by setting the _validate
trigger attribute to true
.
The latest 10 errors occurring during the attempt to place an order (both synchronously and asynchronously), including the ones coming from external validations or subscription processes, are stored in the related resource errors array until order approval. To inspect them, you just need to fetch the error including the resource errors association. You can also leverage the errors_count
attribute (which is reset to 0 once the order is approved) at the order level.
The taxable items of an order are used for tax and discount distributions. Line items of type skus
and bundles
are taxable by default. As for the other item types, you need to set this property by specifying the related attribute at the order level:
Set freight_taxable
to true
if you want to add the line items of type shipments
(i.e. shipping costs) to the taxable items list.
Set payment_method_taxable
to true
if you want to add the line items of type payment_methods
(i.e. specific payment method costs) to the taxable items list.
Set adjustment_taxable
to true
if you want to add the line items of type adjustments
(i.e. positive adjustments) to the taxable items list.
Set gift_card_taxable
to true
if you want to add the line items of type gift_cards
(i.e. purchased gift cards) to the taxable items list.
You can associate additional payment options with an order to extend the information we send to the payment gateway at the moment of the payment creation (e.g. to leverage Stripe Connect and accept payments on behalf of connected accounts). Make sure to do it before the payment source creation so that they can be properly injected.
Order status changes are idempotent. The order and payment statuses are granted to be consistent upon multiple updates (e.g. it's possible to place or cancel an order multiple times, without worrying about duplicated transactions and other side effects).
This can be useful to force a payment status (e.g. paid
), in case the payment gateway has recorded the capture, but for some reason (typically the gateway's timeout) the order kept an inconsistent payment status (e.g. authorized
). Webhooks's events, stock item updates, and other status-related actions are granted to be executed only once.
Shipments are rebuilt so, after any editing operation and before exiting the editing status, you need to check again the (which may be different) and choose a new one to be with the edited order, otherwise the API will return an error on the _stop_editing
.
Similarly, you can decide to unify the authorization and capture steps and automatically capture payments upon authorization by enabling the option. This way if the authorization succeeds, a successful capture is automatically generated and the order's payment status is set to paid
.
If a subscription model is associated with the same market as an order, subscriptions can be automatically generated for all the line items that have a frequency, based on the strategy set at the subscription model level. To you just need to update the source order after placement and pass the _create_subscriptions
attribute.