# Estimate Cart

Using the Estimate Cart endpoint you can discover the estimated totals and available shipping methods for any combination of Sku's and a shipping address. This feature can be useful for debugging failed carts where one or more Sku's may have been unavailable in a certain region or no shipping methods were returned for an address.

{% hint style="info" %}
Cart estimation is not a part of the checkout process and is instead best used as a method for anticipating the behavior of a cart or debugging a failed cart.
{% endhint %}

When using Estimate Cart you do not need to manage the lifecycle of a cart. Violet will handle the creation, modification, and deletion of any external carts that may need to be created while estimating a cart.

When the Estimate Cart process fails in the external commerce platform, Violet will attempt to parse and surface all error messages from the external system so that you are able to fully understand why the estimation failed. The most common reasons for failure will be Sku unavailability and incorrectly formatted shipping addresses.

***

### Response Behavior

#### SKU Availability

Each SKU in the response includes an `available` boolean field indicating whether the item can be purchased. When a SKU is unavailable (e.g., out of stock, discontinued, or region-restricted), the `available` field will be `false`.

```json
{
  "skus": [
    {
      "sku_id": 10000,
      "name": "Nintendo Entertainment System",
      "available": true,
      "price": 9999,
      "quantity": 2,
      "line_price": 19998
    },
    {
      "sku_id": 10001,
      "name": "Discontinued Controller",
      "available": false,
      "price": 2999,
      "quantity": 1,
      "line_price": 2999
    }
  ]
}
```

{% hint style="warning" %}
SKUs with `available: false` are still included in the response but should not be used in cart creation. Always check this field before proceeding to checkout.
{% endhint %}

#### Inventory Information (BETA)

For supported platforms, SKUs may include an `inventory` object with detailed stock information:

| Field                  | Type    | Description                                                  |
| ---------------------- | ------- | ------------------------------------------------------------ |
| `sufficient_inventory` | Boolean | Whether there is enough inventory for the requested quantity |
| `available_inventory`  | Integer | The total quantity available for purchase                    |

```json
{
  "sku_id": 10000,
  "name": "Nintendo Entertainment System",
  "available": true,
  "quantity": 5,
  "inventory": {
    "sufficient_inventory": false,
    "available_inventory": 3
  }
}
```

{% hint style="info" %}
The `inventory` object is currently in BETA and may not be available for all merchants or platforms.
{% endhint %}

#### External Error Messages

Each estimated cart may include an `external_error_messages` array containing raw error strings from the commerce platform. These messages provide additional context when estimation fails or encounters issues.

```json
{
  "merchant_id": 10000,
  "platform": "SHOPIFY",
  "external_error_messages": [
    "The requested quantity is not available",
    "Cannot ship to the provided address"
  ]
}
```

**Interpreting Error Messages**

The `external_error_messages` array contains raw error strings from commerce platforms. While these messages vary by platform and aren't suitable for programmatic parsing, they're valuable for:

1. **Your support team** — Full messages help diagnose issues without escalation
2. **End users** — Provides context about what went wrong (display directly or use to craft friendly messages)
3. **Escalation to Violet** — Include these messages when contacting support for faster resolution

| Scenario                      | `skus` array                                              | `external_error_messages`                 | Recommended Action                                                             |
| ----------------------------- | --------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------ |
| SKU unavailable               | Contains SKU with `available: false`                      | May contain product name                  | Log message for support; show user the SKU is unavailable                      |
| Insufficient inventory (BETA) | Contains SKU with `inventory.sufficient_inventory: false` | May show quantity details                 | Display message to user; log for troubleshooting                               |
| Merchant unreachable          | Empty or missing                                          | Contains errors like "HTTP 404 Not Found" | **Merchant-level failure** — log for ops team; mark all merchant items invalid |
| Invalid discount              | SKUs present (may be available)                           | Contains discount error                   | Display to user; discount issue doesn't affect SKU availability                |

{% hint style="info" %}
**Best Practice:** Use structured fields (`available`, `inventory`) for validation logic. Log `external_error_messages` for troubleshooting and display them to users for context. These messages are the most detailed diagnostic information available when platform issues occur.
{% endhint %}

**Non-Tracked Inventory**

Some merchants don't track inventory. In these cases:

* `available` will be `true` (the item can be purchased)
* `available_inventory` may be `0`, negative, or absent

