Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt

Use this file to discover all available pages before exploring further.

Invoice is the core billing document entity in Well, representing receivable and payable documents (commercial invoices, credit notes, purchase orders, receipts, and related document types) extracted from uploaded files or ingested via connector syncs. It links two Company parties (issuer and receiver) within a Workspace, carries multi-currency financial totals with FX normalization, and tracks both a lifecycle status (draft → issued → paid → canceled) and an orthogonal payment dimension (payment_status) owned exclusively by the recompute service. Key associations include the source Document, line-item InvoiceItems, matched bank transactions via InvoiceTransaction pivot rows, payment instruments via InvoicePaymentMeans, and the originating WorkspaceConnector for provenance.
NamingValue
ObjectInvoice
Resource type (JSON:API type)invoice
Collection / records rootinvoices
REST base/v1/invoices
Entity classInvoice

API operations

OperationMethod & pathStatus
ListGET /v1/invoices✅ Implemented
RetrieveGET /v1/invoices/{id}✅ Implemented
CreatePOST /v1/invoices🟡 Planned
UpdatePATCH /v1/invoices/{id}✅ Implemented
DeleteDELETE /v1/invoices/{id}✅ Implemented

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
invoice_idstring, UUID✅ Yesunique; defaultRaw: gen_random_uuid()Public immutable identifier for the invoice. Exposed in all API responses; used in external references.
statusstring (InvoiceStatusEnum)✅ Yesdefault: draft; nativeEnumName: invoice_status_enumdraft, issued, paid, canceledLifecycle stage of the invoice. Managed by the document extraction and reconciliation pipeline. Do NOT extend — payment dimension is handled by payment_status.
payment_statusstring (PaymentStatusEnum)✅ Yesdefault: unknown; nativeEnumName: payment_status_enum; 🔒 written exclusively by the recompute serviceunpaid, partial, paid, overpaid, unknownOrthogonal 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_dateDate (timestamp), nullable⚪ NocolumnType: timestamp; @EnrichableThe date the invoice was formally issued, as stated on the document. Populated by the AI extraction pipeline.
due_dateDate (date), nullable⚪ NocolumnType: date; @EnrichablePayment deadline as stated on the invoice. Stored as a calendar date (no time component).
grand_totalnumber (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); @EnrichableTotal invoice amount in local_currency, inclusive of taxes. Surfaced via composite_total_amount_currency on the records page.
items_totalnumber (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); @EnrichableSum of all line-item amounts before taxes, in local_currency. Surfaced via composite_items_amount_currency.
tax_totalnumber (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); @EnrichableTotal tax amount in local_currency. Surfaced via composite_tax_amount_currency.
local_currencystring (CurrencyCodeEnum), nullable⚪ NonativeEnumName: currency_code_enum; @EnrichableISO 4217 currency codes (EUR, USD, GBP, …) — full list in packages/shared/src/constants/currency-codes.tsCurrency in which the invoice was issued. grand_total, items_total, and tax_total are denominated in this currency.
invoice_numberstring, nullable⚪ Nono explicit length cap; @Enrichable; partial unique index on (workspace_pk, invoice_number) WHERE deleted_at IS NULL AND invoice_number IS NOT NULLHuman-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_numberstring, nullable⚪ Nolength: 100; @EnrichableExternal reference or PO number annotated on the invoice by the issuer. Distinct from purchase_order_number (which is the buyer-side PO).
purchase_order_numberstring, nullable⚪ Nolength: 100Buyer-side purchase order number linked to this invoice.
document_type_codestring (DocumentTypeCodeEnum), nullable⚪ NonativeEnumName: document_type_code_enumUN/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.tsUN/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_contextstring (BillingContextEnum), nullable⚪ NonativeEnumName: billing_context_enumsubscription, 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, unknownCommercial context or billing model under which the invoice was raised.
descriptionstring, nullable⚪ No@Enrichable; display_type: long_text_area in overrides.ymlFree-text description of the goods or services billed, as extracted from the document.
termsstring, nullable⚪ Nolength: 300; @Enrichable; display_type: long_text_area in overrides.ymlPayment terms as stated on the invoice (e.g. Net 30, early payment discount clauses).
accounting_currencystring (CurrencyCodeEnum), nullable⚪ NonativeEnumName: currency_code_enumISO 4217 currency codes — same enum as local_currencyWorkspace 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_totalstring (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); stored as string to preserve precisiongrand_total converted to accounting_currency via the linked exchange_rate. Written by the invoice FX matching service.
accounting_items_totalstring (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); stored as stringitems_total converted to accounting_currency.
accounting_tax_totalstring (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); stored as stringtax_total converted to accounting_currency.
paid_amountstring (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); stored as string; 🔒 written by recompute serviceCumulative amount matched and allocated against this invoice from bank transactions, in local_currency. Written exclusively by the payment-recompute service.
balance_duestring (decimal 12,2), nullable⚪ NocolumnType: decimal(12,2); stored as string; 🔒 written by recompute serviceRemaining unpaid amount (grand_total minus paid_amount), in local_currency. Derived and written by the payment-recompute service.
last_payment_allocation_dateDate (timestamptz), nullable⚪ NocolumnType: timestamptz; 🔒 written by recompute serviceTimestamp of the most recent payment allocation event processed by the recompute service.
override_versionnumber (integer)✅ Yesdefault: 0; 🔒 incremented by recompute service on every write; selectable but not user-writable via Hasura update permissionsOptimistic concurrency counter incremented by the payment-recompute service on each write. Used for observability and conflict detection; not a user-settable field.
shadow_from_receiptboolean✅ Yesdefault: falsetrue, falseTrue 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_atDate, 🔒 system✅ YesonCreate: () => new Date()Timestamp when the invoice row was created. Set once on insert via MikroORM lifecycle hook.
updated_atDate, 🔒 system⚪ NoonCreate + 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_atDate, nullable⚪ Nonullable; all active-row queries must filter deleted_at IS NULLSoft-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.

