Skip to content

Invoices and documents

POST /api/documents takes any file Spend can read: PDF, image (including HEIC and multi-page TIFF), EML or MSG email, zip, X12 810, cXML or UBL.

{ "filename": "INV-4471.pdf", "contentBase64": "JVBERi0xLjcK...", "markings": ["CONFIDENTIAL"] }

markings is optional: labels from the channel (a sensitivity label, a dedicated mailbox) that may put the document in a class your policy keeps from the AI provider. The caller needs the invoice.enter permission.

The response lists each document found (a zip or an email can hold several):

{
"documents": [
{ "id": "doc_...", "filename": "INV-4471.pdf", "status": "extracted", "docType": "invoice",
"issues": [], "invoiceId": "inv_...", "invoiceStatus": "pending_approval", "error": null }
]
}

status is extracted or needs_review; issues lists fields below the confidence threshold. GET /api/documents/:id returns the extraction with per-field evidence; GET /api/documents/:id/original returns the file as received, base64-encoded.

POST /api/invoices creates an invoice from structured data (amounts in dollars):

{
"number": "4471", "supplierName": "Acme Pipe Supply", "poNumber": "PO-27-00012",
"invoiceDate": "2026-10-20", "dueDate": "2026-11-19", "terms": "Net 30",
"lines": [{ "lineNo": 1, "description": "8 in. ductile iron pipe", "quantity": 40, "unitPrice": 52.5, "amount": 2100, "poLineNo": 1 }],
"tax": 199.5, "freight": 0, "total": 2299.5
}

It runs through matching, coding, tax and duplicate checks exactly like a captured invoice.

  • GET /api/invoices lists invoices with the list parameters. Filters: status, channel, exception, due and approver=me.
  • GET /api/invoices/stats returns the headline counts for the AP queue.
  • GET /api/invoices/:id returns one invoice with its lines, match result, exceptions and approval.
POST /api/invoices/:id/exceptions/:code/resolve
{ "how": "accepted", "note": "Price increase agreed by the buyer on 10/14", "lineNo": 2 }

how is accepted, corrected, overridden or rejected. POST /api/invoices/:id/hold and /release (with invoice.resolve) stop and restart an invoice.

GET /api/invoices/:id/coding returns the suggested coding with the bills it learned from; POST the same path applies it or your own coding.