# Orders

Orders get created in `draft` status and become `pending` when they have a customer and some line items.

{% hint style="info" %}
Draft orders act as **shopping carts** — see our [how-to](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/shopping-cart) 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.
{% endhint %}

{% hint style="danger" %}
For performance reasons (and to make sure no to hit the API [rate limits](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/rate-limits)), we strongly advise against dealing with empty carts — just create a new order right before adding the first line item to it.
{% endhint %}

`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](#asynchronous-order-placement) and transit through the `placing` status use the `place_async` attribute. When an order is `placed`, it can either get `approved` or `cancelled`.

{% hint style="warning" %}
Placed orders cannot be deleted. To archive them you can patch them passing the `_archive` trigger attribute. You can [filter](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/filtering-data) them using the query `filter[q][archived_at_null]=false`, [search](https://app.gitbook.com/s/ASSiAvbL4nFnkl8plQy2/getting-started/use-cases/latest-archived-orders) for them using the Metrics API, or see them in the related section of the Dashboard Orders app.
{% endhint %}

An approved order becomes `fulfilled` when paid and shipped. Cancelling an order automatically [voids](https://docs.commercelayer.io/core-api-reference/voids) its payment source's [authorization](https://docs.commercelayer.io/core-api-reference/authorizations). Captured payments can be [refunded](https://docs.commercelayer.io/core-api-reference/refunds), either fully or partially.

| Action                                                             | Order status | Payment status       | Fulfillment status                                     |
| ------------------------------------------------------------------ | ------------ | -------------------- | ------------------------------------------------------ |
| **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`.

{% hint style="warning" %}
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.
{% endhint %}

<details>

<summary>Data model</summary>

