Skip to content
Tier

Invoice history

Pro

The account's invoices: number, when each was issued, the period it covers, the amount in its own currency, its status (an open or overdue one says when it's due), and a download your app serves. Candor never builds the PDF or takes payment: pass portal and the footer points at the billing provider's own portal (Polar, Stripe, Paddle) for cards and payment methods.

Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1 and 2.6.2: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/invoice-history

Brings in: badge, data, heading-level, heading-scope, locale, ops, page-state, table, tokens, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import { InvoiceHistory } from "@/components/candor/invoice-history"

export default function Example() {
  return (
    <InvoiceHistory
      className="max-w-3xl"
      portal={{ provider: "Stripe", href: "#billing-portal" }}
      invoices={[
        { id: "i4", number: "INV-2026-0011", issuedAt: "2026-11-01", periodStart: "2026-11-01", periodEnd: "2026-11-30", amount: 588, currency: "USD", status: "open", dueAt: "2026-11-15" },
        { id: "i3", number: "INV-2026-0010", issuedAt: "2026-10-01", periodStart: "2026-10-01", periodEnd: "2026-10-31", amount: 588, currency: "USD", status: "paid", url: "#invoice-0010.pdf" },
        { id: "i2", number: "INV-2026-0009", issuedAt: "2026-09-01", periodStart: "2026-09-01", periodEnd: "2026-09-30", amount: 490, currency: "USD", status: "refunded", url: "#invoice-0009.pdf" },
        { id: "i1", number: "INV-2026-0008", issuedAt: "2026-08-01", periodStart: "2026-08-01", periodEnd: "2026-08-31", amount: 490, currency: "USD", status: "overdue", dueAt: "2026-08-15", url: "#invoice-0008.pdf" },
      ]}
    />
  )
}

<InvoiceHistory>

PropTypeDefaultDescription
invoicesrequiredInvoice[]—The invoices, newest first as the app orders them.
portal{ provider: string; href: string } | undefined—The billing provider's customer portal, where payment methods are changed: its name and the link your server made.
stateListState | undefined—What the list is showing: its rows (ready, the default), loading, empty or error with the reason, or partial with a note over the rows. Loading, empty and error draw in place of the rows, in this component's own words, so a list the app doesn't have yet isn't shown as an empty one.
onRetry(() => void) | undefined—Shows Try again when `state` is an error; called when it's pressed. Pass it only when it loads the list again.
classNamestring | undefined—Extra classes for the outer element.
headingLevelHeadingLevel | undefined—The level of the list's heading, so it fits under the page's own headings. Default: one below the nearest `HeadingScope`, else 2 (`<h2>`).

Strings

The fixed words, in English by default. Change any of them under invoiceHistory in <LocaleProvider strings={{ … }}>; the table is exported as invoiceHistoryStrings.

KeyEnglish
labelInvoices
headingInvoices
emptyNo invoices yet.
loadingLoading invoices
errorInvoices couldn’t be loaded.
invoiceInvoice
issuedIssued
periodPeriod
periodRange{start} to {end}
amountAmount
statusStatus
downloadDownload
downloadInvoiceDownload invoice {number}
notReadyNot ready
notReadyWhyThe PDF for {number} isn’t ready yet.
paidPaid
openOpen
overdueOverdue
voidVoid
refundedRefunded
duedue {date}
portalPayment methods and billing are managed at {provider}.
openPortalOpen {provider}

Types

Invoice
One invoice as the billing provider issued it.
{ id: string; /** The invoice's number as printed on it, e.g. "INV-2026-0042". */ number: string; issuedAt: string; periodStart: string; periodEnd: string; /** The total in major units: 49.5 for $49.50. */ amount: number; /** ISO 4217 code, e.g. "USD" or "EUR". */ currency: string; status: "paid" | "open" | "overdue" | "void" | "refunded"; /** When an open or overdue invoice is due. */ dueAt?: string | undefined; /** Where your app serves the PDF (your route, or the provider's hosted link). Without it the row says it isn't ready. */ url?: string | undefined; }

Types from other items

The props above take these. Each is defined by another item; import it from the path shown.

ListState from @/lib/candor/data
What a list or table is showing, the same shape as `ChartState` and as page-state's `ListState` (which the free tier ships, so it declares its own rather than import this file): its rows (ready), the shape of rows still coming (loading), nothing and why (empty), the rows it has with a note on what's missing (partial), or why it couldn't load (error). Lists without a `state` show their rows.
ChartState
HeadingLevel from @/lib/candor/heading-level
A heading's level in the page's outline: `1` is `<h1>`, `6` is `<h6>`. Every Candor item that draws a heading takes its `headingLevel` as this type; the level is where the heading sits in the outline, never how large it looks.
1 | 2 | 3 | 4 | 5 | 6
ChartState from @/lib/candor/data
{ kind: "ready"; } | { kind: "loading"; } /** Nothing to plot, and why. */ | { kind: "empty"; reason: string; } /** Some of the range is missing. */ | { kind: "partial"; note: string; } | { kind: "error"; reason: string; }