Update a quote
Update a quote — only the fields you send change. Setting status to accepted or won creates a pending invoice for the quote total (if it doesn't have one yet) and fires your quote status workflows. A changed total clears the payment link.
PATCH
https://api.centerfy.ai/webhooks/inbound/quotes/:id Headers
| Header | Required | Value | Description |
|---|---|---|---|
x-api-key | Yes | your sub-account API key (cfy_…) | Authenticates the request; or use Authorization: Bearer <key>. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | Yes | The quote or estimate id. |
Body parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
contact_id | string (uuid) | No | — | Move the quote to another contact in this sub-account. |
title | string | No | — | Quote title; cannot be empty. |
description | string | null | No | — | Description; null or empty clears it. |
items | { item, quantity, amount }[] | No | — | Replaces all line items. Line items (1–200). item: non-empty string; quantity: integer ≥ 1; amount: unit price, number ≥ 0.01. The total is the sum of amount × quantity, rounded to cents. |
valid_until | string (YYYY-MM-DD) | No | — | New expiry date. |
notes | string | null | No | — | Notes; null or empty clears them. |
status | string | No | — | One of open, sent, accepted, won, rejected, archived. accepted, rejected and sent also stamp accepted_at, rejected_at or sent_at. |
Request body
{
"status": "accepted"
}Example
curl -X PATCH "https://api.centerfy.ai/webhooks/inbound/quotes/{id}" \
-H "x-api-key: $CENTERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "accepted"
}' import { CenterfyClient } from "@centerfy/sdk";
const centerfy = new CenterfyClient({ apiKey: process.env.CENTERFY_API_KEY! });
const result = await centerfy.quotes.update("<quoteId>", {
"status": "accepted"
});
console.log(result); centerfy quotes update <quoteId> '{"status":"accepted"}' MCP tool: centerfy_quotes_update (see MCP server)
Response
{
"status": "success",
"quote": {
"id": "f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c",
"quote_number": "QUO-2026-007",
"type": "quote",
"contact_id": "3f1c2a9e-7b4d-4c8a-9e2f-1a2b3c4d5e6f",
"title": "Website project",
"description": "Redesign and three months of hosting",
"status": "accepted",
"total_amount": 1575,
"valid_until": "2026-11-05",
"items": [
{
"item": "Website redesign",
"quantity": 1,
"amount": 1500
},
{
"item": "Monthly hosting",
"quantity": 3,
"amount": 25
}
],
"notes": null,
"payment_link": null,
"invoice_id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
"invoiced_at": "2026-10-07T09:00:00.000Z",
"sent_at": null,
"accepted_at": "2026-10-07T09:00:00.000Z",
"rejected_at": null,
"created_at": "2026-10-06T10:00:00.000Z",
"updated_at": "2026-10-06T10:00:00.000Z"
},
"invoice": {
"id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
"invoice_number": "INV-2026-0012",
"contact_id": "3f1c2a9e-7b4d-4c8a-9e2f-1a2b3c4d5e6f",
"quote_id": "f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c",
"amount": 1575,
"status": "pending",
"issued_at": "2026-10-06T10:00:00.000Z",
"due_date": null,
"paid_at": null,
"payment_method": null,
"notes": null,
"items": [],
"payment_url": null,
"payment_link_expires_at": null,
"created_at": "2026-10-06T10:00:00.000Z",
"updated_at": "2026-10-06T10:00:00.000Z"
}
}Errors
400— if title is empty, contact_id is not a UUID, an item is invalid or valid_until is not a valid date.404— if the quote or contact is not in this sub-account.
Notes
invoice is the generated invoice, or null when none was created. If the quote saved but invoice generation failed, you get 200 with invoice: null and a warning. Sending nothing that changes the quote returns it unchanged.