> For the complete documentation index, see [llms.txt](https://developer.esw.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.esw.com/checkout-api/resources/order-confirmation-webhook.md).

# Order Confirmation Webhook

ESW’s Order Confirmation webhook sends your system a notification each time an order is placed through ESW Checkout.

ESW sends an HTTP `POST` request to your webhook URL. The request body contains shopper, product, and payment data in JSON.

Each completed order includes values such as:

* Unique cart ID
* Delivery option selected
* Order value in retailer currency
* Order value in shopper currency
* Product title and description
* Product image, color, and size
* Promo codes and discounts
* Payment method
* Contact details

ESW supports two webhook versions:

* `v2.0`
* `v3.0`

The main differences are covered below.

If you use Checkout API `v3.0`, you must use Order Confirmation `v3.0`. The `v2.0` and `v3.0` payloads are not compatible.

Both versions use the same HTTP response schema.

### Differences between v2.0 and v3.0

* Use Order Confirmation `v3.0` only with Checkout API `v3.0`.
* Use Order Confirmation `v2.0` with Checkout API `v2.0`.

#### Price object

In `v3.0`, `price` is an object. In `v2.0`, `price` is a single string.

{% tabs %}
{% tab title="v2.0" %}
{% code title="price-v2.json" %}

```json
{
  "price": "EUR123.45"
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="price-v3.json" %}

```json
{
  "price": {
    "retailer": {
      "currency": "EUR",
      "amount": "123.45"
    },
    "shopper": {
      "currency": "USD",
      "amount": "123.45"
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Price grouping

In `v2.0`, shopper and retailer prices are separate fields. In `v3.0`, they are grouped under `retailer` and `shopper`.

**Total price**

{% tabs %}
{% tab title="v2.0" %}
{% code title="checkout-total-v2.json" %}

```json
{
  "retailerCurrencyPaymentAmount": "EUR123.45",
  "shopperCurrencyPaymentAmount": "USD123.45"
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="checkout-total-v3.json" %}

```json
{
  "checkoutTotal": {
    "retailer": {
      "currency": "EUR",
      "amount": "123.45"
    },
    "shopper": {
      "currency": "USD",
      "amount": "123.45"
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

**Charges**

{% tabs %}
{% tab title="v2.0" %}
{% code title="charges-v2.json" %}

```json
{
  "shopperCurrencyItemUplift": "EUR123.45",
  "retailerCurrencyItemUplift": "USD123.45"
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="charges-v3.json" %}

```json
{
  "charges": {
    "uplift": {
      "retailer": {
        "currency": "EUR",
        "amount": "123.45"
      },
      "shopper": {
        "currency": "USD",
        "amount": "123.45"
      }
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

**Discounts**

{% tabs %}
{% tab title="v2.0" %}
{% code title="discount-v2.json" %}

```json
{
  "retailerCurrencyProductPriceInfo": {
    "beforeDiscount": "EUR123.45"
  },
  "shopperCurrencyProductPriceInfo": {
    "beforeDiscount": "USD123.45"
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="discount-v3.json" %}

```json
{
  "discount": {
    "retailer": {
      "currency": "EUR",
      "amount": "123.45"
    },
    "shopper": {
      "currency": "USD",
      "amount": "123.45"
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Order items field

In `v2.0`, order items are in `lineItems`. In `v3.0`, order items are in `cartItems`.

{% tabs %}
{% tab title="v2.0" %}
{% code title="line-items-v2.json" %}

```json
{
  "lineItems": [
    {
      "quantity": 1,
      "product": {
        "productCode": "ABCD123",
        "title": "Black Dress"
      }
    }
  ]
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="cart-items-v3.json" %}

```json
{
  "cartItems": [
    {
      "quantity": 1,
      "product": {
        "productCode": "ABCD123",
        "title": "Black Dress"
      }
    }
  ]
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Multiple discounts

`v2.0` supports one discount amount per price field. `v3.0` supports multiple discounts at line item, cart, or delivery option level.

In `v3.0`, the currency type does not need separate shopper or retailer field names. It is derived from the retailer configuration set during onboarding.

**Product discounts**

{% tabs %}
{% tab title="v2.0" %}
{% code title="product-discounts-v2.json" %}

```json
{
  "retailerCurrencyProductPriceInfo": {
    "beforeDiscount": "EUR123.45",
    "discountAmount": "EUR123.45",
    "price": "EUR123.45",
    "title": "Season discount",
    "description": "Winter season discount"
  },
  "shopperCurrencyProductPriceInfo": {
    "beforeDiscount": "USD123.45",
    "discountAmount": "USD123.45",
    "price": "USD123.45",
    "title": "Season discount",
    "description": "Winter season discount"
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="product-discounts-v3.json" %}

```json
{
  "productUnitPriceInfo": {
    "price": {
      "retailer": {
        "currency": "EUR",
        "amount": "123.45"
      },
      "shopper": {
        "currency": "USD",
        "amount": "123.45"
      }
    },
    "discounts": [
      {
        "title": "Season discount",
        "description": "Winter season discount",
        "discount": {
          "retailer": {
            "currency": "EUR",
            "amount": "123.45"
          },
          "shopper": {
            "currency": "USD",
            "amount": "123.45"
          }
        },
        "beforeDiscount": {
          "retailer": {
            "currency": "EUR",
            "amount": "123.45"
          },
          "shopper": {
            "currency": "USD",
            "amount": "123.45"
          }
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

**Cart discounts**

{% tabs %}
{% tab title="v2.0" %}
{% code title="cart-discounts-v2.json" %}

```json
{
  "cartDiscounts": [
    {
      "title": "Season discount",
      "description": "Winter season discount",
      "retailerCurrencyCartDiscountAmount": {
        "beforeDiscount": "EUR123.45",
        "discountAmount": "EUR123.45",
        "price": "EUR123.45",
        "title": "Season discount",
        "description": "Winter season discount"
      },
      "shopperCurrencyCartDiscountAmount": {
        "beforeDiscount": "USD123.45",
        "discountAmount": "USD123.45",
        "price": "USD123.45",
        "title": "Season discount",
        "description": "Winter season discount"
      }
    }
  ]
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="cart-discounts-v3.json" %}

```json
{
  "cartDiscountPriceInfo": {
    "price": {
      "retailer": {
        "currency": "EUR",
        "amount": "123.45"
      },
      "shopper": {
        "currency": "USD",
        "amount": "123.45"
      }
    },
    "discounts": [
      {
        "title": "Season discount",
        "description": "Winter season discount",
        "discount": {
          "retailer": {
            "currency": "EUR",
            "amount": "123.45"
          },
          "shopper": {
            "currency": "USD",
            "amount": "123.45"
          }
        },
        "beforeDiscount": {
          "retailer": {
            "currency": "EUR",
            "amount": "123.45"
          },
          "shopper": {
            "currency": "USD",
            "amount": "123.45"
          }
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

**Delivery option discounts**

{% tabs %}
{% tab title="v2.0" %}
{% code title="delivery-discounts-v2.json" %}

```json
{
  "deliveryOption": {
    "deliveryOption": "Post",
    "retailerCurrencyDeliveryPriceInfo": {
      "beforeDiscount": "EUR123.45",
      "discountAmount": "EUR123.45",
      "price": "EUR123.45",
      "title": "Season discount",
      "description": "Winter season discount"
    },
    "shopperCurrencyDeliveryPriceInfo": {
      "beforeDiscount": "USD123.45",
      "discountAmount": "USD123.45",
      "price": "USD123.45",
      "title": "Season discount",
      "description": "Winter season discount"
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="delivery-discounts-v3.json" %}

```json
{
  "deliveryOptions": [
    {
      "deliveryOption": "Post",
      "deliveryOptionOverridePriceInfo": {
        "price": {
          "retailer": {
            "currency": "EUR",
            "amount": "123.45"
          },
          "shopper": {
            "currency": "USD",
            "amount": "123.45"
          }
        },
        "discounts": [
          {
            "title": "Season discount",
            "description": "Winter season discount",
            "discount": {
              "retailer": {
                "currency": "EUR",
                "amount": "123.45"
              },
              "shopper": {
                "currency": "USD",
                "amount": "123.45"
              }
            },
            "beforeDiscount": {
              "retailer": {
                "currency": "EUR",
                "amount": "123.45"
              },
              "shopper": {
                "currency": "USD",
                "amount": "123.45"
              }
            }
          }
        ]
      }
    }
  ]
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Payment details

In `v2.0`, payment fields are at the root level. In `v3.0`, they are grouped inside `paymentDetails`.

{% tabs %}
{% tab title="v2.0" %}
{% code title="payment-details-v2.json" %}

```json
{
  "paymentTime": "2020-04-91T14:01:01.8876807Z",
  "paymentMethod": "PaymentCard",
  "paymentMethodCardBrand": "Visa"
}
```

{% endcode %}
{% endtab %}

{% tab title="v3.0" %}
{% code title="payment-details-v3.json" %}

```json
{
  "paymentDetails": {
    "time": "2020-04-91T14:01:01.8876807Z",
    "method": "PaymentCard",
    "methodCardBrand": "Visa"
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Responding to the webhook

ESW expects a standard HTTP response with an appropriate status code.

If delivery fails because of endpoint or transport issues, ESW retries three times. The retry intervals are `1.25`, `1.5`, and `2` seconds.

If all attempts fail, ESW treats the request as failed. ESW logs all requests sent to your webhook endpoint.

ESW continues its internal workflow regardless of your HTTP response. Returning `4xx` or `5xx` does not stop processing.

If ESW receives an unsuccessful response, it marks the order as canceled.

For `4xx` or `5xx` responses, include an error code and message. This makes diagnosis faster.

Use a structure like this for detailed failures:

{% code title="error-response.http" %}

```http
HTTP/1.1 500 Internal Server Error
Date: Sun, 12 Jan 2021 00:00:00 UTC
Server: HAL-9000
Content-Length: xxx
Connection: Closed
Content-Type: application/json; charset=utf-8

[
  {
    "code": "AE-35",
    "message": "Internal failure"
  }
]
```

{% endcode %}

### Order Confirmation processing types

ESW supports two processing modes:

1. Synchronous
2. Asynchronous

#### Difference between synchronous and asynchronous processing

In synchronous mode, the shopper is redirected to the Order Confirmation page only after backend processing completes. In asynchronous mode, the shopper is redirected immediately after successful payment.

Key points:

* Order Confirmation processing is synchronous by default.
* Both modes use the same JSON request and response schema.
* Your endpoint receives the same JSON payload in both modes.
* ESW expects the same response format in both modes.

#### Timing

{% tabs %}
{% tab title="Synchronous" %}

* The order is fully confirmed before the shopper is redirected.
* ESW captures payment.
* ESW sends an Order Confirmation request to the retailer.
* ESW waits for the retailer response.
* ESW sends the Order Confirmation request to ESW OMS.
* ESW waits for the ESW OMS response.
* The shopper is redirected only after this flow completes.
* This can appear slower.
* The overall delay depends mainly on your API response time.
  {% endtab %}

{% tab title="Asynchronous" %}

* The shopper is redirected before order confirmation fully completes.
* Order confirmation continues in the background.
* This usually feels faster to the shopper.
* If ESW does not get a response from the retailer API, it retries three times.
* The total timeout window is about two minutes.
* If ESW still gets no response, ESW cancels the order in ESW OMS and issues a refund.
  {% endtab %}
  {% endtabs %}

#### Order confirmation number behavior

{% tabs %}
{% tab title="Synchronous" %}

* `retailerCartId` is the default order confirmation number.
* You can send an Order Confirmation number back to ESW.
* That number appears on the Order Confirmation page when it loads.
* The number must be generated by the retailer.
* This field is optional.
* If omitted, ESW uses the `retailerCartId` sent in preorder.

You must implement a fallback mechanism so ESW order numbers stay aligned with your native system. If not, order numbering mismatches can become irreversible.

{% code title="order-confirmation-response.json" %}

```json
{
  "orderNumber": "string",
  "errors": [
    {
      "message": "Error message",
      "code": 2
    }
  ]
}
```

{% endcode %}
{% endtab %}

{% tab title="Asynchronous" %}

* You can also use an Order Confirmation number in async flow.
* Shopper-facing behavior is different.
* If a new order number is provided, it appears after confirmation.
* The shopper may need to refresh the page to see the updated value.
* The interim UI renders while the order status is `OrderBeingProcessed`.
* The updated UI renders when the order status is `OrderCompleted`.
  {% endtab %}
  {% endtabs %}

#### Enabling

{% tabs %}
{% tab title="Synchronous" %}

* No extra ESW configuration is required.
* Synchronous processing is enabled by default.
* ESW configures the retailer production endpoint to receive the Order Confirmation request.
  {% endtab %}

{% tab title="Asynchronous" %}

* Additional ESW configuration is required.
* Speak to your ESW contact for setup details.
  {% endtab %}
  {% endtabs %}

### Delivery headers

These headers are used only for the asynchronous flow.

| Header            | Description                                                                                                                                                                             |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Esw-Delivery`    | UUID that identifies a specific delivery attempt.                                                                                                                                       |
| `Esw-Event-Type`  | Event type name that identifies the payload version. Possible values include `Esw.Messages.Checkout.Order.v2.OrderConfirmation` and `Esw.Messages.Checkout.Order.v3.OrderConfirmation`. |
| `Idempotency-Key` | UUID shared across all delivery attempts for the same message.                                                                                                                          |

### Delivery examples

#### Synchronous flow

{% code title="sync-request.http" %}

```http
POST /eventSink HTTP/1.1
Host: example.com
Authorization: Bearer xxxxxx
Content-Type: application/json
Content-Length: xxx

{
  "RetailerCartId": "CART#12345",
  "EShopWorldOrderNumber": "226adddf-debd-4ee8-b9b3-5ccb616adcab"
}
```

{% endcode %}

#### Asynchronous flow

{% code title="async-request.http" %}

```http
POST /eventSink HTTP/1.1
Host: example.com
Esw-Delivery: 6a33eceb-de58-4f54-9d00-176cc9508222
Esw-Event-Type: Esw.Messages.Checkout.Order.v3.OrderConfirmation
Idempotency-Key: 337b071c56f843d8983ac4a7deddbd1a
Authorization: Bearer xxxxxx
Content-Type: application/json
Content-Length: xxx

{
  "RetailerCartId": "CART#12345",
  "EShopWorldOrderNumber": "226adddf-debd-4ee8-b9b3-5ccb616adcab"
}
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.esw.com/checkout-api/resources/order-confirmation-webhook.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