Always trust the `available` boolean as the primary indicator. Only use `inventory` fields when they're present AND the merchant tracks inventory.

***

### Handling Estimation Errors

{% hint style="warning" %}
**Important:** For multi-merchant carts, the API may return HTTP 200 even when individual merchants fail. Always check the `errors` array regardless of HTTP status code.
{% endhint %}

#### Single-Merchant Estimation Errors

When estimating a cart with SKUs from a single merchant fails, the error will be surfaced as an API Exception in the response body with a `400` or `422` HTTP status.

<sub>Example: Response when single-merchant estimation fails due to an unavailable SKU.</sub>

```json
{
  "message": "This item is no longer available for purchase.",
  "error": "sku_not_available",
  "code": 4223,
  "data": {
    "skus": [
      {
        "message": "This item is no longer available for purchase.",
        "name": "Nintendo Entertainment System",
        "sku_id": 99999
      }
    ]
  }
}
```

#### Multi-Merchant Estimation Errors

When estimating a cart with SKUs from multiple merchants, the response will return HTTP 200 with any errors nested in the `errors` array. Valid SKUs from successful merchants will still be included in `estimated_carts`.

<sub>Example: Response when one merchant fails while another succeeds. The</sub> <sub></sub><sub>`entity_type`</sub> <sub></sub><sub>of</sub> <sub></sub><sub>`SKU`</sub> <sub></sub><sub>indicates which SKU caused the error, referenced by</sub> <sub></sub><sub>`entity_id`</sub><sub>.</sub>

```json
{
  "estimated_carts": [
    {
      "merchant_id": 10000,
      "platform": "SHOPIFY",
      "sub_total": 19998,
      "shipping_total": 500,
      "tax_total": 2000,
      "total": 22498,
      "skus": [
        {
          "sku_id": 10000,
          "name": "Nintendo Entertainment System",
          "available": true,
          "price": 9999,
          "quantity": 2,
          "line_price": 19998
        }
      ],
      "available_shipping_methods": [
        {
          "label": "Standard Shipping",
          "carrier": "USPS",
          "price": 500,
          "shipping_method_id": "abc123"
        }
      ],
      "has_shipping_methods": true
    }
  ],
  "errors": [
    {
      "id": 55555,
      "bag_id": 77777,
      "entity_id": "99999",
      "entity_type": "SKU",
      "message": "This item is no longer available for purchase.",
      "date_created": "2023-11-07T05:31:56Z",
      "platform": "BIGCOMMERCE"
    }
  ]
}
```

#### Common Error Codes

| Code | Error                      | Description                                          |
| ---- | -------------------------- | ---------------------------------------------------- |
| 2002 | `sku_not_found`            | The requested SKU does not exist in Violet's catalog |
| 2003 | `sku_not_available`        | The SKU exists but is currently unavailable          |
| 4219 | `order_sku_not_available`  | The SKU is no longer available for purchase          |
| 4223 | `insufficient_inventory`   | Not enough inventory for the requested quantity      |
| 4232 | `invalid_shipping_address` | The provided shipping address is invalid             |
| 4236 | `blocked_address`          | The address has been blocked due to fraud history    |

***

### Response Examples

#### Successful Estimation (All SKUs Available)

```json
{
  "estimated_carts": [
    {
      "merchant_id": 10000,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 19998,
      "shipping_total": 500,
      "tax_total": 2000,
      "discount_total": 0,
      "total": 22498,
      "skus": [
        {
          "sku_id": 10000,
          "name": "Nintendo Entertainment System",
          "price": 9999,
          "quantity": 2,
          "line_price": 19998,
          "merchant_id": 10000,
          "external_id": "31516807528534",
          "available": true,
          "requires_shipping": true,
          "product_type": "PHYSICAL"
        }
      ],
      "available_shipping_methods": [
        {
          "label": "Free Shipping",
          "carrier": "OTHER",
          "price": 0,
          "shipping_method_id": "18ff5c0a16d83cb8ba46848e48e06532"
        },
        {
          "label": "Ground Advantage",
          "carrier": "USPS",
          "price": 712,
          "shipping_method_id": "468c823c817c753e850ff6658ef1480f"
        },
        {
          "label": "Priority Mail",
          "carrier": "USPS",
          "price": 934,
          "shipping_method_id": "02ef65ebff687faa10c71830d41144b2"
        }
      ],
      "has_shipping_methods": true,
      "external_error_messages": []
    }
  ],
  "errors": []
}
```

