Invoices

Invoices represent amounts owed to or by your organisation. Sales invoices are issued to contacts (customers); purchase invoices are bills received from suppliers.

Lifecycle

The stored status vocabulary is draft, sent, partial, paid, cancelled, written_off, and credited. overdue is derived, never stored: an invoice is overdue when its due date has passed and its status is sent or partial (the list endpoint's overdue filter applies exactly this predicate). credited is reserved for the forthcoming credit-note mechanism and is not currently set by any operation.

The full transition table is enforced at both the service and the database:

From To
draft sent, cancelled
sent partial, paid, written_off, credited
partial paid, written_off, credited

paid, cancelled, written_off, and credited are terminal. Cancellation applies to DRAFTS ONLY: an issued invoice is a tax document and cannot be cancelled. Close an unpaid issued invoice with written_off, or correct it with a credit note once that mechanism ships. Illegal transitions are rejected. Setting an invoice to its current status produces no lifecycle change; it is not a way to re-issue or re-stamp.

Status changes happen three ways:

  • Explicitly, via the status endpoint. The public targets are sent, cancelled, and written_off; the transition must be legal from the current status per the table above.
  • Automatically on payment: recording a payment sets the status to partial or paid based on the cumulative amount paid. These two statuses are payment-derived and cannot be set via the status endpoint.
  • Automatically on email: emailing a draft invoice transitions it to sent.

Issuing an invoice (transitioning to sent, or creating directly in sent status) records the event in the tamper-evident audit trail AND posts the double-entry issue journal, atomically: for a sales invoice, Trade Debtors is debited the gross total, each line's revenue account is credited its net amount, and VAT on Sales is credited the VAT total (purchase invoices mirror, through Trade Creditors and VAT on Purchases). The journal is dated at the invoice's issue date (the tax point), balances to zero, is immutable once posted, and is linked to the invoice in both directions. An invoice issued in SpeyBooks changes the books.

Because the journal credits each line's revenue or expense account, every line must carry an accountId before the invoice can be issued; issuing with unmapped lines is rejected.

Writing off an invoice posts the bad-debt journal at the transition: Bad Debts is debited and Trade Debtors credited at the OUTSTANDING amount (total minus payments received). VAT bad-debt relief is a VAT-return-level claim under HMRC Notice 700/18. It is not posted at write-off time, because the relief's six-month condition usually has not matured when the business writes off; this journal is the relief's precondition (the transfer to a bad debt account), not the relief itself.

Recording a payment posts no journal: cash recognition belongs to bank reconciliation, by design.

Amounts

The request and response formats differ, and the difference matters:

  • Request line items carry quantity and unitPrice as exact decimal STRINGS, the same grammar as the quote wire. unitPrice is in POUNDS: £1,500.00 is sent as "1500" or "1500.00", and fractional prices are accepted to six decimal places (£100.50 is "100.50"). Do not send pence; "150000" creates an invoice one hundred times larger than intended. quantity is a positive decimal string and may be fractional ("2.5" hours). JSON numbers are rejected: the wire takes strings so that money is never carried by a floating- point type. vatRate is an integer percent (0 to 100).
  • Payments are the exception: the payment amount is an integer in PENCE. £50.00 is sent as 5000.
  • Responses carry all computed amounts (subtotal, vatAmount, total, amountPaid, and per-line vatAmount and lineTotal) as integers in pence, and each line's unitPrice is also returned in pence (a £750.00 unit price reads back as 75000).

Per-line net is computed as quantity times unitPrice times 100, with VAT calculated per line and rounded half-up. The preview endpoint uses the identical calculation path to create.

Numbering

Invoice numbers follow the pattern INV-{sequence} (e.g. INV-0042), assigned automatically on creation and sequential per organisation.

Empty fields

Optional text fields (reference, notes, terms, contact address parts) and an unissued invoice's sentAt are null when unset. An empty string means the field was set to empty; null means it was never set, and the two are distinguishable. createdBy is an integer user id, or null when the invoice was created with an API key.

Metadata

Invoices support custom metadata as string key-value pairs: up to 50 keys, keys up to 40 characters (starting with a letter; letters, digits, underscore, and hyphen), values up to 500 characters. Keys prefixed _sb_ are reserved.

→ The Invoices object

Endpoints