Skip to main content

Create Purchase Invoice from Extraction

POST 

/api/purchase-invoices/ocr/:purchase_extraction_id/create-invoice

Accept the reviewed/edited extraction data (header + lines + cost lines) and create a PurchaseInvoice record, marking the extraction as 'confirmed'. The extraction must be in pending_review or duplicate_detected status (a duplicate-detected extraction is allowed because the user may confirm it is not actually a duplicate and proceed to create a new invoice).

The payload supports two kinds of line items:

  • lines — product line items, attached to PurchaseOrderLines on the target PO. Each may set purchase_order_line_id to bind to a specific PO line, or ignored: true to skip persisting (kept for audit but not invoiced).
  • cost_lines — non-product COST-classified financial lines (freight, duty, handling). These create FinancialLine records on the PurchaseInvoice keyed by a COST-classification financial_line_type_id. allocate_to_products is always true for OCR-created cost lines.

At least one of lines or cost_lines is required (lines is required_without:cost_lines).

Request body fields:

FieldTypeRequiredNotes
purchase_order_idintegeryesMust exist in purchase_orders.
invoice_numberstringyesMax 255 chars.
invoice_datedateyes
due_datedateno
linesarrayrequired_without:cost_linesProduct lines.
lines[].descriptionstringno
lines[].qtynumericyesNegative values are accepted (e.g. PO-level discount rows surfaced as standalone negative lines). The manager filters out ignored: true and match_status: discount_confirmation lines before persisting.
lines[].unit_pricenumericyesNegative values are accepted (e.g. PO-level discount rows surfaced as standalone negative lines). The manager filters out ignored: true and match_status: discount_confirmation lines before persisting.
lines[].purchase_order_line_idintegernoMust exist in purchase_order_lines.
lines[].ignoredbooleannoSkip persisting this line.
cost_linesarraynoNon-product COST FinancialLines.
cost_lines[].financial_line_type_idintegeryes (per cost line)Must exist in financial_line_types and be COST classification.
cost_lines[].descriptionstringnoMax 500 chars.
cost_lines[].quantitynumericyes (per cost line)Min 0.
cost_lines[].amountnumericyes (per cost line)Min 0. Per-line amount (not total).
remember_mappingsbooleannoWhen true, upserts (supplier_id, description) → financial_line_type_id mappings into supplier_description_mappings so future OCR imports auto-tag matching descriptions as cost lines (Tier 0 match).

Response 201:

{
"data": {
"purchase_invoice_id": 312,
"extraction_id": 7
},
"message": "Purchase invoice created from OCR extraction."
}

Response 422 — wrong status (e.g. confirmed or failed):

{ "message": "Only extractions pending review can be used to create an invoice." }

Response 422 — validation failure (no lines or cost lines):

{
"message": "The lines field is required when cost lines is not present.",
"errors": { "lines": ["The lines field is required when cost lines is not present."] }
}

Request

Responses

Successful response