Skip to main content
An Invoice is a published invoice or credit note. Import progress, unusable extraction, duplicates, and non-invoice files are represented by imports rather than invoice lifecycle states.

Duplicate invoices

Structured creation and document imports use the same business identity: supplier, recipient, invoice number, issue date, category, currency, and normalized total including VAT, within your organization. Invoice numbers are trimmed, totals are compared to two decimals, and credit-note amounts use their canonical negative sign. An existing active invoice blocks another structured creation with 409 Conflict. An import completes with outcome: "duplicate" and the existing invoice ID, without publishing another invoice or charging another invoice-processing usage event. The duplicate PDF header check also avoids unnecessary line extraction. The rule applies even when source files differ and no idempotency key is supplied. Missing identity fields are never guessed; an incomplete import can still rely on the primary-file checksum guard. Identity changes on active invoices and restoring deleted invoices use this guard too. A deleted invoice does not block creation by business identity; importing its exact original file still returns the existing invoice through the checksum guard.

Financial validity

financially_valid and financial_errors are computed, read-only arithmetic results. They do not establish extraction accuracy, agreement compliance, or human approval. A valid invoice has an empty financial error list; detailed line errors appear with the paginated line items.
Checks compare each line’s quantity, price, discount, and surcharge with its line total, then compare summed lines with the invoice’s stated totals, including VAT. Rates are fractions: "0.25" means 25%. The rounding tolerance is inclusive at 1 invoice currency unit; a difference greater than 1 fails. Currency, a total, and at least one line are necessary, and the total’s sign must agree with the invoice category. A successful import can therefore produce an invoice with financially_valid: false. Correct the financial values when appropriate, or retain the source’s values and errors for investigation.

Values, parties, and source information

Amounts remain decimal strings. Unknown amounts and dates remain null; missing payment evidence produces payment.status: "unknown". Financial validity does not imply payment. Supplier and recipient objects contain invoice snapshots alongside canonical party IDs. These captured names, organization numbers, and addresses describe the invoice; they are not current party master records. Changing a canonical party ID changes the relationship while preserving the captured snapshot. origin describes structured creation, documents, integrations, or an unknown legacy origin. Original financial values and source documents remain available after editing. Extraction confidence is projected as extraction_confidence: high, mid, low, or unknown. Both successful header and line assessments from the creating import are required; the lower level wins. Structured/XML creation and unavailable history remain unknown. Manual confirmation and arithmetic do not change extraction confidence. Legacy mutable confidence flags are not used.

Editing an invoice

PATCH merges supplied fields with the current invoice. If you send line_items, it is the complete resulting line collection: retain existing IDs, omit lines to remove them, and omit the ID on a new line. Line IDs must belong to that invoice. Supplied delivery replaces the whole delivery object; null clears it. Changing amounts, quantities, prices, rates, currency/conversion, category, or line membership validates the entire resulting invoice. A failure rolls back every supplied change. Equivalent numeric representations and unchanged values are no-ops. Metadata edits preserve existing financial errors. Saving does not approve an invoice or refresh compliance analysis. Existing findings remain results of their previous analysis. Relevant invoice changes make those assessments outdated until a new check runs. Delete soft-deletes an invoice; restore makes it active again. Both operations are repeatable. A restore can conflict with another active invoice’s business identity, in which case the original stays deleted. Use the quickstart for requests and the generated endpoint pages for complete create/update schemas, invoice details, line items, documents, filters, and metrics.

Managing invoice documents

Upload bytes using POST /v1/documents/upload and its signed PUT URL, then attach the returned Document ID. All three commands require Write access and work on published invoices, including soft-deleted invoices. Attachments must be 100 bytes to 25 MiB each. There is no attachment-count or combined-size cap, for these commands or new REST imports. Import primaries retain the 50 MiB limit.
Attach returns 201, or 200 with the current relationship when already attached. New attachments are non-primary even on invoices without documents. Selecting a primary returns 200 and keeps positions unchanged. Unlink returns 204, including repeated requests after authorization. Promote another document before unlinking the primary. An unreleased claim membership blocks removal, including a cancelled claim; remove the alerts from that claim first. Unlinking retains the Document and downloadable bytes, original import sources, and prior findings. Changes update the invoice evidence fingerprint without changing financial values or running extraction, matching, or checks. Repeating an unchanged command preserves evidence and timestamps. Missing or changed uploaded bytes return 409 source_unavailable; invalid sizes return 400. Relationship conflicts return 409 conflict; missing or foreign resources return 404.

Importing PDF and XML documents

