Creating invoices

How invoices are generated, referenced, and rendered

Overview

An invoice is created by selecting one or more uninvoiced ledger entries on a single policy. Root creates the invoice, attaches a line item per ledger entry, allocates a reference, computes the total, queues the PDF, and moves the invoice to pending, all in a single atomic operation.

There are two ways to trigger this:

  • Via the API — call Create an invoice with the policy ID and the ledger entry IDs to bundle. This is the path used by the dashboard's "New invoice" flow.
  • Via a lifecycle hook — a product module can call the generate_invoice lifecycle hook to raise invoices automatically as part of its own billing logic. The platform does not infer eligibility or run a billing schedule for you; your product module decides which ledger entries to bundle and when.
📘

Find what is available to invoice

Use List uninvoiced ledger entries to see which ledger entries on a policy have not yet been placed on an invoice. Each ledger entry can appear on at most one invoice.

What you supply

FieldRequiredNotes
typeYesOne of proforma, receipted, or credit_note.
ledger_entry_idsYesAt least one. Each must belong to the policy and must not already be invoiced.
tax_point_dateYesThe calendar date that renders on the document.
referenceNoYour own reference. Must be unique within your organization. If omitted, Root generates one.
original_invoice_idNoOnly for credit notes. See Credit notes and refunds.
line_item_refund_mappingsNoOnly for credit notes. Maps original lines to their reversing lines.

The invoice's currency is inherited from the policy. You do not supply it.

How the total is computed

The invoice total is the sum of the amounts of the referenced ledger entries. Like all monetary amounts on the Root API, it is an integer amount in cents.

For a credit_note, the bundled ledger entries must sum to a negative total, because a credit note reduces what is owed.

References

A reference is a human-readable identifier that is unique per organization.

  • Supplied by you. Pass reference in the request. If it collides with an existing reference in your organization, the request is rejected with a validation error.
  • Generated by Root. Omit reference, and Root allocates one of the form INV-XXXXXXXX (the prefix INV- followed by eight uppercase hexadecimal characters). Generation retries automatically on the rare collision; if it cannot find a free value, the request fails and asks you to supply an explicit reference.

A reference is only allocated when an invoice is finalised. An open draft has no reference yet.

Document rendering

After an invoice is finalised, its PDF is rendered asynchronously, after the invoice has been committed. The render uses the invoice template registered on the policy's product module:

  1. If the product module has no invoice template configured, no PDF is produced. The invoice is still valid.
  2. Otherwise, Root builds a render context from the invoice, its policy and policyholder, and its line items, renders your template to HTML, and produces a PDF.
  3. The resulting file is stored and the invoice's document_file_id is set.
📘

document_file_id appears after creation

Because rendering happens after the invoice is committed, the document_file_id is not present in the response to the create call. Re-fetch the invoice with Retrieve an invoice to get the file reference once rendering has completed. The invoice_created event also omits the file reference for the same reason.

Your template branches on invoice.type to choose between proforma, receipted, and credit-note layouts.

Validation rules

A create call is rejected if any of the following hold:

  • Invoicing is not enabled for the organization (invoicing_not_enabled).
  • No ledger entries are supplied.
  • The same ledger entry is supplied more than once.
  • A ledger entry does not belong to the policy.
  • A ledger entry is already attached to another invoice (ledger entries already invoiced).
  • The reference you supplied already exists in your organization.
  • The invoice is a credit_note and its total is not negative.
  • The invoice is a credit_note and no original_invoice_id is supplied, or original_invoice_id is supplied on a non-credit-note type.

See Create an invoice for the full request and response, and Errors below for the codes.

Error codes

CodeMeaning
invoicing_not_enabledInvoicing is not enabled for the organization.
invoice_validation_errorThe request failed a validation rule (see above).
invoice_not_foundThe invoice does not exist, or the caller cannot access its policy.
illegal_invoice_transitionA status change was attempted that the lifecycle does not allow.
concurrent_invoice_modificationAnother writer changed the invoice before this transition could be applied.
invoice_invariant_errorAn internal consistency check failed; the operation was rolled back.