Quotes

Quotes are proposals sent to contacts before work begins. They are first-class records stored independently of invoices, with their own numbering sequence and an enforced lifecycle. Converting an accepted quote produces a draft sales invoice linked back to the quote in both directions.

Lifecycle

draft    → sent | declined
sent     → accepted | declined | expired
accepted → converted | declined
  • draft: editable and deletable; the only state a quote can be created in (besides sent) and the only state it can be edited or deleted in. No transition returns a quote to draft.
  • sent: delivered to the contact; immutable.
  • accepted: the contact has agreed; eligible for conversion.
  • declined: the contact rejected the quote; terminal.
  • converted: an invoice has been created from this quote; terminal. Reachable only through the convert endpoint, never through the status endpoint.
  • expired: reserved for future expiry automation. No API path currently produces it; see Expiry below.

Transitions are enforced server-side. A request for a transition outside the table above is rejected. Clients do not need to (and cannot) police the lifecycle themselves.

Conversion

Converting an accepted quote runs as a single atomic transaction: the quote is locked, a draft sales invoice is created with a new invoice number from the standard sequence, every line is copied penny for penny (the quote and invoice calculation paths share the same arithmetic, so the copy holds by construction), the quote and invoice are linked to each other in both directions, the quote status advances to converted, and two audit records are written. All of it commits or none of it does.

Amounts

Two formats, by direction:

  • Requests carry quantity and unitPrice as exact decimal strings (for example "2.5" and "100.00"), both strictly positive, with unitPrice in pounds. vatRate is an integer percent (0 to 100). Sending numbers instead of strings, or non-positive values, is rejected.
  • Responses carry computed amounts (subtotal, vatAmount, total, and per-line netAmount, vatAmount, lineTotal) as integers in minor units (pence). quantity and unitPrice are echoed back as exact decimal strings at stored precision.

All calculation happens server-side with exact decimal arithmetic. The preview endpoint uses the identical calculation path to create, so what you preview is what you get on submit.

Numbering

Quotes use the pattern QT-{sequence} (e.g. QT-0001). Numbers are issued atomically from the organisation's document sequence; the sequence is monotonically increasing and independent of year, and duplicate numbers are impossible under concurrent creation (AX-CON-001).

Expiry

Quotes have a validUntil date. A sent quote past its validUntil keeps the status sent; it is not automatically transitioned. Expiry is surfaced two ways: the list endpoint's expiredCount stat counts sent quotes past their date, and status=expired is accepted as a list filter for the same set.

→ The Quotes object

Endpoints