IngestionLoad
Push invoices INTO Nuntiq from a connector. Two flows:
- Drop a file into the standard pipeline — same path as email intake. Nuntiq runs OCR, picks a template, extracts fields.
- Build a structured invoice with fields + lines + addresses, then attach the original PDF, then submit. Skips OCR entirely.
For the worked-example tutorial, see Patterns → Invoice ingestion.
Import
from lib.objects.ingestion import IngestionLoad
ingest_pdf / ingest_files — Pattern 1
load = IngestionLoad(context)
result = load.ingest_pdf(
filename='invoice.pdf',
content=pdf_bytes,
receiving_inbox='invoices@acme.apreceiving.com', # all kwargs optional
supplier_code='SUP-100',
company_code='EMEA',
)
print(result.source_document_id) # int
print(result.files_uploaded) # int (>=1; ZIPs expand)
For multiple files in one call:
result = load.ingest_files(
files=[
('invoice.pdf', pdf_bytes, None),
('attachment.docx', docx_bytes, None),
],
receiving_inbox='invoices@acme.apreceiving.com',
)
| Arg | Required | Notes |
|---|---|---|
filename / files[*][0] | yes | Used by Nuntiq for display + MIME inference |
content / files[*][1] | yes | Raw bytes |
content_type | no | Inferred from filename when omitted |
receiving_inbox | no | Controls which template Nuntiq picks |
supplier_code | no | Routing hint; skips supplier AI match |
company_code | no | Routing hint; skips company AI match |
Max 20 files per request. Max 50MB per file. ZIP files are unzipped server-side.
SourceDocumentResult
| Field | Type | Notes |
|---|---|---|
source_document_id | int | The new source document's id |
files_uploaded | int | Number of files accepted (>=1; ZIPs expand) |
pdf_files_queued | int | Number of PDFs queued for processing |
upload_session_id | str (UUID) | Groups this upload — useful for log searches |
new_invoice() — Pattern 2 (structured + PDF)
load = IngestionLoad(context)
inv = load.new_invoice(
workflow='payment_portal', # default
receiving_inbox='invoices@acme.apreceiving.com',
)
# Header — set whatever you have. All fields optional, all template-driven.
inv.header.invoice_number = 'INV-2026-0042'
inv.header.invoice_date = '2026-05-17' # ISO date
inv.header.due_date = '2026-06-16'
inv.header.gross_amount = 1815.00
inv.header.tax_amount = 315.00
inv.header.net_amount = 1500.00
inv.header.currency_code = 'EUR'
inv.header.supplier_name = 'Acme Corp'
inv.header.order_number_1 = 'PO-2026-0042'
inv.header.custom_text_1 = 'cost-center-42'
# Lines
line = inv.new_line()
line.product_code_1 = 'WIDGET-A'
line.product_name = 'Office Widget'
line.quantity = 100
line.unit_price = 12.50
line.unit_of_measure = 'EA'
line.net_amount = 1250.00
line.tax_amount = 262.50
line.gross_amount = 1512.50
# Addresses — type must be REMITTO | SUPPLIER | SHIPTO | BILLTO
addr = inv.new_address('SUPPLIER')
addr.street = 'Herengracht 500'
addr.city = 'Amsterdam'
addr.country = 'NL'
# Optional: taxes / charges / discounts
tax = inv.new_tax()
tax.tax_name = 'VAT'
tax.tax_rate = 21
tax.tax_amount = 315.00
# Attachments
inv.attach_image(filename='invoice.pdf', content=pdf_bytes) # exactly one
inv.attach_file(filename='delivery_note.pdf', content=dn_bytes) # 0..N
# Send
result = inv.submit()
print(result.invoice_token, result.invoice_status)
Workflow choice
workflow | Resulting status | Use when |
|---|---|---|
payment_portal (default) | 100 (Processed) | Upstream data is fully verified — skip enrichment |
basic_enrichment | 10 | Run light enrichment, no AI |
full_enrichment | 1 | Run the full AI-match + validation pipeline |
Attachment rules
attach_image()— at most one per invoice. Calling it twice raisesValueError. This is the PDF the AP team will view; multiple "primary" PDFs would confuse the viewer.attach_file()— 0..N supporting documents (delivery notes, supporting POs, etc.). Visible to the AP team but not the primary view.- If you don't pass any IMAGE, the invoice has no viewable PDF — AP team sees structured fields only. Usually a poor UX.
InvoiceImportResult
| Field | Type | Notes |
|---|---|---|
invoice_token | str (UUID) | Pass to InvoiceLoad.get_by_token() |
invoice_id | int | Internal numeric id |
source_document_id | int | Underlying source document |
workflow | str | Workflow used |
invoice_status | int | Final numeric status (e.g. 100 = Processed) |
source_document_status | int | Final source-document status |
template_id | int | Template Nuntiq used |
template_type | str | 'global' or 'customer' |
attachments_linked | int | Count of attachments tied to the invoice |
receiving_inbox | str | Inbox used for template lookup |
Error handling
ingest_pdf / ingest_files and submit() raise ApiError on transport
or HTTP failure. See ApiClient → Error handling.
Local validation (workflow value, address_type value, max-1-image) raises
ValueError before the HTTP call — so you find out at code-write time,
not after a network round trip.
Idempotency
Neither endpoint has an idempotency-key concept today. If you call
ingest_pdf or inv.submit() twice with the same data, Nuntiq creates
two records. Track which upstream records you've already submitted in your
own state (typically via delta_run) and don't
re-submit.
What's next
- Patterns → Invoice ingestion — worked-example tutorials for both flows.
- InvoiceLoad — once ingested, this is how you read the resulting invoice or claim it for downstream push.