# Checkout

Cart pricing quotes before payment

## POST /api/v3/checkout/quote

Quote a purchase (read-only pricing)

Compute the priced response for a checkout intent without inserting any rows. Re-uses the same pricing pipeline that `confirmPurchaseIntent` runs, so the result is byte-for-byte aligned with what the client will eventually pay. The returned `expiresAt` window is 5 minutes from now (D-23). If any cart item or KDI is unavailable (out of stock, KDI aborted/removed) the call fails with 400 `items_unavailable` (D-25).

**Permissions:** ⚪ `tabs.pay`

Request body:

```ts
{
  tabId?: string // uuid
  tabMemberId?: string // uuid
  locationId: integer
  mode: "upfront" | "items" | "amount" | "remainder"
  cart?: Record<string, unknown>[]
  kitchenDispatchItemIds?: string[]
  amountCents?: integer
  tipAmountCents?: integer
  persist?: boolean
  voucherCodes?: string[]
  metadata?: Record<string, unknown>
}
```

Response 200 — Priced quote (read-only)

```ts
{
  status?: "success"
  data?: {
    mode: "upfront" | "items" | "amount" | "remainder"
    lineItems: Array<{
        type?: "product" | "tip" | "amount"
        title?: string
        finalAmountCents?: integer
        vatRateBasisPoints?: integer
        vatAmountCents?: integer
        quantity?: number
        quantityCents?: integer
        totalAmountCents?: integer
        totalVatAmountCents?: integer
        originItemId?: integer | null
        kitchenDispatchItemId?: string | null // uuid
        appliedTotalDiscountAmountCents?: integer | null
      }>
    vatBreakdown?: Array<{
        vatRateBasisPoints?: integer
        netAmountCents?: integer
        vatAmountCents?: integer
        grossAmountCents?: integer
      }>
    subtotalCents?: integer
    tipAmountCents?: integer
    discountCents?: integer
    surplusServiceFeeCents?: integer
    totalAmountCents: integer
    quoteId?: string // uuid
    currencyCode: string
    availablePaymentMethods?: string[]
    expiresAt: string // date-time
  }
  meta?: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```
