[Objects](https://oods-foundry.com/objects) / Invoice

# Invoice

Canonical SaaS invoice object normalizing payment terms, status, and refund posture.

beta 4 traits · 7 contexts · 42 fields [Invoice.object.yaml](#file) [How objects work](https://oods-foundry.com/guides/objects-and-traits)

Generated from @oods/foundry 0.10.2

This object is marked beta.

## Screens

Every screen below was generated from this object by OODS Foundry 0.10.2, in React and Vue, and shows the calls that made it and its content hash. Each runs as its generated app runs, in this site's brand, Aquex, in the theme you choose, with the sample records this object's own file carries. A value no record gives shows as a neutral one, such as an empty value or "Not recorded"; OODS Foundry invents none.

[Invoice detail screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/detail-react)

React app · sample records Maturity: beta `sha256:cf7934100633…` [Open full size: Invoice detail screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/detail-react)

Vue app · sample records Maturity: beta `sha256:f824c0c1f74b…` [Open full size: Invoice detail screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/detail-vue)

React app · sample records Maturity: beta `sha256:05dac7424d09…` [Open full size: Invoice list screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/list-react)

Vue app · sample records Maturity: beta `sha256:9476b6d0b0dc…` [Open full size: Invoice list screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/list-vue)

React app · sample records Maturity: beta `sha256:062d4b0b456a…` [Open full size: Invoice form screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/form-react)

Vue app · sample records Maturity: beta `sha256:edb30ad46a2a…` [Open full size: Invoice form screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/form-vue)

React app · sample records Maturity: beta `sha256:d7e39862edb8…` [Open full size: Invoice timeline screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/timeline-react)

Vue app · sample records Maturity: beta `sha256:a89fd3acbaf7…` [Open full size: Invoice timeline screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/timeline-vue)

React app · sample records Maturity: beta `sha256:b36593ed2fe6…` [Open full size: Invoice card screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/card-react)

Vue app · sample records Maturity: beta `sha256:0a33320e888f…` [Open full size: Invoice card screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/card-vue)

React app · sample records Maturity: beta `sha256:f5c1de94835b…` [Open full size: Invoice inline screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/inline-react)

Vue app · sample records Maturity: beta `sha256:b25505d56494…` [Open full size: Invoice inline screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/inline-vue)

React app · sample records Maturity: beta `sha256:01e49d0e007c…` [Open full size: Invoice workflow screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/workflow-react)

Vue app · sample records Maturity: beta `sha256:064633aa44d3…` [Open full size: Invoice workflow screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/invoice/screens/workflow-vue)

What `design_compose` reported for every screen here:

- `OODS-V121` Object 'Invoice' has maturity 'beta' — composed output may change.

The calls that made the Invoice detail apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "detail",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-2e9a71e1",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-2e9a71e1",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:cf79341006331fe509c72fcfdd33524098062f0a029c6664c4c4875f824e6a81`. Its `src/` folder: App.tsx, GeneratedUI.tsx, app.css, charts/, main.tsx, oods-brand-aquex.css

The Vue app's content hash: `sha256:f824c0c1f74b29f6dec3f284ecf9df32af8dbd04ede28fe38db2061ef135a5cf`. Its `src/` folder: App.vue, GeneratedUI.vue, app.css, charts/, main.ts, oods-brand-aquex.css

The calls that made the Invoice list apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "list",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-ea32062f",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-ea32062f",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:05dac7424d0969dd9d65ac50e79bc36b8824600f02f28d61ed5a70776e548fda`. Its `src/` folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css

The Vue app's content hash: `sha256:9476b6d0b0dc281e4df501bffb2ca2b9f2beddea07e9712055c0cbf271ac814a`. Its `src/` folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css

For this screen it also reported:

- `OODS-V119` No view_extensions found for context "form" in object "Invoice". Available contexts: list, card, detail, dashboard

The calls that made the Invoice form apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "form",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-ef3b11ef",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-ef3b11ef",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:062d4b0b456a31846f480da86d6cf152f5ffd2a5bcf2375289228e4680ee31a7`. Its `src/` folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css

The Vue app's content hash: `sha256:edb30ad46a2ae71c13d68aeee9b4015a1eda6684a19c1de373dba2806e9a8742`. Its `src/` folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css

For this screen it also reported:

- `OODS-V119` No view_extensions found for context "timeline" in object "Invoice". Available contexts: list, card, detail, dashboard

The calls that made the Invoice timeline apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "timeline",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-82fbfb12",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-82fbfb12",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:d7e39862edb83c9d3344616548d04536e584fc75f390ce128a1a588beac136da`. Its `src/` folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css

The Vue app's content hash: `sha256:a89fd3acbaf7969dc0f5694ee6064b423e3236ca8f7cedde7a3f00d44987f57f`. Its `src/` folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css

The calls that made the Invoice card apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "card",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-f88d3c21",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-f88d3c21",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:b36593ed2fe63b1eb4a4fbf11ef17f6866c9160196362462dfef7b16ed7173f2`. Its `src/` folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css

The Vue app's content hash: `sha256:0a33320e888f501a38107bfd22131017c3fdf83f316de953b8093310a24a5803`. Its `src/` folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css

For this screen it also reported:

- `OODS-V119` No view_extensions found for context "inline" in object "Invoice". Available contexts: list, card, detail, dashboard

The calls that made the Invoice inline apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "inline",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-f712263e",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-f712263e",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:f5c1de94835bc35477d42dff0d52fd51b078a5615f88f9d2d114d1186b122056`. Its `src/` folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css

The Vue app's content hash: `sha256:b25505d5649457afe9a5ede5d3457502b8f9959aedd6a0766925ae1a744e5533`. Its `src/` folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css

For this screen it also reported:

- `OODS-V121` as above, 4 times in all
- `OODS-V119` No view_extensions found for context "form" in object "Invoice". Available contexts: list, card, detail, dashboard
- `OODS-V119` No view_extensions found for context "timeline" in object "Invoice". Available contexts: list, card, detail, dashboard

The calls that made the Invoice workflow apps, in React and Vue

3 calls, as the pipeline sent them

```
design_compose {
  "object": "Invoice",
  "context": "workflow",
  "preferences": {
    "brand": "Aquex",
    "theme": "light"
  }
}

code_generate {
  "schemaRef": "compose-b3c97c8f",
  "framework": "react",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}

code_generate {
  "schemaRef": "compose-b3c97c8f",
  "framework": "vue",
  "profile": "build",
  "options": {
    "output": "application",
    "brand": "Aquex",
    "theme": "light",
    "payloadMode": "file"
  }
}
```

The React app's content hash: `sha256:01e49d0e007c333d878b39e8fefbc2d3f37f9a5fea8a2cb81b8e3c8cb5995802`. Its `src/` folder: App.tsx, actions.ts, app.css, application.ts, chart-assets.ts, charts/, main.tsx, oods-brand-aquex.css, sample-data.ts, screens/, ssr.tsx, store.ts

The Vue app's content hash: `sha256:064633aa44d316b6106873997345b45cc2a88b2be7b79d6e1d05111c3d3ff717`. Its `src/` folder: App.vue, actions.ts, app.css, application.ts, chart-assets.ts, charts/, main.ts, oods-brand-aquex.css, sample-data.ts, screens/, ssr.ts, store.ts

## Fields

| Field | Type | Description |
| - | - | - |
| `invoice_number` required | string | Human readable invoice identifier presented to customers. |
| `status` required | string | Canonical invoice status after provider mapping. |
| `provider_status` | string | Original provider reported status or badge. |
| `issued_at` required | datetime | Timestamp when the invoice was finalized or posted. |
| `due_at` | datetime | Payment due timestamp derived from payment terms. |
| `paid_at` | datetime | Timestamp when full payment cleared. |
| `total_minor` required | integer | Total amount due expressed in minor currency units. |
| `balance_minor` | integer | Remaining amount outstanding in minor units. |
| `currency` required | string | ISO 4217 currency for the invoice. |
| `payment_terms` | string | Payment term label describing when payment is expected. |
| `collection_state` | string | Dunning phase or retry program detail presented to success teams. |
| `last_reminder_at` | datetime | Timestamp of most recent payment reminder issued to customer. |
| `aging_bucket_days` | integer | Number of days outstanding grouped for aging reports. |
| `attempt_count` | integer | Number of automatic payment attempts made on this invoice (Stripe smart-retries attempt_count).MoreIncrements on each retry in the dunning window. Source: docs.stripe.com/billing/revenue-recovery/smart-retries. |
| `next_payment_attempt` | datetime | When the next automatic payment retry is scheduled (Stripe smart-retries next_payment_attempt).MoreDefines the open end of the retry window — modeled on the Refundable.refundable_until datetime-window precedent. Absent/null when no further attempts are scheduled (retries exhausted → invoice goes uncollectible, mirroring the subscription \`unpaid\` state). Source: docs.stripe.com/billing/revenue-recovery/smart-retries. |
| `memo` | string | Internal finance note or customer visible memo. |
| `refundable_until` | datetime | Date when refund eligibility window ends for this record. |
| `refund_policy_url` | string | Link to customer facing refund or cancellation policy. |
| `total_refunded_minor` | integer | Cumulative amount refunded in minor currency units. |
| `credit_memo_balance_minor` | integer | Remaining credit memo balance that can be applied to invoices. |
| `credit_memo_type` | string | Category of credit memo tied to business justification. |
| `last_refund_at` | datetime | Timestamp when the most recent refund was issued. |
| `requires_manager_approval` | boolean | Indicates if finance manager approval is required before issuing refund. |
| `notes` | string | Internal commentary about refund actions or policy exceptions. |
| `created_at` required | datetime | Timestamp recording when the entity was first created. |
| `updated_at` | datetime | Timestamp for the most recent modification, when available. |
| `last_event` required | string | Lifecycle event associated with the most recent timestamp mutation. |
| `last_event_at` | datetime | Timestamp for the lifecycle event captured in last_event. |
| `invoice_id` required | string | Primary identifier for the invoice inside the billing domain. |
| `subscription_id` required | string | Subscription identifier this invoice is associated with. |
| `provider` required | string | Source system providing invoice data. |
| `provider_invoice_id` | string | Native provider identifier retained for audit trails. |
| `billing_contact_name` | string | Customer billing contact receiving the invoice. |
| `billing_contact_email` | email | Email address for the billing contact. |
| `tax_minor` | integer | Tax amount collected on the invoice in minor currency units. |
| `discount_minor` | integer | Total discounts applied to the invoice in minor units. |
| `subtotal_minor` | integer | Subtotal before discounts and tax in minor units. |
| `line_items` | InvoiceLineItem\[] | Normalized line items with quantity, amount_minor, and description fields. |
| `attachments` | AssetReference\[] | Supporting documents or credit memos associated with the invoice. |
| `portal_url` | string | Link to the hosted invoice or customer billing portal. |
| `dunning_step` | string | Current dunning playbook step label (ex: reminder_1, reminder_final, collections).MoreThe structured retry window (attempt_count + next_payment_attempt) is provided by the composed SaaSBillingPayable trait; this field is the human-readable step name. |
| `payment_source` | string | Payment method used or expected (card, ach, wire). |

## Traits

Each trait adds fields and behaviour. Every object with the trait gets the same.

- [SaaSBillingPayable as InvoiceTerms](https://oods-foundry.com/traits/saas-billing-payable)
- [SaaSBillingRefundable as CreditWindow](https://oods-foundry.com/traits/saas-billing-refundable)
- [Timestampable as AuditTrail](https://oods-foundry.com/traits/timestampable)
- [MarkBar](https://oods-foundry.com/traits/mark-bar)

## Relationships

These arrows show declared relationships between object types. They don't join live records.

- [Subscription](https://oods-foundry.com/objects/subscription), many-to-one, via `subscription_id`

## The object file

The Invoice object definition in YAML: `domains/saas-billing/objects/Invoice.object.yaml`

```
object:
  name: Invoice
  version: 1.0.0
  domain: saas.billing
  description: Canonical SaaS invoice object normalizing payment terms, status, and refund posture.
  tags:
    - billing
    - invoice
    - finance

traits:
  - name: SaaSBillingPayable
    alias: InvoiceTerms
  - name: SaaSBillingRefundable
    alias: CreditWindow
  - name: lifecycle/Timestampable
    alias: AuditTrail
    parameters:
      recordedEvents:
        - created
        - posted
        - payment_initiated
        - payment_cleared
        - payment_failed
        - voided
        - written_off
      timezone: UTC
      allowNullUpdatedAt: true
  # s223-m01 (#2527 ruling 2): line items are money, so the chart plots major units in the invoice's currency
  # (amount_minor / 100, the y axis reading $12,000, £1,234 or €19), not minor units.
  - name: viz/MarkBar
    parameters:
      title: Invoice line item amounts
      description: Line-item amounts in the invoice's currency; line items with the same description are summed.
      chart:
        chartType: bar
        source: record-array
        dataField: line_items
        encodings:
          x: {field: description, title: Line item}
          y: {field: amount_minor, aggregate: sum, title: Amount}
        minorUnits: 100
        currencyField: currency
        # Copied from domains/saas-billing/examples/stripe.json invoice.line_items.
        sampleRows:
          - description: Scale plan
            quantity: 1
            amount_minor: 284000
            unit_amount_minor: 284000

schema:
  invoice_id:
    type: string
    required: true
    description: Primary identifier for the invoice inside the billing domain.
  subscription_id:
    type: string
    required: true
    description: Subscription identifier this invoice is associated with.
  provider:
    type: string
    required: true
    description: Source system providing invoice data.
  provider_invoice_id:
    type: string
    required: false
    description: Native provider identifier retained for audit trails.
  billing_contact_name:
    type: string
    required: false
    description: Customer billing contact receiving the invoice.
  billing_contact_email:
    type: email
    required: false
    description: Email address for the billing contact.
  tax_minor:
    type: integer
    required: false
    description: Tax amount collected on the invoice in minor currency units.
  discount_minor:
    type: integer
    required: false
    description: Total discounts applied to the invoice in minor units.
  subtotal_minor:
    type: integer
    required: false
    description: Subtotal before discounts and tax in minor units.
  line_items:
    type: InvoiceLineItem[]
    required: false
    description: Normalized line items with quantity, amount_minor, and description fields.
    default: []
  attachments:
    type: AssetReference[]
    required: false
    description: Supporting documents or credit memos associated with the invoice.
    default: []
  portal_url:
    type: string
    required: false
    description: Link to the hosted invoice or customer billing portal.
  dunning_step:
    type: string
    required: false
    description: >-
      Current dunning playbook step label (ex: reminder_1, reminder_final, collections).
      The structured retry window (attempt_count + next_payment_attempt) is provided by
      the composed SaaSBillingPayable trait; this field is the human-readable step name.
  payment_source:
    type: string
    required: false
    description: Payment method used or expected (card, ach, wire).

semantics:
  invoice_id:
    semantic_type: billing.invoice.id
    token_mapping: tokenMap(billing.invoice.id)
  subscription_id:
    semantic_type: billing.invoice.subscription_id
    token_mapping: tokenMap(billing.invoice.subscription_id)
  provider:
    semantic_type: billing.invoice.provider
    token_mapping: tokenMap(billing.invoice.provider)
  provider_invoice_id:
    semantic_type: billing.invoice.provider_id
    token_mapping: tokenMap(billing.invoice.provider_id)
  # The one-line summary under the invoice number in lists: who is billed.
  billing_contact_name:
    semantic_type: text.summary
    token_mapping: tokenMap(billing.invoice.billing_contact_name)
  billing_contact_email:
    semantic_type: billing.invoice.billing_contact_email
    token_mapping: tokenMap(billing.invoice.billing_contact_email)
  tax_minor:
    semantic_type: billing.invoice.tax_minor
    token_mapping: tokenMap(billing.invoice.tax_minor)
    ui_hints:
      component: CurrencyAmount
      currencyField: currency
      minorUnits: 100
  discount_minor:
    semantic_type: billing.invoice.discount_minor
    token_mapping: tokenMap(billing.invoice.discount_minor)
    ui_hints:
      component: CurrencyAmount
      currencyField: currency
      minorUnits: 100
  subtotal_minor:
    semantic_type: billing.invoice.subtotal_minor
    token_mapping: tokenMap(billing.invoice.subtotal_minor)
    ui_hints:
      component: CurrencyAmount
      currencyField: currency
      minorUnits: 100
  line_items:
    semantic_type: billing.invoice.line_items
    token_mapping: tokenMap(billing.invoice.line_items)
  attachments:
    semantic_type: billing.invoice.attachments
    token_mapping: tokenMap(billing.invoice.attachments)
  portal_url:
    semantic_type: billing.invoice.portal_url
    token_mapping: tokenMap(billing.invoice.portal_url)
  dunning_step:
    semantic_type: billing.invoice.dunning_step
    token_mapping: tokenMap(billing.invoice.dunning_step)
  payment_source:
    semantic_type: billing.invoice.payment_source
    token_mapping: tokenMap(billing.invoice.payment_source)

tokens:
  billing.invoice.id: "var(--cmp-text-strong)"
  billing.invoice.billing_contact_name: "var(--cmp-text-body-strong)"
  billing.invoice.payment_source: "var(--cmp-text-subtle)"
  billing.invoice.dunning_step: "var(--cmp-badge-text-warning)"

metadata:
  owners:
    - revenue-ops@oods.systems
    - finance@oods.systems
  maturity: beta
  references:
    - R13.5 Canonical Model: Subscription and Invoice
    - R4.5 SaaS Enum-to-Token Mapping Schema

# Authored type associations; no record join or referential-integrity claim.
relationships:
  - target: Subscription
    via: subscription_id
    cardinality: many-to-one
    label: Subscription

# Eight authored sample invoices for the sample subscriptions; each is billed to a sample Organization by name. Line
# items sum to the subtotal, the balance is what remains unpaid, and the last event is the latest recorded change (a
# refund is not a recorded event).
samples:
  - invoice_id: inv_2026_0142
    invoice_number: INV-2026-0142
    subscription_id: sub_northwind_business
    provider: Stripe
    provider_invoice_id: in_1RkT2nNw8aQ5bC01
    provider_status: paid
    billing_contact_name: Northwind Traders
    billing_contact_email: billing@northwind.example
    status: paid
    currency: USD
    payment_terms: due_upon_receipt
    line_items:
      - { description: Business plan, quantity: 1, unit_amount_minor: 14900, amount_minor: 14900 }
    subtotal_minor: 14900
    discount_minor: 0
    tax_minor: 0
    total_minor: 14900
    balance_minor: 0
    attempt_count: 1
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0142
    memo: Business plan, Sep 2 to Oct 2
    issued_at: '2026-09-02T15:00:00Z'
    due_at: '2026-09-02T15:00:00Z'
    paid_at: '2026-09-02T15:01:00Z'
    created_at: '2026-09-02T15:00:00Z'
    updated_at: '2026-09-02T15:01:00Z'
    last_event: payment_cleared
    last_event_at: '2026-09-02T15:01:00Z'
  - invoice_id: inv_2026_0118
    invoice_number: INV-2026-0118
    subscription_id: sub_marlow_starter
    provider: Stripe
    provider_invoice_id: in_1QwE8rMa2lYo9gV7
    provider_status: void
    billing_contact_name: Marlow Yoga
    billing_contact_email: studio@marlowyoga.example
    status: void
    currency: USD
    payment_terms: due_upon_receipt
    line_items:
      - { description: Starter plan, quantity: 1, unit_amount_minor: 1900, amount_minor: 1900 }
    subtotal_minor: 1900
    discount_minor: 0
    tax_minor: 0
    total_minor: 1900
    balance_minor: 0
    attempt_count: 0
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0118
    memo: Renewal issued before the cancellation took effect; voided
    issued_at: '2026-07-09T10:15:00Z'
    due_at: '2026-07-09T10:15:00Z'
    paid_at: null
    created_at: '2026-07-09T10:15:00Z'
    updated_at: '2026-07-09T10:20:00Z'
    last_event: voided
    last_event_at: '2026-07-09T10:20:00Z'
  - invoice_id: inv_2026_0155
    invoice_number: INV-2026-0155
    subscription_id: sub_tidewater_enterprise
    provider: Stripe
    provider_invoice_id: in_1SkV7cRx1nTd8qJ4
    provider_status: open
    billing_contact_name: Tidewater Co-op
    billing_contact_email: treasurer@tidewater.example
    status: processing
    currency: USD
    payment_terms: net_45
    line_items:
      - { description: Enterprise plan, quantity: 1, unit_amount_minor: 1080000, amount_minor: 1080000 }
      - { description: Premium support, quantity: 1, unit_amount_minor: 120000, amount_minor: 120000 }
    subtotal_minor: 1200000
    discount_minor: 0
    tax_minor: 0
    total_minor: 1200000
    balance_minor: 1200000
    attempt_count: 0
    payment_source: wire
    portal_url: https://pay.example/invoices/INV-2026-0155
    memo: Annual renewal, Oct 30 2026 to Oct 30 2027; bank transfer in progress
    issued_at: '2026-09-15T21:00:00Z'
    due_at: '2026-10-30T14:00:00Z'
    paid_at: null
    created_at: '2026-09-15T21:00:00Z'
    updated_at: '2026-09-28T21:00:00Z'
    last_event: payment_initiated
    last_event_at: '2026-09-28T21:00:00Z'
  - invoice_id: inv_2026_0139
    invoice_number: INV-2026-0139
    subscription_id: sub_kestrel_team
    provider: Stripe
    provider_invoice_id: in_1S8mQ2Kt5oPz4rN6
    provider_status: open
    billing_contact_name: Kestrel Print Co.
    billing_contact_email: hello@kestrelprint.example
    status: past_due
    currency: GBP
    payment_terms: due_upon_receipt
    line_items:
      - { description: Team plan, quantity: 1, unit_amount_minor: 4900, amount_minor: 4900 }
    subtotal_minor: 4900
    discount_minor: 0
    tax_minor: 0
    total_minor: 4900
    balance_minor: 4900
    collection_state: Automatic retries
    dunning_step: reminder_2
    last_reminder_at: '2026-09-24T09:00:00Z'
    aging_bucket_days: 27
    attempt_count: 3
    next_payment_attempt: '2026-10-01T10:00:00Z'
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0139
    memo: Team plan, Sep 3 to Oct 3; card declined three times
    issued_at: '2026-09-03T10:00:00Z'
    due_at: '2026-09-03T10:00:00Z'
    paid_at: null
    created_at: '2026-09-03T10:00:00Z'
    updated_at: '2026-09-24T09:00:00Z'
    last_event: payment_failed
    last_event_at: '2026-09-24T09:00:00Z'
  - invoice_id: inv_2026_0151
    invoice_number: INV-2026-0151
    subscription_id: sub_lindqvist_starter
    provider: Stripe
    provider_invoice_id: in_1SaP4dLq7uWe3hK2
    provider_status: paid
    billing_contact_name: Lindqvist Bakery
    billing_contact_email: finance@lindqvist.example
    status: paid
    currency: EUR
    payment_terms: due_upon_receipt
    line_items:
      - { description: Starter plan, quantity: 1, unit_amount_minor: 1900, amount_minor: 1900 }
    subtotal_minor: 1900
    discount_minor: 0
    tax_minor: 0
    total_minor: 1900
    balance_minor: 0
    attempt_count: 1
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0151
    memo: Starter plan, Sep 15 to Oct 15
    issued_at: '2026-09-15T08:00:00Z'
    due_at: '2026-09-15T08:00:00Z'
    paid_at: '2026-09-15T08:01:00Z'
    created_at: '2026-09-15T08:00:00Z'
    updated_at: '2026-09-15T08:01:00Z'
    last_event: payment_cleared
    last_event_at: '2026-09-15T08:01:00Z'
  - invoice_id: inv_2026_0133
    invoice_number: INV-2026-0133
    subscription_id: sub_lindqvist_starter
    provider: Stripe
    provider_invoice_id: in_1RzH6bJw3sXv2mE9
    provider_status: refunded
    billing_contact_name: Lindqvist Bakery
    billing_contact_email: finance@lindqvist.example
    status: refunded
    currency: EUR
    payment_terms: due_upon_receipt
    line_items:
      - { description: Starter plan, quantity: 1, unit_amount_minor: 1900, amount_minor: 1900 }
    subtotal_minor: 1900
    discount_minor: 0
    tax_minor: 0
    total_minor: 1900
    balance_minor: 0
    total_refunded_minor: 1900
    last_refund_at: '2026-08-19T11:30:00Z'
    refundable_until: '2026-09-15T08:00:00Z'
    notes: Duplicate of INV-2026-0132 for the same period; refunded in full.
    attempt_count: 1
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0133
    memo: Starter plan, Aug 15 to Sep 15 (charged twice)
    issued_at: '2026-08-16T08:00:00Z'
    due_at: '2026-08-16T08:00:00Z'
    paid_at: '2026-08-16T08:01:00Z'
    created_at: '2026-08-16T08:00:00Z'
    updated_at: '2026-08-19T11:30:00Z'
    last_event: payment_cleared
    last_event_at: '2026-08-16T08:01:00Z'
  - invoice_id: inv_2026_0149
    invoice_number: INV-2026-0149
    subscription_id: sub_summit_business
    provider: Stripe
    provider_invoice_id: in_1ScN9fTy6pRb1wL3
    provider_status: paid
    billing_contact_name: Summit Outfitters
    billing_contact_email: ap@summit.example
    status: paid
    currency: USD
    payment_terms: due_upon_receipt
    line_items:
      - { description: Business plan, quantity: 1, unit_amount_minor: 14900, amount_minor: 14900 }
    subtotal_minor: 14900
    discount_minor: 0
    tax_minor: 0
    total_minor: 14900
    balance_minor: 0
    attempt_count: 1
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0149
    memo: Business plan, Sep 7 to Oct 7
    issued_at: '2026-09-07T12:00:00Z'
    due_at: '2026-09-07T12:00:00Z'
    paid_at: '2026-09-07T12:01:00Z'
    created_at: '2026-09-07T12:00:00Z'
    updated_at: '2026-09-07T12:01:00Z'
    last_event: payment_cleared
    last_event_at: '2026-09-07T12:01:00Z'
  - invoice_id: inv_2026_0160
    invoice_number: INV-2026-0160
    subscription_id: sub_blueharbor_team
    provider: Stripe
    provider_invoice_id: in_1SmB3gUz8qNc5xP1
    provider_status: draft
    billing_contact_name: Blue Harbor Studio
    billing_contact_email: accounts@blueharbor.example
    status: draft
    currency: USD
    payment_terms: due_upon_receipt
    line_items:
      - { description: Team plan, quantity: 1, unit_amount_minor: 4900, amount_minor: 4900 }
    subtotal_minor: 4900
    discount_minor: 0
    tax_minor: 0
    total_minor: 4900
    balance_minor: 4900
    attempt_count: 0
    payment_source: card
    portal_url: https://pay.example/invoices/INV-2026-0160
    memo: First Team invoice; finalises when the trial ends on Oct 5
    issued_at: '2026-10-05T09:00:00Z'
    due_at: '2026-10-05T09:00:00Z'
    paid_at: null
    created_at: '2026-09-28T09:00:00Z'
    updated_at: '2026-09-28T09:00:00Z'
    last_event: created
    last_event_at: '2026-09-28T09:00:00Z'
```
