---
title: "The quote object"
description: "Every field on a quote returned by the QuotWay API - status, lines, totals, headline, still_open vs accepted, and buyer data behind read_customer_data."
url: "https://www.quotway.com/fr/docs/api/quote-object"
type: "documentation"
category: "api"
updated: "2026-09-30"
locale: "fr"
source: "QuotWay - B2B Quote & Negotiation App for Shopify"
---

# The quote object

**Read time:** 10 minutes.
**Who it's for:** Developers mapping QuotWay quotes into another system.

`GET /v1/quotes`, `GET /v1/quotes/{id}`, `POST /v1/quotes` and `POST /v1/quotes/{id}/send-proposal`
all return quotes in this shape. It's the **merchant's view** of the quote: it includes lines the
buyer can't see (flagged as such) and never includes internal notes.

## Conventions

- Keys are `snake_case`; enum values are lowercase (`proposal_sent`, `b2b`).
- **Money is a decimal string with exactly two places** (`"1250.00"`), always next to an ISO 4217
  currency code. Parse it with a decimal type, not a float.
- Timestamps are ISO-8601 in UTC (`"2026-09-29T14:12:00.000Z"`).
- Shopify references are Shopify GIDs (`gid://shopify/Customer/7012345678`).
- New fields may be added to this object at any time; your code should ignore fields it doesn't
  know. See [Versioning](/docs/api/versioning).

## Example

A wholesale quote where the buyer accepted one line, declined one and left one open:

```json
{
  "object": "quote",
  "id": "clz8k2x9f0001qw7h3m4n5p6r",
  "number": "QW-1042",
  "status": "partially_accepted",
  "mode": "wholesale",
  "source": "product_page",
  "currency": "USD",
  "version_number": 2,
  "negotiation_round": 1,
  "po_number": "PO-88213",
  "requested_delivery_date": "2026-11-01T00:00:00.000Z",
  "expires_at": "2026-10-14T00:00:00.000Z",
  "created_at": "2026-09-22T09:31:05.412Z",
  "updated_at": "2026-09-29T14:12:00.000Z",
  "first_accepted_at": "2026-09-29T14:12:00.000Z",
  "fully_converted_at": null,
  "invoice_sent_at": null,
  "totals": {
    "currency": "USD",
    "subtotal": "2300.00",
    "discount_total": "115.00",
    "shipping_total": "40.00",
    "tax_estimate": "0.00",
    "total": "2225.00",
    "accepted_total": "1187.50",
    "still_open_total": "450.00",
    "headline": "1187.50",
    "headline_mode": "open",
    "base_currency": {
      "currency": "USD",
      "total": null,
      "accepted_total": null,
      "exchange_rate": null
    }
  },
  "lines": [
    {
      "id": "clz8m0v1a0010qw7hk2l3m4n5",
      "quote_line_item_id": "clz8k2xa00002qw7h9a8b7c6d",
      "position": 0,
      "product_id": "gid://shopify/Product/8123456789",
      "variant_id": "gid://shopify/ProductVariant/4455667788",
      "sku": "NW-CUP-12OZ",
      "title": "Compostable cup, 12 oz",
      "variant_title": "Case of 50",
      "quantity": 100,
      "catalog_price": "14.00",
      "requested_price": "11.50",
      "unit_price": "12.50",
      "line_total": "1250.00",
      "is_custom": false,
      "requires_shipping": true,
      "taxable": true,
      "buyer_visibility": "show",
      "kit": null,
      "decision": "accept",
      "accepted": true,
      "still_open": false
    },
    {
      "id": "clz8m0v1a0011qw7hp6q7r8s9",
      "quote_line_item_id": "clz8k2xa00003qw7hd5e4f3g2",
      "position": 1,
      "product_id": "gid://shopify/Product/8123456790",
      "variant_id": "gid://shopify/ProductVariant/4455667790",
      "sku": "NW-LID-12OZ",
      "title": "Lid, 12 oz",
      "variant_title": null,
      "quantity": 20,
      "catalog_price": "32.00",
      "requested_price": null,
      "unit_price": "30.00",
      "line_total": "600.00",
      "is_custom": false,
      "requires_shipping": true,
      "taxable": true,
      "buyer_visibility": "show",
      "kit": null,
      "decision": "reject",
      "accepted": false,
      "still_open": false
    },
    {
      "id": "clz8m0v1a0012qw7ht1u2v3w4",
      "quote_line_item_id": "clz8k2xa00004qw7hh1i2j3k4",
      "position": 2,
      "product_id": null,
      "variant_id": null,
      "sku": null,
      "title": "Custom logo print setup",
      "variant_title": null,
      "quantity": 10,
      "catalog_price": null,
      "requested_price": null,
      "unit_price": "45.00",
      "line_total": "450.00",
      "is_custom": true,
      "requires_shipping": false,
      "taxable": true,
      "buyer_visibility": "show",
      "kit": null,
      "decision": "defer",
      "accepted": false,
      "still_open": true
    }
  ],
  "proposal": {
    "version_number": 2,
    "sent_by": "merchant",
    "created_at": "2026-09-24T16:02:44.108Z",
    "shipping_status": "final",
    "shipping_label": "UPS Ground",
    "payment_terms": "Net 30",
    "deposit_percentage": null,
    "expires_at": "2026-10-14T00:00:00.000Z"
  },
  "approval": { "active": false, "pending_domain": null },
  "shopify": {
    "customer_id": "gid://shopify/Customer/7012345678",
    "company_id": null,
    "company_location_id": null,
    "company_contact_id": null,
    "draft_order_ids": [],
    "order_ids": []
  },
  "assigned_staff": { "id": "clx3q9r8s0000ab12cd34ef56", "email": "sam@northwind-supply.com" },
  "kit_conversion_mode": "collapse",
  "based_on_quote_id": null,
  "links": {
    "admin_url": "https://admin.shopify.com/store/northwind-supply/apps/<app-client-id>/app/quotes/clz8k2x9f0001qw7h3m4n5p6r"
  }
}
```

