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 with409 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.
"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 remainnull; 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 sendline_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 usingPOST /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.
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 withfinancially_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 includealert_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
Usemine=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, andGET /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.