本文へスキップ

Post messages and send proposals

Read time: 6 minutes. Who it's for: Developers connecting a CRM, ERP or support tool that needs to talk to buyers through QuotWay, or to release a proposal once an outside process signs it off.

⚠️ Both endpoints need the Enterprise plan and a key with the write_quotes scope. Send an Idempotency-Key on every call.

Post a message - POST /v1/quotes/{id}/messages

Adds a message from the store to the quote's conversation.

curl https://api.quotway.com/v1/quotes/clz8k2x9f0001qw7h3m4n5p6r/messages \
  -H "Authorization: Bearer $QUOTWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3a9c2d1e-7f6b-4a5c-9d8e-1f2a3b4c5d6e" \
  -d '{"body": "Good news — we can do the 12 oz lids in the same shipment."}'
Field Required Description
body Yes The message text, 1–5,000 characters (leading and trailing whitespace is trimmed).
internal No true makes it an internal note: visible to your team in QuotWay only. Default false.

Response - 201 Created:

{
  "object": "message",
  "id": "clz9c4d5e0007qw7hb8c9d0e1",
  "quote_id": "clz8k2x9f0001qw7h3m4n5p6r",
  "internal": false,
  "body": "Good news — we can do the 12 oz lids in the same shipment.",
  "created_at": "2026-09-29T15:04:11.820Z"
}

What happens next:

  • A buyer-facing message appears in the quote's conversation, is sent under your store's name, and is emailed to the buyer. It fires the quote.message_created webhook. (If the email can't be queued, the message is still recorded.)
  • An internal note ("internal": true) is never emailed and never published to webhooks, the events feed or any integration.
  • Buyer-facing messages count toward the store's daily buyer-email allowance; internal notes don't. Over the allowance you get 429 email_quota_exceeded.

The API can post messages; it can't read the conversation back.

Send the staged proposal - POST /v1/quotes/{id}/send-proposal

Sends the proposal your team already priced and saved in QuotWay's proposal editor. It's the same action as pressing Send proposal in the admin, with the same checks. The API never sets prices - if nobody has saved a proposal draft, there's nothing to send.

Typical uses: an ERP or CPQ approves margins before release; a CRM step marks the deal ready; a batch job releases proposals at the start of the business day.

curl -X POST https://api.quotway.com/v1/quotes/clz8k2x9f0001qw7h3m4n5p6r/send-proposal \
  -H "Authorization: Bearer $QUOTWAY_API_KEY" \
  -H "Idempotency-Key: 5e4d3c2b-1a09-4f8e-b7d6-c5b4a3928170"

The body is optional. Its only field:

Field Description
confirm_below_floor true sends even if some lines are below the store's price floor - the same explicit confirmation the admin asks for.

What gets checked

In order, exactly as in the admin:

  1. A saved draft exists - otherwise 409 no_staged_proposal.
  2. The quote can take a proposal - its status must be submitted, in_review or countered; otherwise 409 not_editable.
  3. B2B catalog prices - for a b2b quote, the company location's catalog prices are re-read from Shopify as the baseline.
  4. Price floor - any line below the floor stops the send with 409 below_price_floor (listing the lines), unless you pass confirm_below_floor: true. Each line is judged at the price the buyer pays, with its share of any whole-quote discount taken off. A fixed-amount discount larger than the subtotal is refused first, with 422 invalid_proposal - confirm_below_floor doesn't override it.
  5. The proposal is valid - e.g. every line has a price; otherwise 422 invalid_proposal.
  6. Approval policies - if a policy requires sign-off (say, discounts over 10%), the proposal is parked for your team's approval instead of going to the buyer.
  7. Sent - the buyer is emailed, with the Proposal PDF when the store generates one automatically.

Response - 200 OK

{
  "object": "proposal_send",
  "outcome": "sent",
  "version_number": 2,
  "quote": { "object": "quote", "id": "clz8k2x9f0001qw7h3m4n5p6r", "status": "proposal_sent", "…": "…" }
}
outcome Meaning
sent The proposal went to the buyer. The quote is proposal_sent; quote.proposal_sent fires.
awaiting_approval An approval policy parked it. The quote is awaiting_merchant_approval; quote.merchant_approval.requested fires, and the buyer is notified once it's approved.

quote is the full quote object after the send.

Errors

Status Code What to do
409 no_staged_proposal Price and save the proposal in QuotWay first.
409 not_editable Check the quote's status.
409 below_price_floor Review prices, or resend with confirm_below_floor: true.
422 invalid_proposal Fix the draft in QuotWay.
409 state_conflict The quote changed mid-send. Re-fetch, then retry with a new idempotency key.
409 send_incomplete A version was created but the send didn't finish. Check the quote before doing anything else.
404 not_found No such quote in this store.
429 email_quota_exceeded The store's daily allowance of buyer-emailing API calls is used up.

Every refusal is a 4xx, and 4xx responses are stored against your Idempotency-Key, so a retry with the same key replays the refusal rather than creating a second proposal version.

What the API can't do (yet)

There are no endpoints to price or edit lines, change a proposal, accept or decline on the buyer's behalf, or convert a quote to a draft order. Those stay in QuotWay, where your team, your price floor and your approval policies govern them.

解決しませんか?サポートチームがお手伝いします。

サイトの利用状況を把握するため、分析用Cookieを設定したいと考えています。必須ではありません。拒否してもサイトの動作は変わらず、選択はいつでも変更できます。変更はこちらから: プライバシーページ.