# Calculate a cart

URL: https://docs.sparklayer.io/developers/api/ordering/calculate-cart
Operation: `POST /api/v1/carts/{id}/calculate` (operationId `calculateCart`)
OpenAPI spec: https://docs.sparklayer.io/openapi/ordering.yaml

Calculates the cart's totals, tax, available shipping methods and allowed payment methods, optionally for the shipping rate given in `shipping_rate_handle`. Returns `422` with the error code `cart-empty` if the cart has no items, or `cart-shipping-rate-handle-unavailable` if the SparkLayer shipping rate you chose isn't available for this cart.

`POST /api/v1/carts/{id}/calculate`

**Base URLs:** `https://app.sparklayer.io` (Live), `https://test.app.sparklayer.io` (Test)

**Authentication:** send `Authorization: Bearer <access_token>` and `Site-Id: <site id>` with every request. Get the token from [Get an access token](https://docs.sparklayer.io/developers/api/core/get-an-access-token.md); see [Authentication](https://docs.sparklayer.io/developers/authentication.md).

### Example request

```bash
curl -X POST "https://app.sparklayer.io/api/v1/carts/9151f21f-43ae-43b4-92f3-f4af67cdf544/calculate" \
  -H "Authorization: Bearer $SPARKLAYER_TOKEN" \
  -H "Site-Id: $SPARKLAYER_SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "shipping_rate_handle": "<shipping_rate_handle>"
}'
```

Set `SPARKLAYER_TOKEN` to an access token and `SPARKLAYER_SITE_ID` to your Site ID. For the test environment, use `https://test.app.sparklayer.io`.

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | The cart's ID: the `cart_id` returned by **Create a cart**. Example: `9151f21f-43ae-43b4-92f3-f4af67cdf544` |

### Header parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Site-Id` | string | Yes | Your SparkLayer Site ID, from Settings > API in the SparkLayer Dashboard. Example: `jones-climbing` |

### Request body (`application/json`) (optional)

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `shipping_rate_handle` | string \| null | | Omitting this will set the carts shipping handle to the first available |

```json
{
  "shipping_rate_handle": "<shipping_rate_handle>"
}
```

### Responses

#### 200: The cart's totals, available shipping methods and allowed payment methods.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `totals` | object | | |
| `totals.total` | object | | |
| `totals.total.pre_discount` | object | | |
| `totals.total.pre_discount.net` | object | | |
| `totals.total.pre_discount.net.amount` | string | | |
| `totals.total.pre_discount.net.currency_code` | string | | |
| `totals.total.pre_discount.gross` | object | | |
| `totals.total.pre_discount.gross.amount` | string | | |
| `totals.total.pre_discount.gross.currency_code` | string | | |
| `totals.total.pre_discount.tax` | object | | |
| `totals.total.pre_discount.tax.amount` | string | | |
| `totals.total.pre_discount.tax.currency_code` | string | | |
| `totals.total.pre_discount.apportioned_tax_rate` | number (float) | | |
| `totals.total.pre_discount.currency` | string | | |
| `totals.total.discount` | object \| null | | |
| `totals.total.discount.net` | object | | |
| `totals.total.discount.net.amount` | string | | |
| `totals.total.discount.net.currency_code` | string | | |
| `totals.total.discount.gross` | object | | |
| `totals.total.discount.gross.amount` | string | | |
| `totals.total.discount.gross.currency_code` | string | | |
| `totals.total.discount.tax` | object | | |
| `totals.total.discount.tax.amount` | string | | |
| `totals.total.discount.tax.currency_code` | string | | |
| `totals.total.discount.apportioned_tax_rate` | number (float) | | |
| `totals.total.discount.currency` | string | | |
| `totals.total.charge` | object | | |
| `totals.total.charge.net` | object | | |
| `totals.total.charge.net.amount` | string | | |
| `totals.total.charge.net.currency_code` | string | | |
| `totals.total.charge.gross` | object | | |
| `totals.total.charge.gross.amount` | string | | |
| `totals.total.charge.gross.currency_code` | string | | |
| `totals.total.charge.tax` | object | | |
| `totals.total.charge.tax.amount` | string | | |
| `totals.total.charge.tax.currency_code` | string | | |
| `totals.total.charge.apportioned_tax_rate` | number (float) | | |
| `totals.total.charge.currency` | string | | |
| `totals.shipping` | object | | |
| `totals.shipping.pre_discount` | object | | |
| `totals.shipping.pre_discount.net` | object | | |
| `totals.shipping.pre_discount.net.amount` | string | | |
| `totals.shipping.pre_discount.net.currency_code` | string | | |
| `totals.shipping.pre_discount.gross` | object | | |
| `totals.shipping.pre_discount.gross.amount` | string | | |
| `totals.shipping.pre_discount.gross.currency_code` | string | | |
| `totals.shipping.pre_discount.tax` | object | | |
| `totals.shipping.pre_discount.tax.amount` | string | | |
| `totals.shipping.pre_discount.tax.currency_code` | string | | |
| `totals.shipping.pre_discount.apportioned_tax_rate` | number (float) | | |
| `totals.shipping.pre_discount.currency` | string | | |
| `totals.shipping.discount` | object \| null | | |
| `totals.shipping.discount.net` | object | | |
| `totals.shipping.discount.net.amount` | string | | |
| `totals.shipping.discount.net.currency_code` | string | | |
| `totals.shipping.discount.gross` | object | | |
| `totals.shipping.discount.gross.amount` | string | | |
| `totals.shipping.discount.gross.currency_code` | string | | |
| `totals.shipping.discount.tax` | object | | |
| `totals.shipping.discount.tax.amount` | string | | |
| `totals.shipping.discount.tax.currency_code` | string | | |
| `totals.shipping.discount.apportioned_tax_rate` | number (float) | | |
| `totals.shipping.discount.currency` | string | | |
| `totals.shipping.charge` | object | | |
| `totals.shipping.charge.net` | object | | |
| `totals.shipping.charge.net.amount` | string | | |
| `totals.shipping.charge.net.currency_code` | string | | |
| `totals.shipping.charge.gross` | object | | |
| `totals.shipping.charge.gross.amount` | string | | |
| `totals.shipping.charge.gross.currency_code` | string | | |
| `totals.shipping.charge.tax` | object | | |
| `totals.shipping.charge.tax.amount` | string | | |
| `totals.shipping.charge.tax.currency_code` | string | | |
| `totals.shipping.charge.apportioned_tax_rate` | number (float) | | |
| `totals.shipping.charge.currency` | string | | |
| `totals.sub_total` | object | | |
| `totals.sub_total.pre_discount` | object | | |
| `totals.sub_total.pre_discount.net` | object | | |
| `totals.sub_total.pre_discount.net.amount` | string | | |
| `totals.sub_total.pre_discount.net.currency_code` | string | | |
| `totals.sub_total.pre_discount.gross` | object | | |
| `totals.sub_total.pre_discount.gross.amount` | string | | |
| `totals.sub_total.pre_discount.gross.currency_code` | string | | |
| `totals.sub_total.pre_discount.tax` | object | | |
| `totals.sub_total.pre_discount.tax.amount` | string | | |
| `totals.sub_total.pre_discount.tax.currency_code` | string | | |
| `totals.sub_total.pre_discount.apportioned_tax_rate` | number (float) | | |
| `totals.sub_total.pre_discount.currency` | string | | |
| `totals.sub_total.discount` | object \| null | | |
| `totals.sub_total.discount.net` | object | | |
| `totals.sub_total.discount.net.amount` | string | | |
| `totals.sub_total.discount.net.currency_code` | string | | |
| `totals.sub_total.discount.gross` | object | | |
| `totals.sub_total.discount.gross.amount` | string | | |
| `totals.sub_total.discount.gross.currency_code` | string | | |
| `totals.sub_total.discount.tax` | object | | |
| `totals.sub_total.discount.tax.amount` | string | | |
| `totals.sub_total.discount.tax.currency_code` | string | | |
| `totals.sub_total.discount.apportioned_tax_rate` | number (float) | | |
| `totals.sub_total.discount.currency` | string | | |
| `totals.sub_total.charge` | object | | |
| `totals.sub_total.charge.net` | object | | |
| `totals.sub_total.charge.net.amount` | string | | |
| `totals.sub_total.charge.net.currency_code` | string | | |
| `totals.sub_total.charge.gross` | object | | |
| `totals.sub_total.charge.gross.amount` | string | | |
| `totals.sub_total.charge.gross.currency_code` | string | | |
| `totals.sub_total.charge.tax` | object | | |
| `totals.sub_total.charge.tax.amount` | string | | |
| `totals.sub_total.charge.tax.currency_code` | string | | |
| `totals.sub_total.charge.apportioned_tax_rate` | number (float) | | |
| `totals.sub_total.charge.currency` | string | | |
| `discounts` | any[] | | |
| `shipping_methods` | object[] | | |
| `shipping_methods[].title` | string | | |
| `shipping_methods[].description` | string \| null | | |
| `shipping_methods[].price_v2` | object | | |
| `shipping_methods[].price_v2.net` | number (float) | | |
| `shipping_methods[].price_v2.gross` | number (float) | | |
| `shipping_methods[].price_v2.tax_rate` | number (float) \| null | | |
| `shipping_methods[].price_v2.currency_code` | string | | |
| `shipping_methods[].price_v2.tax_inclusive_display` | boolean | | Whether the storefront should show the gross amount and label it tax inclusive. Not derivable from tax_rate, since a zero-rated SKU on a tax-inclusive price list has a rate of 0 but must still be labelled. Display only - it says nothing about what is charged. Default: `false`. |
| `shipping_methods[].price_v2_pre_discount` | object \| null | | |
| `shipping_methods[].price_v2_pre_discount.net` | number (float) | | |
| `shipping_methods[].price_v2_pre_discount.gross` | number (float) | | |
| `shipping_methods[].price_v2_pre_discount.tax_rate` | number (float) \| null | | |
| `shipping_methods[].price_v2_pre_discount.currency_code` | string | | |
| `shipping_methods[].price_v2_pre_discount.tax_inclusive_display` | boolean | | Whether the storefront should show the gross amount and label it tax inclusive. Not derivable from tax_rate, since a zero-rated SKU on a tax-inclusive price list has a rate of 0 but must still be labelled. Display only - it says nothing about what is charged. Default: `false`. |
| `shipping_methods[].handle` | string | | |
| `shipping_methods[].cost_type` | string | | |
| `shipping_methods[].cost_language_string` | string \| null | | |
| `allowed_payment_methods` | object | | |
| `allowed_payment_methods.payment_by_invoice` | "AVAILABLE" \| "DISABLED" | | |
| `allowed_payment_methods.payment_on_account` | "AVAILABLE" \| "DISABLED" \| "UNAVAILABLE_DUE_TO_CREDIT" \| "AVAILABLE_CREDIT_LIMIT_HIT" | | |
| `allowed_payment_methods.upfront_payment` | "AVAILABLE" \| "DISABLED" | | |
| `allowed_payment_methods.quote` | "AVAILABLE" \| "DISABLED" | | |
| `selected_shipping_rate_handle` | string \| null | | |
| `selected_payment_method` | string \| null | | |

```json
{
  "totals": {
    "total": {
      "pre_discount": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      },
      "discount": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      },
      "charge": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      }
    },
    "shipping": {
      "pre_discount": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      },
      "discount": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      },
      "charge": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      }
    },
    "sub_total": {
      "pre_discount": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      },
      "discount": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      },
      "charge": {
        "net": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "gross": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "tax": {
          "amount": "<amount>",
          "currency_code": "<currency_code>"
        },
        "apportioned_tax_rate": 0,
        "currency": "<currency>"
      }
    }
  },
  "discounts": [],
  "shipping_methods": [
    {
      "title": "<title>",
      "description": "<description>",
      "price_v2": {
        "net": 0,
        "gross": 0,
        "tax_rate": 0,
        "currency_code": "<currency_code>",
        "tax_inclusive_display": false
      },
      "price_v2_pre_discount": {
        "net": 0,
        "gross": 0,
        "tax_rate": 0,
        "currency_code": "<currency_code>",
        "tax_inclusive_display": false
      },
      "handle": "<handle>",
      "cost_type": "<cost_type>",
      "cost_language_string": "<cost_language_string>"
    }
  ],
  "allowed_payment_methods": {
    "payment_by_invoice": "AVAILABLE",
    "payment_on_account": "AVAILABLE",
    "upfront_payment": "AVAILABLE",
    "quote": "AVAILABLE"
  },
  "selected_shipping_rate_handle": "<selected_shipping_rate_handle>",
  "selected_payment_method": "<selected_payment_method>"
}
```

#### 404: Cart not found

#### 422: The cart is empty (`cart-empty`) or the chosen shipping rate isn't available (`cart-shipping-rate-handle-unavailable`). See [Cart errors](https://docs.sparklayer.io/developers/errors.md#cart-errors).

One of these:

**CartErrorResponse**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `detail` | string | | Human-readable summary of the error |
| `status` | 422 | | HTTP Status code returned from API |
| `title` | "cart-error" | | Machine-readable error code |
| `type` | string \| null | | |
| `errors` | object[] \| null | | A list of errors related to the call |
| `errors[].code` | "cart-shipping-rate-handle-unavailable" \| "cart-customer-not-found" \| "cart-impersonator-user-not-found" \| "cart-payment-method-unavailable" | | Machine-readable error code |

- **Error**: the standard error body (below).

```json
{
  "detail": "Cart error occurred",
  "status": 422,
  "title": "cart-error",
  "type": "https://docs.sparklayer.io/api/errors#invalid-api-request-contents",
  "errors": [
    {
      "code": "cart-shipping-rate-handle-unavailable"
    }
  ]
}
```

#### Other statuses: An error. The body describes the problem: see [Errors](https://docs.sparklayer.io/developers/errors.md).

`application/problem+json`: the standard error body (below).

### Error body

Error responses with a body use this RFC 7807 problem details object. See [Errors](https://docs.sparklayer.io/developers/errors.md) for every status code and which errors to retry.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `detail` | string | | Human-readable summary of the error |
| `status` | integer | | HTTP Status code returned from API |
| `title` | string | | Machine-readable error code |
| `type` | string \| null | | |
| `errors` | object[] \| null | | A list of errors related to the call |
| `errors[].code` | string | | Machine-readable error code |
| `errors[].property` | string | | The property the error relates to |
| `errors[].message` | string | | Human readable summary of the error |

```json
{
  "detail": "Data Validation Failed",
  "status": 400,
  "title": "invalid-api-request-contents",
  "type": "https://docs.sparklayer.io/api/errors#invalid-api-request-contents",
  "errors": [
    {
      "code": "resource-not-found",
      "property": "stock_location_id",
      "message": "stock_location_id not found"
    }
  ]
}
```
