---
title: "Quote a cart"
description: "Prices a cart exactly as the order will, and tells you whether it can\ncheck out. Always 200 for a well-formed request: problems such as an\ninvalid coupon or a missed minimum are reported inside the response\n(`coupon.valid`, `minimum`, `canCheckout`).\n\nThe quote is a preview: Unipage recomputes every amount when the order\nis placed. Promotional offers and tips are not previewed.\n"
---

> Documentation Index
> Fetch the complete documentation index at: https://developer.unipage.be/llms.txt
> Use this file to discover all available pages before exploring further.

Path: Storefront API › Cart

`POST /cart/quote`

Prices a cart exactly as the order will, and tells you whether it can
check out. Always 200 for a well-formed request: problems such as an
invalid coupon or a missed minimum are reported inside the response
(`coupon.valid`, `minimum`, `canCheckout`).

The quote is a preview: Unipage recomputes every amount when the order
is placed. Promotional offers and tips are not previewed.

## Authentication

Requires one of the following:

- `publicKey`, apiKey, in header, header `X-Unipage-Key`
- `secretKey`, http, header `Authorization`

## Request body

_Required._

- `orderType` (`quoteCart.orderType`; string, required)
  - one of `"TAKEOUT"`, `"DELIVERY"`
- `lines` (`quoteCart.lines`; array<object>, required)
  - `productId` (`quoteCart.lines.productId`; string, required)
  - `quantity` (`quoteCart.lines.quantity`; integer, required)
    - min 1
  - `notes` (`quoteCart.lines.notes`; string, optional)
    - maxLength 255
  - `options` (`quoteCart.lines.options`; array<object>, optional)
    - `groupId` (`quoteCart.lines.options.groupId`; string, required)
    - `optionId` (`quoteCart.lines.options.optionId`; string, required)
    - `quantity` (`quoteCart.lines.options.quantity`; integer, optional) — Only matters for `AMOUNT` groups.
      - default `1`
- `delivery` (`quoteCart.delivery`; object, optional) — The delivery zone, for `DELIVERY`.
  - `zoneId` (`quoteCart.delivery.zoneId`; string, optional)
- `coupon` (`quoteCart.coupon`; string, optional)
- `slotAt` (`quoteCart.slotAt`; integer, optional) — Send it once the shopper picked a slot, so the prices and availability are the ones of that moment. `POST /orders` always uses its own `slotAt`.

## Example request

```json
{
  "orderType": "TAKEOUT",
  "lines": [
    {
      "productId": "p7d2x",
      "quantity": 1,
      "notes": "no salt",
      "options": [
        {
          "groupId": "g5t1r",
          "optionId": "o9w3e",
          "quantity": 1
        }
      ]
    }
  ],
  "delivery": {
    "zoneId": "z81qm"
  },
  "coupon": "WELCOME10",
  "slotAt": 1792750500
}
```

## Code samples

### cURL

```bash
curl --request POST \
  --url https://api.unipage.eu/storefront/v1/cart/quote \
  --header 'Content-Type: application/json' \
  --header 'X-Unipage-Key: <X-Unipage-Key>' \
  --data '
{
  "orderType": "TAKEOUT",
  "lines": [
    {
      "productId": "p7d2x",
      "quantity": 1,
      "notes": "no salt",
      "options": [
        {
          "groupId": "g5t1r",
          "optionId": "o9w3e",
          "quantity": 1
        }
      ]
    }
  ],
  "delivery": {
    "zoneId": "z81qm"
  },
  "coupon": "WELCOME10",
  "slotAt": 1792750500
}
'
```

### TypeScript

```typescript
const url = 'https://api.unipage.eu/storefront/v1/cart/quote';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', 'X-Unipage-Key': '<X-Unipage-Key>'},
  body: JSON.stringify({
    orderType: 'TAKEOUT',
    lines: [
      {
        productId: 'p7d2x',
        quantity: 1,
        notes: 'no salt',
        options: [{groupId: 'g5t1r', optionId: 'o9w3e', quantity: 1}]
      }
    ],
    delivery: {zoneId: 'z81qm'},
    coupon: 'WELCOME10',
    slotAt: 1792750500
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));
```

