LedgerBee Developer
  • Getting started
  • Conventions
  • Products
  • Advisor firms
  • Configuration
  • API Reference
Subscriptions
Payment flowCard paymentsProducts & PricingDiscountsProduct Entitlements
Billing documents
    OverviewInvoicesCredit notesQuotesOrder confirmationsDocument templates
Accounting
WebhooksPartner-Hosted Checkout
Customer Portal
Billing documents

Invoices

An invoice is a booked accounting document: sending allocates its number and posts it to the books. Reads require the invoices-read scope and writes invoices-write — one scope pair covers invoices and credit notes. The shared line model, list/get/PDF reads, and send channels are in Billing documents; this page covers what is specific to invoices.

Lifecycle

PhaseWhat happens
CreatePOST /v1/invoices returns a draft. The draft has no number yet (number is null).
UpdatePATCH /v1/invoices/{id} changes an invoice that has not been sent.
DeleteDELETE /v1/invoices/{id} removes a draft.
SendPOST /v1/invoices/{id}/send books the document, allocates the invoice number, and delivers it over the chosen channel.
DownloadGET /v1/invoices/{id}/pdf streams the rendered PDF at any point. Before send, pass ?draft=true for a watermarked preview.
TrackGET /v1/invoices/{id}/delivery-status returns the aggregate send summary plus a per-attempt log.

Create an invoice

POST /v1/invoices returns the draft as PublicInvoice. customerId is required, and the document must carry at least one product line (see Document lines). A billable line sends a priceId and a quantity; you may override unitPrice (it defaults to the price's current amount in the document currency). totalPrice and VAT (vatRate / vatAmount, derived from the product and the customer's VAT zone) are computed server-side — do not send them. totalPrice is quantity * unitPrice for a flat-rate price or an overridden unitPrice, and what the price's tiers charge for the quantity on a volume, graduated or package price. The invoice number stays null until the document is sent.

dueDate is optional. When omitted it is derived from the payment terms (date plus paymentTerms days; for cash terms the due date is the invoice date). An explicit dueDate may equal date but must not be earlier — see Errors.

subject and notes print on the PDF; description never does. See Text on the document.

TerminalCode
curl -X POST 'https://api.ledgerbee.com/api/v1/invoices' \ -H 'x-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "customerId": "0197a943-2325-7829-b835-b6c71a293065", "date": "2026-01-15", "dueDate": "2026-02-14", "currency": "DKK", "paymentTerms": 30, "subject": "Website maintenance, March", "notes": "Thank you for your business.", "lines": [ { "priceId": "0197a943-2325-7829-b835-b6c71a293099", "quantity": 2 } ] }'

Update an invoice

PATCH /v1/invoices/{id} changes an invoice whose status is draft or scheduled and returns the updated PublicInvoice. Send null to clear a field the API Reference marks as nullable, such as reference, subject or notes.

TerminalCode
curl -X PATCH 'https://api.ledgerbee.com/api/v1/invoices/0197a943-2325-7829-b835-b6c71a293066' \ -H 'x-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "reference": "PO-12345", "notes": null }'
RequestResult
A field is left outIts stored value is kept, except where the rules below change it.
A nullable field is nullThe field is cleared.
Any other field is null400.
lines is sentEvery stored line is replaced. Send the full intended set: a line left out of the array is removed.
lines is left outThe stored lines are kept.

The invoice must still carry at least one product line. Prices, totals and VAT are worked out again from the lines you send.

Changing customerId or currency requires lines in the same request: line prices are derived from the currency and line VAT from the customer's VAT zone. A customer change also removes the stored customerDepartmentId and customerContactId unless the request states new ones, and removes any extra email recipients added to the invoice in the app.

A request with date or paymentTerms and no dueDate sets the due date again from the invoice's payment terms.

An approved invoice whose content changes loses its approval. If it was scheduled to send, it returns to draft.

lines cannot be replaced on the invoices below. The request is refused with INVOICE_LINE_UPDATE_NOT_SUPPORTED, and details.reason says why:

details.reasonThe invoice
subscriptionwas created by subscription billing (it has a customerSubscriptionId or a billingGroupId, or isConsolidated set), or one of its lines bills a subscription.
self_billingis a self-billing invoice.
shipmenthas lines a shipment refers to.

The other fields of such an invoice can still be changed, except customerId and currency, which require lines.

A line that defers its revenue (recognitionPeriodDays) is replaced like any other line. Its revenue schedule is written again from the lines and the date the invoice ends up with, so the period a replacement line states is the one that is recognised.

A sent invoice is booked. Correct it with a credit note.