Relationships

NameTypeRequiredDescription
issuerto-one (company)⚪ No (nullable)The Company that issued (sent) this invoice — typically the vendor or service provider. Index: idx_invoices_issuer. Used as a hot-path FK rewrite target during company-merge operations.
receiverto-one (company)⚪ No (nullable)The Company that received (was billed by) this invoice — typically the workspace’s own company for payables, or the customer for receivables. Index: idx_invoices_receiver. Also a hot-path FK rewrite target during company-merge.
documentto-one (document)⚪ No (nullable)The source Document from which this invoice was extracted (contains the original file, filename, and organisation/partner slugs). Indexed jointly with deleted_at via idx_invoices_document_deleted.
workspaceto-one (workspace)⚪ No (nullable)Tenant boundary. Every active invoice belongs to exactly one Workspace. Partial indexes for active-row listing and source-connector listing both scope to workspace_pk.
source_workspace_connectorto-one (workspace_connector)⚪ No (nullable)The WorkspaceConnector instance that ingested this invoice, when it was created via a connector sync. Null for manually uploaded or email-extracted invoices. Partial index idx_invoices_workspace_source_connector_active covers (workspace_pk, source_workspace_connector_pk) WHERE deleted_at IS NULL.
exchange_rateto-one (exchange_rate)⚪ No (nullable)FK-normalised ExchangeRate row used for multi-currency conversion. Carries rate, source_currency, target_currency, rate_date, and source. Used by the composite_fx_rate cell renderer and by accounting_* total computation.
subscriptionto-one (subscription)⚪ No (nullable)Optional link to a Subscription record when the invoice was generated from a recurring subscription context.
invoice_itemsto-many (invoice_item)Line items (InvoiceItem) belonging to this invoice. Contains per-line quantity, unit price, description, and tax rates. Owned by the invoice — cascade-deleted when the invoice is hard-deleted.
invoice_transactionsto-many (invoice_transaction)Pivot rows (InvoiceTransaction) linking this invoice to matched bank transactions. Written by the reconciliation / payment-recompute service. The existence and amounts of these rows drive paid_amount and balance_due.
payment_meansto-many (invoice_payment_means)Payment instrument links (InvoicePaymentMeans) associating bank account / payment method information stated on the invoice (e.g. IBAN to pay to).
invoice_workspace_connectorsto-many (invoice_workspace_connector)Connector provenance pivot rows (InvoiceWorkspaceConnector) recording which WorkspaceConnector instances have touched or are aware of this invoice. Used for deduplication and cross-connector identity resolution.