PDF imports extract the primary invoice’s header, then its lines. Attachments provide supporting context; a different invoice in an attachment does not replace the primary document. XML imports support PEPPOL BIS Billing 3.0 UBL Invoice and CreditNote documents. These are parsed deterministically, without model calls or generated descriptions. The primary XML supplies the business values; attachments are inspected and retained without overriding those values. Other primary XML formats fail with an actionable unsupported-format message. There is no model fallback for unsupported or structurally unusable XML. The parser preserves stated totals, decimal precision, identifiers, and source-language text. Missing required values fail extraction; unknown optional values stay null. Explicit document allowances and charges become signed adjustment lines. Constructs that cannot be represented faithfully by the invoice contract, such as line adjustments outside the supported rate range, fail with an explanation. XML parsing does not establish full Peppol conformance. Structurally usable XML with inconsistent financial values still produces an invoice with financially_valid: false, using the same financial checks as PDF imports. Invoice totals represent the total including VAT, which may differ from an outstanding amount after earlier payments. Import detail includes bounded evidence for inspection, header, lines, or xml stages. Each summary describes the latest saved result for that stage. A new result replaces the previous one; this is not a history of extraction attempts. Workflow runs retain their execution outcomes. XML evidence has null extraction confidence. Retry may reuse compatible successful stages; source versions must still be available and unchanged. Evidence and model usage remain separate from the published Invoice.

Alert coverage

Invoice list and detail include alert_summary, with check coverage and retained alert counts. Use alert_checked, alert_checkable, and has_open_alerts to filter invoices. These observations are separate from financial validity and approval. See Alerts and check coverage.

My records and teams

Use mine=true or explicit team_ids to filter by shared team rules. See My records and teams for matching rules, empty results, errors, and pagination.

Selection, ordering, and exports

Lists, metrics, and GET /v1/invoices/export share the same selection. Use join_operator=and|or (default AND) for a flat group of column filters; each inclusive date range remains one AND condition. Organization, deletion, search, agreement_ids, and mine/team scope always stay outside that group. Query selections accept at most 50 comma-separated entries, normalized and deduplicated. Omission adds no filter; empty or invalid entries return 400. Supplier, recipient, category, currency, confidence, and check-status selections have corresponding *_operator=is|is_not controls (supplier_operator, recipient_operator, category_operator, currency_operator, confidence_operator, check_status_operator). Nullable party/currency values use literal null. Excluding NOK includes unknown currency unless you also exclude null. Sort by supplier or recipient to use current canonical names across the full selection. Responses include supplier_name and recipient_name; snapshots remain separate. Nulls sort last and invoice IDs break ties. Default ordering remains created_at desc; use sort=issued_date&direction=desc for an invoice-date list. Search still matches invoice number/title. Use financially_valid, confidence_levels=high,mid,low,unknown, has_recorded_match, has_open_alerts, and check_statuses independently. Status values are not_checkable, checking, not_checked, completed, and incomplete. Recorded relationship counts describe an invoice’s linked credit notes or a credit note’s matched invoices; a match does not prove financial resolution. alert_summary.is_fully_credited is true only when one completed, nondeleted credit note uniquely targets the invoice and offsets its total including VAT within ±1 currency unit in the same currency. Both documents must be completed and nondeleted with nonzero canonical amounts. Partial notes are not summed, and shared notes do not qualify. Any linked completed, nondeleted credit note blocks checks, including partial and shared matches. Retained links to deleted, unfinished, or reclassified documents do not block checks. has_credit_note_match continues to report the relationship independently. alert_scope=selected_agreements requires agreement_ids and restricts coverage/counts to currently matched selected agreements. Default invoice scope evaluates overall coverage. Responses identify scope explicitly in alert_summary.scope.type (metrics: alert_scope.type), with value invoice or selected_agreements. Each scope object also includes agreement_ids: null for overall coverage or the normalized requested selection for selected scope. A check completed for A can give completed coverage in A’s view while missing B makes overall coverage incomplete. No findings is distinct from completed current coverage. Detail also exposes stored payment terms, invoice-wide notes and additional properties. Paginated lines preserve separate line notes, additional properties and allowance/charge evidence. Null means unavailable; empty collections stay empty. GET /v1/invoices/imports?limit=1 includes has_ingestion alongside data and next_cursor for retained Imports, invoice rows or invoice-category Documents, including legacy ingestion. Use this organization-wide signal when an empty invoice list needs an onboarding decision. It is independent of Import status filters and pagination; normal invoice lists do not run this query. CSV export accepts granularity=invoice|invoice-items (default invoice), all selection filters, and no pagination/sort parameters. It exports every selected invoice or stored line in UUID order using bounded live batches. Values use exact decimal strings, blank nulls, JSON arrays, formula-safe text, UTF-8 BOM and CRLF. Empty results contain column headers. Changes during traversal can affect later rows; it is not a snapshot. HTTP 200 alone does not establish completion: interrupted streams fail, and retry starts a fresh download. No resumable download exists. Generated clients should request parseAs: 'stream' with an AbortSignal and forward the body to a writable destination without Blob buffering.