Delete an invoice

DELETE /v1/invoices/{id} removes an invoice whose status is draft and returns 204 with no body. The Errors table lists the drafts that are kept.

TerminalCode
curl -X DELETE 'https://api.ledgerbee.com/api/v1/invoices/0197a943-2325-7829-b835-b6c71a293066' \ -H 'x-api-key: YOUR_API_KEY'

Deleting a draft that subscription billing created removes the invoice only. Subscription billing does not bill that period again.

Status values

Invoice status is one of draft, scheduled, sending, sent, paid, partially_paid, cancelled, uncollectible, credited, ls_rejected.

ls_rejected appears only on an invoice collected through Leverandørservice (Mastercard Payment Services): the payer's bank rejected or charged back the collection while the invoice was sending, so the invoice was not paid that way.

Send

POST /v1/invoices/{id}/send books the document and allocates its number. What happens next is the deliveryType channel's business — Manual stops there and leaves delivery to you. Invoices accept every channel; see Sending.

TerminalCode
curl -X POST 'https://api.ledgerbee.com/api/v1/invoices/0197a943-2325-7829-b835-b6c71a293066/send' \ -H 'x-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "deliveryType": "Email", "overrideEmail": "billing@acme.example" }'

overrideEmail and overrideEanNumber apply to the single send unless updateCustomerRecord is true, which persists them onto the customer record. documentTemplateId overrides the PDF template for this send. The response carries success, deliveryType, and sproomDocumentId (the id of the document created on the Sproom network, for a Sproom send).

Delivery status

GET /v1/invoices/{id}/delivery-status returns a summary (send count, last channel, last recipient, last send time) and a chronological entries log of every attempt with its status (success / failed), deliveryType, recipient, sentAt, and errorCode on failure.

A Sproom send rejected by the network does not fail the request synchronously; it records a failed delivery entry with its errorCode. Poll delivery-status after a Sproom send to confirm the outcome.

Errors

ConditionResponseFix
Missing or wrong scope403Grant the matching read or write scope.
Non-UUID id / unknown id400 / 404Pass a UUID id that exists for your tenant.
dueDate earlier than date400 INVOICE_DUE_DATE_BEFORE_ISSUE_DATESend a due date on or after the invoice date, or omit dueDate to derive it from the payment terms.
Update of an invoice that has been sent400 INVOICE_MODIFICATION_FORBIDDENIssue a credit note against it.
Update that changes customerId or currency without lines400 INVOICE_CUSTOMER_OR_CURRENCY_CHANGE_REQUIRES_LINESSend the full line set in the same request. On an invoice whose lines cannot be replaced, the customer and currency cannot be changed.
Update with lines on an invoice whose lines cannot be replaced400 INVOICE_LINE_UPDATE_NOT_SUPPORTEDLeave lines out of the request. details.reason names the cause; see Update an invoice.
Update with lines, a department or a contact on an invoice that has no customer400 INVOICE_MISSING_CUSTOMERSend customerId together with lines.
Delete of an invoice that is not a draft, or of a draft whose revenue recognition has already posted400 INVOICE_DELETION_FORBIDDENIssue a credit note against a sent invoice.
Update or delete of an invoice waiting for an approver400 INVOICE_APPROVAL_PENDINGRetry once the approval is decided.
Delete of a draft a shipment refers to400 INVOICE_DELETION_BLOCKED_BY_SHIPMENTCancel the shipment first.
Delete of a draft with a card payment that took money, may still take it, or holds an amount400 INVOICE_DELETION_BLOCKED_BY_CARD_CHARGEKeep the draft.
scheduledSendAt on cash payment terms400 INVOICE_CASH_CANNOT_BE_SCHEDULEDCash invoices are paid on send; remove scheduledSendAt or use day-count terms.
Card payment providers with no customer400 INVOICE_CARD_PAY_REQUIRES_CUSTOMERSet customerId when enabling allowedPaymentProviders.

Subscription and billing-group invoices

Three fields on an invoice say who it bills:

FieldSet when
customerSubscriptionIdThe invoice bills exactly one subscription.
billingGroupIdThe invoice is a billing group's shared document. Never set together with customerSubscriptionId.
isConsolidatedSeveral subscriptions bill onto this one document: a billing group's shared invoice, or a parent customer's invoice covering its child customers' subscriptions. With both ids null it is the parent-paid kind.

A manually created invoice carries neither id. List a group's documents with GET /v1/invoices?billingGroupId=<uuid>.