Read more about the anatomy of an order [here](https://commercelayer.io/docs/data-model/anatomy-of-an-order) and check the related ER diagram that illustrates how the order resource relates to the other API entities.

</details>

## Asynchronous order placement

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](#order-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](https://docs.commercelayer.io/core-api-reference/markets#external-urls) 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](#order-errors) 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`).

{% hint style="info" %}
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](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/api-credentials#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.
{% endhint %}

{% hint style="warning" %}
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.
{% endhint %}

## Auto-refresh

By default, orders that are still editable (i.e. in `draft` or `pending` status) are automatically refreshed each time they get updated and/or one of the related line items gets created, updated, or destroyed. This automatically triggers several actions:

* If the order is already associated with a shipping address, the related shipments are rebuilt based on the related [inventory model's strategy](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/inventory/strategies).
* Any active promotions and/or gift cards are applied and the related discounts are recalculated.
* Any negative adjustment is redistributed on the [taxable items](#taxable-items).
* If the market associated with the order has a tax calculator, taxes get updated.
* All of the internal amounts and counters are refreshed.

All of the above gets calculated in sequence for each of the order's line items, resulting in a pretty intensive computation, which can considerably slow down in case one or more [external resources](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/external-resources) are involved. This may lead to concurrent request issues and/or timeout errors, making the automatic refresh not ideal, especially when you have to deal with cart containing a large number of line items (e.g. B2B).

To better handle these specific scenarios you can leverage the order's `autorefresh` attribute and set it to `false` (default is `true`) to prevent the automatic triggering of the above-mentioned actions. This choice will result in stale order data, but will ensure a much faster order editing (the performance gain will build up exponentially with increasing number of line items — we estimate an average boost of 500%). Once the editing is completed, the attribute can be updated back to `true`, which automatically triggers a new refresh of the order (in any case, remember that there is always the option to force a refresh manually even when the order auto-refresh is disabled by passing the `_refresh` trigger attribute).

{% hint style="warning" %}
If your top priority is pure performance and you're fine with getting a refreshed snapshot of the order just before placing it rather than in real time, we strongly recommend disabling the order auto-refresh option when needed.
{% endhint %}

## Order editing

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.

{% hint style="warning" %}
For security reasons, only [integrations](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/api-credentials#integration) 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.
{% endhint %}

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](#capture-options), 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](https://docs.commercelayer.io/core-api-reference/refunds) will be performed and no further edit to the order will be allowed.

### Promotions, coupons, and gift cards

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.

### Shipments and shipping methods

Shipments are rebuilt so, after any editing operation and before exiting the editing status, you need to check again the [available shipping methods](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/checkout/selecting-a-shipping-method#1.-get-the-available-shipping-methods) (which may be different) and choose a new one to be [re-associated](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/checkout/selecting-a-shipping-method#3.-select-a-shipping-method) with the edited order, otherwise the API will return an error on the `_stop_editing`.

{% hint style="info" %}
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.
{% endhint %}

### Non-editable attributes

[Integrations](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/api-credentials#integration) 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](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/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`

{% hint style="info" %}
You can still edit the attributes above if the order is in the `placed` status by entering [order editing](#order-editing), otherwise they are considered frozen and not editable anymore.
{% endhint %}

{% hint style="danger" %}
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.
{% endhint %}

## Default payment method

If you set a [default payment method](https://docs.commercelayer.io/core-api-reference/markets#default-payment-method) for a market, all the market's orders not already associated with a payment method will be automatically associated with the default one. Specifically:

* If you create a new order, it will be automatically associated with the default payment method at creation time. Then, if needed, you can change the payment method by patching the order and [updating the relationship](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/updating-resources#updating-relationships).
* If an order is already associated with a payment method and the association is [removed](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/updating-resources#removing-relationships), the order will be automatically associated with the default payment method.
* Existing orders with no payment method associated will not be automatically associated with the default one until a new validation on the order is triggered (e.g. order editing).

In any case, the associated line item of type `payment_methods` will be created/recreated accordingly and the default payment method will be listed in the `available_payment_methods` array associated with the order.

## Changing the order number

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.

{% hint style="info" %}
This feature is available **for enterprise plans only** and can be activated by [environment](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/api-specification#environments) (meaning you can request to enable it in test mode, in live mode or both — inspect the related [organization](https://docs.commercelayer.io/core-api-reference/organization)'s flags `order_number_editable_test` and `order_number_editable_live` to check your configuration).
{% endhint %}

## Stock reservation

When an order is placed the [stock reservations](https://docs.commercelayer.io/core-api-reference/stock_reservations) needed to block the whole order's stock are automatically created and the associated stock is reserved without decrementing the [stock item](https://docs.commercelayer.io/core-api-reference/stock_items) 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](https://docs.commercelayer.io/core-api-reference/line_items#reserving-the-stock) when adding the line item to the order.

## Capture options

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](https://docs.commercelayer.io/core-api-reference/payment_methods#capture-options) at the payment method level. This way, the fulfillment status can become `in_progress` even if the payment status is not `paid` yet.

Similarly, you can decide to unify the authorization and capture steps and automatically capture payments upon authorization by enabling the [auto-capture](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/auto-capture) option. This way if the authorization succeeds, a successful capture is automatically generated and the order's payment status is set to `paid`.

## Automatic subscriptions generation

If a [subscription model](https://docs.commercelayer.io/core-api-reference/subscription_models) 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 [trigger the automatic order subscription generation](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/subscriptions/generating-the-subscriptions) you just need to update the source order after placement and pass the `_create_subscriptions` attribute.

## Order validation

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](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/external-resources/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](https://docs.commercelayer.io/core-api-reference/markets) level and update the order(s) in question by setting the `_validate` trigger attribute to `true`.

<details>

<summary>How-to</summary>

Check the related [guide](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/external-resources/external-order-validation) to learn how to validate orders via external services.

</details>

## Timed placement

You can add an expiration date for the placement of an order by setting the order's `expires_at` attribute (you need to use [integration](https://app.gitbook.com/s/-LgByaSP8eKjad-MIuHE/api-credentials#integration) API credentials) after which the order placement attempt will fail. If the `expires_at` timestamp is set, you can also fill the `expiration_info` JSON object with any key/value pair you need to add useful information (e.g. messages to be shown on the frontend, a return URL for orders not placed due to expired time, etc.).

{% hint style="warning" %}
The value of the expiration timestamp will be checked against the current time only at the first placement attempt of the order (i.e. it will be ignored for the subsequent [order editing](#order-editing) updates, if any).
{% endhint %}

{% hint style="info" %}
This option can come in handy when dealing with quite common use cases such as ticketing processes, time-limited inventory, flash sales, and more.
{% endhint %}

## Order errors

The latest **10** errors occurring during the attempt to place an order (both synchronously and [asynchronously](#asynchronous-order-placement)), including the ones coming from [external validations](#order-validation) or [subscription](#automatic-subscriptions-generation) processes, are stored in the related [resource errors](https://docs.commercelayer.io/core-api-reference/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.

## Taxable items

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.

## Payment options

You can associate additional [payment options](https://docs.commercelayer.io/core-api-reference/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](https://stripe.com/connect) and accept payments [on behalf of](https://support.stripe.com/questions/sending-invoices-on-behalf-of-connected-accounts) connected accounts). Make sure to do it before the payment source creation so that they can be properly injected.

## Idempotency

{% hint style="info" %}
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).
{% endhint %}

This can be useful to force a payment status (e.g. `paid`), in case the [payment gateway](https://docs.commercelayer.io/core-api-reference/payment_gateways) has recorded the capture, but for some reason (typically the gateway's timeout) the order kept an inconsistent payment status (e.g. `authorized`). [Webhooks](https://docs.commercelayer.io/core-api-reference/webhooks)'s events, [stock item](https://docs.commercelayer.io/core-api-reference/stock_items) updates, and other status-related actions are granted to be executed only once.