#### Partial Availability (Some SKUs Unavailable)

When some SKUs in a single-merchant cart are unavailable, they will be included in the response with `available: false`. The totals will only reflect the available items.

```json
{
  "estimated_carts": [
    {
      "merchant_id": 10000,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 9999,
      "shipping_total": 500,
      "tax_total": 1050,
      "discount_total": 0,
      "total": 11549,
      "skus": [
        {
          "sku_id": 10000,
          "name": "Nintendo Entertainment System",
          "price": 9999,
          "quantity": 1,
          "line_price": 9999,
          "available": true,
          "requires_shipping": true,
          "product_type": "PHYSICAL"
        },
        {
          "sku_id": 10001,
          "name": "Discontinued Controller",
          "price": 2999,
          "quantity": 1,
          "line_price": 2999,
          "available": false,
          "requires_shipping": true,
          "product_type": "PHYSICAL"
        }
      ],
      "available_shipping_methods": [
        {
          "label": "Standard Shipping",
          "carrier": "USPS",
          "price": 500,
          "shipping_method_id": "abc123"
        }
      ],
      "has_shipping_methods": true
    }
  ],
  "errors": []
}
```

#### Insufficient Inventory

When the requested quantity exceeds available stock, the `inventory` object (when available) provides details:

```json
{
  "estimated_carts": [
    {
      "merchant_id": 10000,
      "platform": "SHOPIFY",
      "sub_total": 49995,
      "shipping_total": 1500,
      "tax_total": 5000,
      "total": 56495,
      "skus": [
        {
          "sku_id": 10000,
          "name": "Nintendo Entertainment System",
          "price": 9999,
          "quantity": 5,
          "line_price": 49995,
          "available": true,
          "inventory": {
            "sufficient_inventory": false,
            "available_inventory": 3
          },
          "requires_shipping": true,
          "product_type": "PHYSICAL"
        }
      ],
      "has_shipping_methods": true,
      "external_error_messages": [
        "Insufficient inventory for item with ID 10000."
      ]
    }
  ],
  "errors": []
}
```

***

### Best Practices

#### Recommended Implementation Pattern

```javascript
async function validateSkus(skuIds, shippingAddress) {
  const response = await estimateCart({
    skus: skuIds,
    shipping_address: shippingAddress
  });

  // Check HTTP status first (single-merchant failures)
  if (response.status >= 400) {
    return {
      valid: [],
      invalid: response.data.skus.map(s => ({
        sku_id: s.sku_id,
        message: s.message
      }))
    };
  }

  // Multi-merchant or success - check errors array
  const validSkuIds = new Set();
  response.estimated_carts.forEach(cart => {
    cart.skus
      .filter(sku => sku.available)
      .forEach(sku => validSkuIds.add(sku.sku_id));
  });

  const invalidSkus = response.errors
    ?.filter(e => e.entity_type === 'SKU')
    .map(e => ({ sku_id: e.entity_id, message: e.message })) || [];

  return {
    valid: Array.from(validSkuIds),
    invalid: invalidSkus
  };
}
```

#### Common Use Cases

| Use Case                | What to Check                                                                |
| ----------------------- | ---------------------------------------------------------------------------- |
| Pre-checkout validation | `available` field on each SKU                                                |
| Inventory management    | `inventory.sufficient_inventory` and `inventory.available_inventory`         |
| Shipping availability   | `has_shipping_methods` and `available_shipping_methods` array                |
| Debugging failed carts  | `errors` array and `external_error_messages`                                 |
| Multi-merchant carts    | Check each `estimated_cart` individually; some may succeed while others fail |

***

{% openapi src="<https://3937396275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8lXIp71Ct5qCUhXjko2q%2Fuploads%2Fgit-blob-8ab007712b2fb1063fba6d0d5fac84738eef8644%2Forder-service.yaml?alt=media>" path="/carts/estimate" method="post" expanded="true" %}
[order-service.yaml](https://3937396275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8lXIp71Ct5qCUhXjko2q%2Fuploads%2Fgit-blob-8ab007712b2fb1063fba6d0d5fac84738eef8644%2Forder-service.yaml?alt=media)
{% endopenapi %}