### Python

```python
import requests

url = "https://api.unipage.eu/storefront/v1/cart/quote"

payload = {
    "orderType": "TAKEOUT",
    "lines": [
        {
            "productId": "p7d2x",
            "quantity": 1,
            "notes": "no salt",
            "options": [
                {
                    "groupId": "g5t1r",
                    "optionId": "o9w3e",
                    "quantity": 1
                }
            ]
        }
    ],
    "delivery": { "zoneId": "z81qm" },
    "coupon": "WELCOME10",
    "slotAt": 1792750500
}
headers = {
    "Content-Type": "application/json",
    "X-Unipage-Key": "<X-Unipage-Key>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

## Responses

### 200

The quote.

#### Example

```json
{
  "lines": [
    {
      "index": 0,
      "productId": "p7d2x",
      "name": "Loaded fries",
      "quantity": 1,
      "unitPrice": 5,
      "optionsLabel": "Toppings: Feta",
      "total": 5,
      "errors": [
        "string"
      ]
    }
  ],
  "subtotal": 5,
  "charges": [
    {
      "name": "Packaging",
      "amount": 0.5
    }
  ],
  "deliveryCost": 10,
  "serviceCost": 0,
  "couponDiscount": 0,
  "coupon": {
    "code": "WELCOME10",
    "valid": false,
    "message": "Coupon is not valid"
  },
  "total": 15.5,
  "minimum": {
    "amount": 50,
    "missing": 45
  },
  "errors": [
    "Minimum order for delivery is EUR 50.00"
  ],
  "canCheckout": false
}
```

- `lines` (`quoteCart.response.200.lines`; array<object>, optional)
  - `index` (`quoteCart.response.200.lines.index`; integer, optional) — Position of the line in the request.
  - `productId` (`quoteCart.response.200.lines.productId`; string, optional)
  - `name` (`quoteCart.response.200.lines.name`; string, optional)
  - `quantity` (`quoteCart.response.200.lines.quantity`; integer, optional)
  - `unitPrice` (`quoteCart.response.200.lines.unitPrice`; number, optional)
  - `optionsLabel` (`quoteCart.response.200.lines.optionsLabel`; string, optional)
  - `total` (`quoteCart.response.200.lines.total`; number, optional)
  - `errors` (`quoteCart.response.200.lines.errors`; array<string>, optional)
- `subtotal` (`quoteCart.response.200.subtotal`; number, optional)
- `charges` (`quoteCart.response.200.charges`; array<object>, optional) — Fixed charges the restaurant adds to every order of this type (a packaging or bag fee, for example). They are part of `total`; show them as separate lines.
  - `name` (`quoteCart.response.200.charges.name`; string, optional)
  - `amount` (`quoteCart.response.200.charges.amount`; number, optional)
- `deliveryCost` (`quoteCart.response.200.deliveryCost`; number, optional)
- `serviceCost` (`quoteCart.response.200.serviceCost`; number, optional)
- `couponDiscount` (`quoteCart.response.200.couponDiscount`; number, optional)
- `coupon` (`quoteCart.response.200.coupon`; object | null, optional) — `null` when none was sent.
  - `code` (`quoteCart.response.200.coupon.code`; string, optional)
  - `valid` (`quoteCart.response.200.coupon.valid`; boolean, optional)
  - `message` (`quoteCart.response.200.coupon.message`; string, optional)
- `total` (`quoteCart.response.200.total`; number, optional) — `subtotal` + `charges` + `deliveryCost` + `serviceCost` - `couponDiscount`.
- `minimum` (`quoteCart.response.200.minimum`; object | null, optional) — `null` when no minimum applies.
  - `amount` (`quoteCart.response.200.minimum.amount`; number, optional)
  - `missing` (`quoteCart.response.200.minimum.missing`; number, optional)
- `errors` (`quoteCart.response.200.errors`; array<string>, optional) — Every reason `canCheckout` is false that is not a line error.
- `canCheckout` (`quoteCart.response.200.canCheckout`; boolean, optional)

### 401

A missing, unknown or revoked key (`UNAUTHENTICATED`).

#### Example

```json
{
  "error": {
    "code": "UNAUTHENTICATED",
    "message": "No valid key."
  }
}
```

- `error` (`quoteCart.response.401.error`; object, required)
  - `code` (`quoteCart.response.401.error.code`; string, required)
    - one of `"UNAUTHENTICATED"`, `"FORBIDDEN"`, `"NOT_FOUND"`, `"METHOD_NOT_ALLOWED"`, `"VALIDATION"`, `"SLOT_UNAVAILABLE"`, `"DELIVERY_UNAVAILABLE"`, `"PRODUCT_UNAVAILABLE"`, `"COUPON_INVALID"`, `"MINIMUM_NOT_REACHED"`, `"RATE_LIMITED"`, `"INTERNAL"`
  - `message` (`quoteCart.response.401.error.message`; string, required) — Human readable.
  - `fields` (`quoteCart.response.401.error.fields`; map<string>, optional) — Only present when the error belongs to specific request fields.

### 403

A public key on a secret route, or used from an origin that is not
registered for it (`FORBIDDEN`).

#### Example

```json
{
  "error": {
    "code": "FORBIDDEN",
    "message": "Origin not registered for this key."
  }
}
```

- `error` (`quoteCart.response.403.error`; object, required)
  - `code` (`quoteCart.response.403.error.code`; string, required)
    - one of `"UNAUTHENTICATED"`, `"FORBIDDEN"`, `"NOT_FOUND"`, `"METHOD_NOT_ALLOWED"`, `"VALIDATION"`, `"SLOT_UNAVAILABLE"`, `"DELIVERY_UNAVAILABLE"`, `"PRODUCT_UNAVAILABLE"`, `"COUPON_INVALID"`, `"MINIMUM_NOT_REACHED"`, `"RATE_LIMITED"`, `"INTERNAL"`
  - `message` (`quoteCart.response.403.error.message`; string, required) — Human readable.
  - `fields` (`quoteCart.response.403.error.fields`; map<string>, optional) — Only present when the error belongs to specific request fields.

### 422

The request is not valid, see `fields` (`VALIDATION`).

#### Example

```json
{
  "error": {
    "code": "VALIDATION",
    "message": "The request is not valid.",
    "fields": {
      "products": "Unknown product."
    }
  }
}
```

- `error` (`quoteCart.response.422.error`; object, required)
  - `code` (`quoteCart.response.422.error.code`; string, required)
    - one of `"UNAUTHENTICATED"`, `"FORBIDDEN"`, `"NOT_FOUND"`, `"METHOD_NOT_ALLOWED"`, `"VALIDATION"`, `"SLOT_UNAVAILABLE"`, `"DELIVERY_UNAVAILABLE"`, `"PRODUCT_UNAVAILABLE"`, `"COUPON_INVALID"`, `"MINIMUM_NOT_REACHED"`, `"RATE_LIMITED"`, `"INTERNAL"`
  - `message` (`quoteCart.response.422.error.message`; string, required) — Human readable.
  - `fields` (`quoteCart.response.422.error.fields`; map<string>, optional) — Only present when the error belongs to specific request fields.

### 429

Too many requests (`RATE_LIMITED`). Wait `Retry-After` seconds.

#### Example

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests."
  }
}
```

- `error` (`quoteCart.response.429.error`; object, required)
  - `code` (`quoteCart.response.429.error.code`; string, required)
    - one of `"UNAUTHENTICATED"`, `"FORBIDDEN"`, `"NOT_FOUND"`, `"METHOD_NOT_ALLOWED"`, `"VALIDATION"`, `"SLOT_UNAVAILABLE"`, `"DELIVERY_UNAVAILABLE"`, `"PRODUCT_UNAVAILABLE"`, `"COUPON_INVALID"`, `"MINIMUM_NOT_REACHED"`, `"RATE_LIMITED"`, `"INTERNAL"`
  - `message` (`quoteCart.response.429.error.message`; string, required) — Human readable.
  - `fields` (`quoteCart.response.429.error.fields`; map<string>, optional) — Only present when the error belongs to specific request fields.


Source: https://developer.unipage.be/storefront/api/cart/quote/index.md