With the `read_customer_data` scope, the quote also carries a `customer` object and each line a
`buyer_note` - see [Buyer personal data](#buyer-personal-data).

## Top-level fields

| Field | Type | Description |
|---|---|---|
| `object` | `"quote"` | Always `quote`. |
| `id` | string | The quote's id. Use it in API paths. |
| `number` | string | The human reference buyers and staff see, e.g. `QW-1042` (the prefix is the store's setting). Not usable in API paths. |
| `status` | string | Where the quote is in its life cycle - see [Status](#status). |
| `mode` | string | `wholesale` (a standard quote) or `b2b` (a company-aware quote tied to a Shopify B2B company location). |
| `source` | string | Where the request came from: `product_page`, `cart`, `buyer_portal`, `admin` (created by staff), `guest`, `customer_account` (buyer quick order in the Shopify customer account) or `api`. |
| `currency` | string | ISO currency of the quote's money. |
| `version_number` | integer | The current proposal version (`0` before any proposal exists). |
| `negotiation_round` | integer | How many negotiation rounds the quote has been through. |
| `po_number` | string \| null | The buyer's purchase-order number. |
| `requested_delivery_date` | timestamp \| null | The delivery date the buyer asked for. |
| `expires_at` | timestamp \| null | When the current offer expires. |
| `created_at` / `updated_at` | timestamp | Created / last changed. `updated_at` is the field to sync on. |
| `first_accepted_at` | timestamp \| null | When the buyer first accepted any part of the quote. |
| `fully_converted_at` | timestamp \| null | When every accepted line had become a Shopify draft order. |
| `invoice_sent_at` | timestamp \| null | When the draft-order invoice was sent. |
| `totals` | object | See [Totals](#totals). |
| `lines` | array | See [Lines](#lines). |
| `proposal` | object \| null | The current proposal version; `null` before the first proposal. See [Proposal](#proposal). |
| `approval` | object | `active` - an approval chain is in progress; `pending_domain` - `merchant` (your team's approval) or `buyer` (the buyer's internal approval), or `null`. |
| `shopify` | object | Shopify ids: `customer_id`, `company_id`, `company_location_id`, `company_contact_id` (each may be `null`), plus `draft_order_ids` and `order_ids` (arrays of GIDs). These are identifiers, not personal data. |
| `assigned_staff` | object \| null | The staff member the quote is assigned to (`id`, `email`). |
| `kit_conversion_mode` | string | How kits become draft-order lines: `collapse` (one line at the kit price) or `expand` (the components). |
| `based_on_quote_id` | string \| null | Set when staff created the quote with **Duplicate quote**; the id of the original. (A buyer's reorder is a fresh request and doesn't set it.) |
| `links.admin_url` | string | Opens the quote in the QuotWay admin inside Shopify. Staff need to be logged in to Shopify. |
| `customer` | object | **Only with `read_customer_data`.** See [Buyer personal data](#buyer-personal-data). |

### Status

`status` is one of:

| Value | Meaning |
|---|---|
| `submitted` | A new request, not yet opened. Quotes created with `POST /v1/quotes` start here. |
| `in_review` | Your team has opened the quote and is working on it. |
| `awaiting_info` | Waiting for information from the buyer. |
| `awaiting_merchant_approval` | A proposal is waiting for your team's internal approval before it goes out. |
| `proposal_sent` | A proposal is with the buyer. |
| `awaiting_buyer_approval` | The buyer's own internal approval chain is reviewing the proposal. |
| `countered` | The buyer made a counter-offer. |
| `partially_accepted` | The buyer accepted some lines. |
| `fully_accepted` | The buyer accepted the whole proposal. |
| `partially_converted` | Some accepted lines have become a Shopify draft order. |
| `fully_converted` | Every accepted line has become a Shopify draft order. |
| `invoice_sent` | The draft-order invoice has been sent to the buyer. |
| `order_completed` | The buyer paid and the order was placed. |
| `order_cancelled` | The resulting order was cancelled. |
| `order_refunded` | The resulting order was refunded. |
| `declined` | The quote was declined. |
| `expired` | The offer passed its expiry date. |
| `closed` | The quote was closed. |

New statuses may be added in future; treat an unknown value as "in progress" rather than failing.

## Totals

`totals` answers two different questions - *what was offered* and *what was agreed* - and gives
you one field, `headline`, that is always the right figure to act on.

| Field | Description |
|---|---|
| `currency` | ISO currency of every amount in `totals` (except `base_currency`). |
| `subtotal` | Sum of the current proposal's lines, before discount. |
| `discount_total` | The quote-level discount. |
| `shipping_total` | Shipping on the proposal. |
| `tax_estimate` | Estimated tax. Shopify computes the final tax on the draft order. |
| `total` | **What was offered** on the current version: subtotal − discount + shipping + tax estimate. Never rewritten by acceptance. |
| `accepted_total` | **What the buyer committed to on a mixed acceptance** - the accepted lines, **net** of their share of the quote discount, **excluding** shipping and tax. `null` when nothing has been accepted, and also `null` on a full acceptance (use `total`). |
| `still_open_total` | The value of the lines the buyer left undecided (the sum of their line totals, before any discount share). `null` unless some lines are still open. |
| `headline` | **The figure to act on.** See `headline_mode`. Always present. |
| `headline_mode` | Why `headline` is what it is - see below. |
| `base_currency` | The store's base currency view: `currency`, `total`, `accepted_total` and the `exchange_rate` captured when the quote was requested. The amounts are `null` when no exchange-rate snapshot was captured - fall back to `totals.total` when the quote's `currency` equals the base currency. |

### `headline_mode`

| Value | Situation | `headline` equals |
|---|---|---|
| `none` | Nothing accepted yet. | `total` |
| `full` | Accepted in full. | `total` |
| `decided` | Every line was either accepted or declined - nothing is pending. | `accepted_total` |
| `open` | Some lines accepted, some still undecided. | `accepted_total` (what's agreed so far); `still_open_total` is what's still in play |

**If you only store one number, store `headline`.** Reconstructing it yourself from `total` and
the lines is how quote values end up wrong in a CRM: on a partial acceptance `total` still shows the
whole original offer.

## Lines

Before the first proposal, `lines` are the buyer's requested lines. Once a proposal exists, they are
the **current proposal version's** lines, and `quote_line_item_id` links each one back to the
request line it came from.

| Field | Description |
|---|---|
| `id` | The line's id (a proposal-version line once a proposal exists). |
| `quote_line_item_id` | The request line this proposal line came from; `null` before a proposal. |
| `position` | Sort order, starting at 0. |
| `product_id` / `variant_id` | Shopify GIDs; `null` for custom lines. |
| `sku`, `title`, `variant_title` | As captured from Shopify. A kit's parent line shows the kit's name. |
| `quantity` | Integer. |
| `catalog_price` | The Shopify price when the line was captured. |
| `requested_price` | The unit price the buyer asked for, if any. |
| `unit_price` | The price you offered; `null` until priced. |
| `line_total` | `unit_price × quantity`; `null` until priced. |
| `is_custom` | `true` for a custom line (not a Shopify product). |
| `requires_shipping`, `taxable` | How the line converts to the draft order. |
| `buyer_visibility` | What the **buyer** sees: `show`, `price_hidden` (shown as "Included", no price) or `hidden` (not shown to the buyer at all). |
| `kit` | For kit lines: `key` (groups a kit's lines), `role` (`parent` or `component`) and `title`. `null` otherwise. |
| `decision` | The buyer's per-line decision on a mixed acceptance: `accept`, `reject` (declined) or `defer` (decide later). `null` when there's nothing to mark - not yet accepted, or accepted in full. |
| `accepted` | `true` when the line is part of an accepted set. |
| `still_open` | `true` when the line is **undecided and still negotiable**. |
| `buyer_note` | The buyer's note on this line. **Only with `read_customer_data`.** |

### `still_open` is not `!accepted`

A declined line is neither accepted nor still open. Use the pair like this:

| `accepted` | `still_open` | The line is… |
|---|---|---|
| `false` | `true` | not yet decided - before acceptance, or deferred by the buyer |
| `true` | `false` | accepted |
| `false` | `false` | declined |

### Kits

A kit is sold as one line at one price. Its **parent** line carries the price; its **component**
lines are `0.00` and exist so stock and fulfilment see what's in the box. All of a kit's lines share
the same `kit.key`. To total a quote yourself, sum parents and ordinary lines - the components add
nothing. Component lines are often `buyer_visibility: "hidden"`; they're included here because this
is the merchant's view.

## Proposal

`proposal` describes the current version, or is `null` before the first one.

| Field | Description |
|---|---|
| `version_number` | The version this describes. |
| `sent_by` | Who created it: `merchant`, `buyer` (a counter-offer) or `system` (automation). |
| `created_at` | When the version was created. |
| `shipping_status` | `pending` (shipping still to be confirmed) or `final`. |
| `shipping_label` | The shipping method label, if set. |
| `payment_terms` | Payment-terms name, e.g. `Net 30`, if set. |
| `deposit_percentage` | The deposit asked for, e.g. `"50.00"`, or `null`. |
| `expires_at` | When this version's offer expires. |

## Buyer personal data

With the `read_customer_data` scope, quotes include:

```json
"customer": {
  "email": "buyer@example.com",
  "name": "Dana Ortiz",
  "phone": "+1 303 555 0142",
  "company_name": "Acme Restaurant Group",
  "shipping_address": {
    "firstName": "Dana",
    "lastName": "Ortiz",
    "name": null,
    "company": "Acme Restaurant Group",
    "address1": "1200 Larimer St",
    "address2": null,
    "city": "Denver",
    "province": null,
    "provinceCode": "CO",
    "countryCode": "US",
    "zip": "80204",
    "phone": null
  },
  "billing_address": null,
  "custom_fields": { "industry": "Hospitality", "weekly_volume": "500+" },
  "notes": "Delivery to our Denver kitchen, please."
}
```

- `shipping_address` / `billing_address` are the stored address objects - note their keys are
  **camelCase** (`address1`, `provinceCode`, `countryCode`), unlike the rest of the API - or
  `null`.
- `custom_fields` holds the answers to the store's custom quote-form fields, keyed by field key.
- `notes` is the buyer's note on the request.

Without the scope, `customer` and every `buyer_note` are **absent** (not `null`). Nothing else
changes, so the same code can handle both.

Internal notes your team writes are **never** returned by the API.

## Related

- [Pagination](/docs/api/pagination) - listing and syncing quotes.
- [Webhooks](/docs/api/webhooks) - the smaller, PII-free quote snapshot sent with each event.
- [Partial acceptance](/docs/negotiation/partial-acceptance) - how buyers accept line by line.
