| invoice_id | string, UUID | ✅ Yes | unique; defaultRaw: gen_random_uuid() | — | Public immutable identifier for the invoice. Exposed in all API responses; used in external references. |
| status | string (InvoiceStatusEnum) | ✅ Yes | default: draft; nativeEnumName: invoice_status_enum | draft, issued, paid, canceled | Lifecycle stage of the invoice. Managed by the document extraction and reconciliation pipeline. Do NOT extend — payment dimension is handled by payment_status. |
| payment_status | string (PaymentStatusEnum) | ✅ Yes | default: unknown; nativeEnumName: payment_status_enum; 🔒 written exclusively by the recompute service | unpaid, partial, paid, overpaid, unknown | Orthogonal payment dimension tracking how much of the invoice has been settled against matched bank transactions. Owned by the payment-recompute service; not user-writable through Hasura update permissions. |
| issue_date | Date (timestamp), nullable | ⚪ No | columnType: timestamp; @Enrichable | — | The date the invoice was formally issued, as stated on the document. Populated by the AI extraction pipeline. |
| due_date | Date (date), nullable | ⚪ No | columnType: date; @Enrichable | — | Payment deadline as stated on the invoice. Stored as a calendar date (no time component). |
| grand_total | number (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); @Enrichable | — | Total invoice amount in local_currency, inclusive of taxes. Surfaced via composite_total_amount_currency on the records page. |
| items_total | number (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); @Enrichable | — | Sum of all line-item amounts before taxes, in local_currency. Surfaced via composite_items_amount_currency. |
| tax_total | number (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); @Enrichable | — | Total tax amount in local_currency. Surfaced via composite_tax_amount_currency. |
| local_currency | string (CurrencyCodeEnum), nullable | ⚪ No | nativeEnumName: currency_code_enum; @Enrichable | ISO 4217 currency codes (EUR, USD, GBP, …) — full list in packages/shared/src/constants/currency-codes.ts | Currency in which the invoice was issued. grand_total, items_total, and tax_total are denominated in this currency. |
| invoice_number | string, nullable | ⚪ No | no explicit length cap; @Enrichable; partial unique index on (workspace_pk, invoice_number) WHERE deleted_at IS NULL AND invoice_number IS NOT NULL | — | Human-readable invoice reference number as printed on the document (e.g. INV-2026-00412). Used as a deduplication key during import within a workspace. |
| reference_number | string, nullable | ⚪ No | length: 100; @Enrichable | — | External reference or PO number annotated on the invoice by the issuer. Distinct from purchase_order_number (which is the buyer-side PO). |
| purchase_order_number | string, nullable | ⚪ No | length: 100 | — | Buyer-side purchase order number linked to this invoice. |
| document_type_code | string (DocumentTypeCodeEnum), nullable | ⚪ No | nativeEnumName: document_type_code_enum | UN/EDIFACT D.16A document type codes: 380 (COMMERCIAL_INVOICE), 381 (CREDIT_NOTE), 383 (DEBIT_NOTE), 384 (CORRECTED_INVOICE), 385 (CONSOLIDATED_INVOICE), 386 (PREPAYMENT_INVOICE), 325 (PROFORMA_INVOICE), 326 (PARTIAL_INVOICE), and many others — full list in apps/api/src/constants/document-type-code.const.ts | UN/EDIFACT D.16A document type code classifying the nature of the commercial document. Used to distinguish invoices from credit notes, purchase orders, remittance advices, utility bills, expense receipts, etc. |
| billing_context | string (BillingContextEnum), nullable | ⚪ No | nativeEnumName: billing_context_enum | subscription, recurring, periodic, installment, retainer, usage_based, consumption, metered, volume_based, overage, project, milestone, hourly, fixed_price, time_materials, one_time, event_based, commission, bonus, reimbursement, maintenance, support, consulting, training, professional_services, contract, license, rental, lease, franchise, adjustment, refund, credit, penalty, discount, deposit, advance_payment, escrow, insurance, tax, promotional, trial, freemium, setup, activation, other, mixed, unknown | Commercial context or billing model under which the invoice was raised. |
| description | string, nullable | ⚪ No | @Enrichable; display_type: long_text_area in overrides.yml | — | Free-text description of the goods or services billed, as extracted from the document. |
| terms | string, nullable | ⚪ No | length: 300; @Enrichable; display_type: long_text_area in overrides.yml | — | Payment terms as stated on the invoice (e.g. Net 30, early payment discount clauses). |
| accounting_currency | string (CurrencyCodeEnum), nullable | ⚪ No | nativeEnumName: currency_code_enum | ISO 4217 currency codes — same enum as local_currency | Workspace functional / reporting currency into which totals have been converted by the FX matching pipeline. Present when local_currency differs from the workspace accounting currency. |
| accounting_grand_total | string (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); stored as string to preserve precision | — | grand_total converted to accounting_currency via the linked exchange_rate. Written by the invoice FX matching service. |
| accounting_items_total | string (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); stored as string | — | items_total converted to accounting_currency. |
| accounting_tax_total | string (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); stored as string | — | tax_total converted to accounting_currency. |
| paid_amount | string (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); stored as string; 🔒 written by recompute service | — | Cumulative amount matched and allocated against this invoice from bank transactions, in local_currency. Written exclusively by the payment-recompute service. |
| balance_due | string (decimal 12,2), nullable | ⚪ No | columnType: decimal(12,2); stored as string; 🔒 written by recompute service | — | Remaining unpaid amount (grand_total minus paid_amount), in local_currency. Derived and written by the payment-recompute service. |
| last_payment_allocation_date | Date (timestamptz), nullable | ⚪ No | columnType: timestamptz; 🔒 written by recompute service | — | Timestamp of the most recent payment allocation event processed by the recompute service. |
| override_version | number (integer) | ✅ Yes | default: 0; 🔒 incremented by recompute service on every write; selectable but not user-writable via Hasura update permissions | — | Optimistic concurrency counter incremented by the payment-recompute service on each write. Used for observability and conflict detection; not a user-settable field. |
| shadow_from_receipt | boolean | ✅ Yes | default: false | true, false | True when this invoice row was synthesized from a payment_receipt document via the mapReceiptToShadowFlat (R1) pipeline rather than extracted from a real bill. Lets the UI distinguish promoted receipts from genuine outstanding invoices. |
| created_at | Date, 🔒 system | ✅ Yes | onCreate: () => new Date() | — | Timestamp when the invoice row was created. Set once on insert via MikroORM lifecycle hook. |
| updated_at | Date, 🔒 system | ⚪ No | onCreate + onUpdate: () => new Date() | — | Timestamp of the last modification. Automatically maintained by MikroORM lifecycle hooks. Declared optional in the entity; absent on rows that have never been updated after initial insert. |
| deleted_at | Date, nullable | ⚪ No | nullable; all active-row queries must filter deleted_at IS NULL | — | Soft-delete timestamp. Non-null means the invoice is logically deleted and must not appear in active listings. Partial indexes on workspace + created_at and workspace + source_connector include WHERE deleted_at IS NULL. |