System-computed

  • invoice_id is generated automatically at insert by Postgres via defaultRaw: gen_random_uuid(). It is immutable after creation.
  • created_at is set once on INSERT via MikroORM onCreate: () => new Date() lifecycle hook.
  • updated_at is set on both INSERT and UPDATE via onCreate + onUpdate: () => new Date() lifecycle hooks. It is declared optional in the entity (updated_at?: Date) and may be absent on rows that have never been modified after creation.
  • deleted_at is null on creation and is set to a Date value by soft-delete logic. All active-row queries must predicate on deleted_at IS NULL. No hard delete should be issued directly.
  • payment_status (and paid_amount, balance_due, last_payment_allocation_date, override_version) are owned exclusively by the payment-recompute service. Application code and API clients must treat these as read-only. override_version is an optimistic concurrency counter incremented on every recompute write.
  • shadow_from_receipt defaults to false. It is set to true only by the mapReceiptToShadowFlat (R1) pipeline when synthesizing an invoice row from a payment_receipt document.
  • accounting_grand_total, accounting_items_total, accounting_tax_total, and accounting_currency are written by the invoice FX matching service (fx-rate.service.ts + invoice.service.ts) when the invoice local_currency differs from the workspace accounting currency.
  • source_workspace_connector (sourceWorkspaceConnector) is set at creation time when the invoice is ingested through a connector sync; it remains null for manually uploaded or email-extracted invoices.
  • Fields decorated with @Enrichable (issue_date, grand_total, local_currency, reference_number, terms, items_total, tax_total, description, invoice_number, due_date) are eligible for AI enrichment via the enrichment pipeline workers.
  • Partial index idx_invoices_workspace_invoice_number_active enforces uniqueness of (workspace_pk, invoice_number) among non-deleted rows where invoice_number IS NOT NULL, enabling efficient deduplication on import.
  • Partial index idx_invoices_workspace_source_connector_active on (workspace_pk, source_workspace_connector_pk) WHERE deleted_at IS NULL supports efficient tenant + connector listing queries.
  • Partial index idx_invoices_workspace_created_active on (workspace_pk, created_at DESC) WHERE deleted_at IS NULL mirrors the records-page default sort order to avoid full-table scans.

Example

{
  "data": {
    "type": "invoice",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "attributes": {
      "invoice_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "issued",
      "payment_status": "partial",
      "issue_date": "2026-04-15T00:00:00.000Z",
      "due_date": "2026-05-15",
      "grand_total": "12450.00",
      "items_total": "10375.00",
      "tax_total": "2075.00",
      "local_currency": "EUR",
      "invoice_number": "INV-2026-00412",
      "reference_number": "PO-8821-ACME",
      "purchase_order_number": "PO-8821",
      "document_type_code": "380",
      "billing_context": "subscription",
      "description": "Annual SaaS platform licence — Enterprise tier",
      "terms": "Net 30. Late payments subject to 1.5 % monthly interest.",
      "accounting_currency": "USD",
      "accounting_grand_total": "13489.35",
      "accounting_items_total": "11241.00",
      "accounting_tax_total": "2248.35",
      "paid_amount": "5000.00",
      "balance_due": "7450.00",
      "last_payment_allocation_date": "2026-05-01T14:32:00.000Z",
      "override_version": 3,
      "shadow_from_receipt": false,
      "created_at": "2026-04-16T09:17:42.000Z",
      "updated_at": "2026-05-01T14:32:01.000Z",
      "deleted_at": null
    },
    "relationships": {
      "issuer": {
        "data": { "type": "company", "id": "a1b2c3d4-0001-4000-8000-111111111111" }
      },
      "receiver": {
        "data": { "type": "company", "id": "a1b2c3d4-0002-4000-8000-222222222222" }
      },
      "document": {
        "data": { "type": "document", "id": "d0c00000-0000-4000-8000-999999999999" }
      },
      "workspace": {
        "data": { "type": "workspace", "id": "w0000000-0000-4000-8000-000000000001" }
      },
      "source_workspace_connector": {
        "data": { "type": "workspace_connector", "id": "c0000000-0000-4000-8000-000000000001" }
      },
      "exchange_rate": {
        "data": { "type": "exchange_rate", "id": "e0000000-0000-4000-8000-000000000001" }
      },
      "subscription": {
        "data": null
      },
      "invoice_items": {
        "data": [
          { "type": "invoice_item", "id": "b1000000-0000-4000-8000-000000000001" }
        ]
      },
      "invoice_transactions": {
        "data": [
          { "type": "invoice_transaction", "id": "t2000000-0000-4000-8000-000000000001" }
        ]
      },
      "payment_means": {
        "data": [
          { "type": "invoice_payment_means", "id": "pm000000-0000-4000-8000-000000000001" }
        ]
      },
      "invoice_workspace_connectors": {
        "data": []
      }
    }
  }
}
Source: apps/api/src/database/entities/Invoice.ts · domain: financial-graph · tier: Main