Skip to content

Invoices

Invoices follow a lifecycle: draftposted → optionally void.

Only draft invoices can be modified. Posted invoices are immutable.

GET /api/v1/books/invoices

Scope: read

ParameterTypeDescription
statusstringFilter: draft, posted, void
contact_idintegerFilter by contact
invoice_numberstringFilter by invoice number
fromdateIssue date from (inclusive)
todateIssue date to (inclusive)
qstringSearch invoice number or contact name
limitintegerRecords per page (default 25, max 100)
afterstringPagination cursor

GET /api/v1/books/invoices/:id

Scope: read

Returns the invoice with line items and payment applications:

{
"data": {
"id": 123,
"external_id": "INV-001",
"invoice_number": "INV-00001",
"status": "posted",
"contact_id": 42,
"contact_external_id": "cust-001",
"contact_name": "Acme Corp",
"issue_date": "2026-03-01",
"due_date": "2026-04-01",
"currency": "USD",
"subtotal_cents": 50000,
"discount_cents": 0,
"tax_cents": 0,
"tax_rate_bps": 0,
"total_cents": 50000,
"amount_paid_cents": 0,
"balance_due_cents": 50000,
"notes": null,
"posted_at": "2026-03-01T12:00:00Z",
"voided_at": null,
"created_at": "2026-03-01T12:00:00Z",
"updated_at": "2026-03-01T12:00:00Z",
"invoice_lines": [
{
"id": 456,
"external_id": "LINE-001",
"position": 0,
"description": "Consulting",
"quantity": 1.0,
"unit_price_cents": 50000,
"amount_cents": 50000,
"service_id": null,
"revenue_account_id": null
}
],
"payment_applications": []
}
}
FieldTypeDescription
idintegerUnique identifier
external_idstringYour system’s ID
invoice_numberstringAuto-generated invoice number
statusstringdraft, posted, or void
contact_idintegerAssociated contact ID
contact_external_idstringContact’s external ID
contact_namestringContact name
issue_datedateInvoice issue date
due_datedatePayment due date
currencystring3-letter currency code
subtotal_centsintegerSubtotal before discounts and tax
discount_centsintegerDiscount amount
tax_centsintegerTax amount
tax_rate_bpsintegerTax rate in basis points (875 = 8.75%)
total_centsintegerTotal after discounts and tax
amount_paid_centsintegerAmount paid via applied payments
balance_due_centsintegerRemaining balance
notesstringFree-text notes
posted_attimestampWhen the invoice was posted (null if draft)
voided_attimestampWhen the invoice was voided (null if not voided)

GET /api/v1/books/invoices/by_external_id/:external_id

Scope: read


POST /api/v1/books/invoices

Scope: write | Idempotency: supported

{
"invoice": {
"contact_id": 42,
"issue_date": "2026-03-12",
"due_date": "2026-04-12",
"currency": "USD",
"external_id": "INV-001",
"tax_rate_bps": 0,
"notes": "March consulting",
"invoice_lines_attributes": [
{
"description": "Consulting — March 2026",
"quantity": 1,
"unit_price_cents": 50000,
"position": 0,
"external_id": "LINE-001"
}
]
}
}
FieldTypeRequiredDescription
contact_idintegeryesContact to bill
issue_datedateyesInvoice date
due_datedateyesPayment due date
currencystringnoDefaults to entity currency
external_idstringnoYour system’s ID
discount_centsintegernoDiscount amount
tax_centsintegernoTax amount (overrides tax_rate_bps)
tax_rate_bpsintegernoTax rate in basis points
notesstringnoNotes
invoice_lines_attributesarraynoLine items (see below)
FieldTypeRequiredDescription
descriptionstringyesLine description
quantitynumberyesQuantity (supports decimals)
unit_price_centsintegeryesUnit price in cents
positionintegernoDisplay order
external_idstringnoYour system’s ID
service_idintegernoLink to a service
revenue_account_idintegernoOverride revenue account

Returns: 201 Created

Webhook: books.invoice.created

Totals are automatically calculated from line items.


PATCH /api/v1/books/invoices/:id

Scope: write

Only draft invoices can be updated. Returns 422 with code INVOICE_NOT_DRAFT if the invoice is posted or voided.


POST /api/v1/books/invoices/:id/post_invoice

Scope: write

Transitions the invoice from draft to posted. Creates the corresponding journal entry in the general ledger.

Returns 422 with:

  • INVOICE_NOT_DRAFT if already posted/voided
  • PERIOD_CLOSED if the issue date falls in a closed period

POST /api/v1/books/invoices/:id/void

Scope: write

Voids a posted invoice. The invoice must have no payment applications.

Webhook: books.invoice.voided


POST /api/v1/books/invoices/:invoice_id/lines

Scope: write | Only on draft invoices

PATCH /api/v1/books/invoices/:invoice_id/lines/:id

Scope: write | Only on draft invoices

DELETE /api/v1/books/invoices/:invoice_id/lines/:id

Scope: write | Only on draft invoices | Returns 204 No Content