Credit notes and refunds

How to reverse a finalised invoice

Overview

Finalised invoices are immutable. To refund or correct one, you do not edit it: you raise a new credit note invoice against it. The credit note is a credit_note-type invoice with a negative total, linked back to the original through original_invoice_id. Creating it moves the original invoice to refunded and fires the invoice_refunded event.

This keeps a complete, auditable trail: the original invoice and the credit note both remain on record, and the relationship between them is explicit.

How a refund works

  1. Raise new credit ledger entries on the policy for the amounts being refunded (and, where applicable, any admin-fee or tax debits that go with the refund).
  2. Call Create an invoice with:
    • type set to credit_note,
    • ledger_entry_ids referencing the new credit entries (their amounts must sum to a negative total),
    • original_invoice_id set to the invoice being refunded,
    • optionally, line_item_refund_mappings to record which original line each credit line reverses.
  3. Root creates the credit note, finalises it, and atomically moves the original invoice to refunded, firing invoice_refunded with the original and the refund invoice IDs.
  4. The credit note renders through your template's credit_note layout.
❗️

A credit note must be a true credit

The bundled ledger entries on a credit_note must sum to a negative total. A credit note is always finalised on creation; it cannot be created as an open draft.

What can be refunded

The original invoice must be in a refundable status: pending, sent, or paid. You cannot raise a credit note against an invoice that is open, already void, or already refunded.

The credit note must be on the same policy as the original invoice.

Per-line refunds

To record that specific lines were reversed (rather than the whole invoice), supply line_item_refund_mappings. Each mapping links:

  • original_line_item_id — a line item on the original invoice, to
  • refund_ledger_entry_id — the ledger entry on the credit note that reverses it.

Root validates these mappings and sets refunded_by_line_item_id on each original line so dashboards and templates can show "this line was reversed by line X on credit note Y."

🚧

Mappings must be 1:1

Within a single credit note, no original line item may be mapped twice, and no refund ledger entry may be mapped twice. Duplicate mappings are rejected with a validation error. Each refund_ledger_entry_id must be one of the ledger entries on the credit note, and each original_line_item_id must be a line on the original invoice.

Result

  • The credit note exists as its own invoice, with original_invoice_id pointing at the refunded invoice.
  • The original invoice's status becomes refunded (terminal).
  • invoice_refunded fires on the policy, carrying the original invoice_id and the refund_invoice_id.

See Invoice events for the event payloads.