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, andwritten_off; the transition must be legal from the current status per the table above. - Automatically on payment: recording a payment sets the status
to
partialorpaidbased 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
quantityandunitPriceas exact decimal STRINGS, the same grammar as the quote wire.unitPriceis 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.quantityis 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.vatRateis an integer percent (0 to 100). - Payments are the exception: the payment
amountis an integer in PENCE. £50.00 is sent as5000. - Responses carry all computed amounts (
subtotal,vatAmount,total,amountPaid, and per-linevatAmountandlineTotal) as integers in pence, and each line'sunitPriceis also returned in pence (a £750.00 unit price reads back as75000).
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.
Endpoints
https://app.speybooks.com/api/v1/invoices/List invoicesPOSThttps://app.speybooks.com/api/v1/invoices/Create an invoicePOSThttps://app.speybooks.com/api/v1/invoices/previewPreview invoice calculationsGEThttps://app.speybooks.com/api/v1/invoices/{id}Retrieve an invoicePUThttps://app.speybooks.com/api/v1/invoices/{id}Update a draft invoiceDELETEhttps://app.speybooks.com/api/v1/invoices/{id}Delete a draft invoicePOSThttps://app.speybooks.com/api/v1/invoices/{id}/emailSend invoice via emailPOSThttps://app.speybooks.com/api/v1/invoices/{id}/paymentRecord a paymentPOSThttps://app.speybooks.com/api/v1/invoices/{id}/payment/reverseReverse a paymentGEThttps://app.speybooks.com/api/v1/invoices/{id}/pdfDownload invoice as PDFPATCHhttps://app.speybooks.com/api/v1/invoices/{id}/statusUpdate invoice status