customerSubscriptionId names the exact version of the subscription that issued the invoice. Once a subscription has been changed (a new plan, a scheduled edit) that id can differ from the subscription's own id; the per-line subscriptionId below and the subscriptionId list filter always use the subscription's own id, and the filter accepts either.

Which subscription each line was billed for

One invoice can carry several subscriptions' lines: an add-on bills on its parent's invoice, a billing group's members share one document, and a parent customer's invoice covers its children's subscriptions. Each line on GET /v1/invoices/{id} says whose it is:

Line fieldValue
subscriptionIdThe subscription the line was billed for. An add-on's lines name the add-on, not the parent the invoice is addressed to. null on a line that belongs to no subscription, such as a line on a manually created invoice.
addonOfSubscriptionIdOn an add-on's lines, the parent it is billed with. null on every other line.

The same two fields are on credit-note lines.

A parent with one add-on, billed on one invoice addressed to the parent (abridged — other line fields omitted):

Code
{ "id": "0197a943-2325-7829-b835-b6c71a2930a1", "customerSubscriptionId": "0197a943-2325-7829-b835-b6c71a2930b1", "lines": [ { "id": "0197a943-2325-7829-b835-b6c71a2930c1", "totalPrice": "500.00", "subscriptionId": "0197a943-2325-7829-b835-b6c71a2930b1", "addonOfSubscriptionId": null }, { "id": "0197a943-2325-7829-b835-b6c71a2930c2", "totalPrice": "1000.00", "subscriptionId": "0197a943-2325-7829-b835-b6c71a2930b2", "addonOfSubscriptionId": "0197a943-2325-7829-b835-b6c71a2930b1" } ] }

Find the invoices a subscription was billed on

GET /v1/invoices?subscriptionId=<uuid> returns every invoice the subscription was billed on: the ones addressed to it, and the ones addressed to another subscription or to a billing group that carry its lines. Filtering by an add-on therefore returns its parent's invoices. An unknown subscription returns an empty list, the same as an unknown customerId; a malformed id returns 400.

TerminalCode
curl 'https://api.ledgerbee.com/api/v1/invoices?subscriptionId=0197a943-2325-7829-b835-b6c71a2930b2' \ -H 'x-api-key: YOUR_API_KEY'

List items carry no lines; read an invoice for its per-line subscriptionId.

Webhook events

Subscription-driven invoices (those the billing engine sends) emit the billing.invoice_sent topic. On a billing group's shared invoice the payload's subscriptionId is null; read the invoice for its billingGroupId. Invoices you create and send directly over this API are booked the same way but are not subscription events. Webhooks covers endpoint setup, the signed-envelope format, and the full topic list.

TopicFires when
billing.invoice_sentFired when an invoice document is sent to the customer.
billing.credit_note_sentFired when a credit note document is sent to the customer.
billing.invoice_updatedFired when an invoice is changed, in the app or through the API alike: its fields, its lines or their order, or its status. A draft scheduled or cancelled fires it, and so does an invoice reaching sent once it is delivered, beside billing.invoice_sent. A save that changes nothing fires nothing; changedFields names what moved.
billing.invoice_deletedFired when a draft invoice is deleted, in the app or through the API alike. Only drafts can be deleted; a sent invoice is corrected with a credit note instead.
billing.invoice_paidFired when a customer invoice becomes paid in full: by payments, by a settlement, or by a credit note applied to it. Only the invoice fires it — the credit note it was settled against does not, and neither does a reminder fee or an advance. A partial payment fires nothing. An invoice reopened (a payment reverted) and paid again fires again. Invoices brought in by an import do not fire it.

A change to an invoice emits billing.invoice_updated, whether it is made over this API or in the LedgerBee app. The payload is a summary of the invoice after the change, not the whole invoice: its id, number, customer, status, totals and currency, with changedFields, the names of the fields that changed. It does not carry the lines; read the invoice for them. Webhooks lists every field of the payload. Changing lines, or only their order, lists lines, plus subtotal, vat and amount when the totals moved. Sending an invoice emits it as well, with changedFields set to ["status"] once the invoice is delivered and its status is sent. A PATCH that changes nothing emits no event. Deleting a draft emits the delete topic in the table above, carrying the invoice's id, its number (null until the invoice is sent) and its customer.

Last modified on November 6, 2026
OverviewCredit notes
On this page
  • Lifecycle
  • Create an invoice
  • Update an invoice
  • Delete an invoice
  • Status values
  • Send
  • Delivery status
  • Errors
  • Subscription and billing-group invoices
    • Which subscription each line was billed for
    • Find the invoices a subscription was billed on
  • Webhook events
JSON