Bulk invoice operations
Import invoices in bulk and export catalog-matched receiver data
Two endpoints handle invoices in bulk rather than one at a time: POST /v1/invoices/import for pushing many invoices into Ottimate, and GET /v1/invoices/receiver-export for pulling catalog-matched line data back out. Bulk approval is covered in Invoice approvals.
Importing invoices in bulk
POST /v1/invoices/import creates many invoices asynchronously. The request body is a bare JSON array of invoice objects — not an object wrapping an array:
Each object takes the same fields as POST /v1/invoices, and each carries its own ottimate_location_id — a single request can span several locations.
- Maximum 100 invoices per request
- Every invoice requires
ottimate_location_idand a uniqueupload_id - An empty array, or a body that is not an array, returns a
400 raw_imagesis not supported in bulk mode — useimage_urlsinstead
Validation is all-or-nothing; creation is not. Every invoice in the array is validated up front, and one invalid entry rejects the whole request with a 400 — nothing is created. Once validation passes the batch is queued, and individual invoices can still fail during processing. Poll the batch results to confirm what was actually created.
Response
The endpoint returns 202 Accepted immediately:
Poll GET /v1/batch/{id}/progress for status and GET /v1/batch/{id}/results for per-invoice outcomes.
Access errors are per-item
If your API user cannot access one of the locations in the array, the whole request is rejected with a 400. The body carries one entry per invoice you sent, positionally, so an empty object means that invoice passed validation:
Here the second invoice in the array referenced a location the API user cannot reach. Nothing was created.
Marking already-processed invoices on ingestion
Both POST /v1/invoices and POST /v1/invoices/import accept an optional, write-only status field. It exists for backfilling invoices that were already approved and paid — or already approved and exported — in your own system, so they do not re-enter Ottimate’s approval workflow.
Omit the field entirely for normal invoices — they will route through extraction, coding, and approval as usual.
Sending verified for an invoice you have already paid risks a double payment. verified leaves the invoice active and eligible for billpay and autopay, so Ottimate may pay it again. Use archived for anything already paid, and verified only for invoices that are approved in your system but still genuinely outstanding. If you are unsure which applies, omit the field.
This is not the same status you read back. The write-only ingestion status accepts only archived or verified. The status returned on an invoice is the derived lifecycle status described in Invoice lifecycle, and it cannot be set through the API.
Receiver export
GET /v1/invoices/receiver-export returns exported invoices together with their catalog-matched line items, in the shape a receiving or inventory system expects.
This endpoint is in beta.
The result set is deliberately narrow. An invoice appears only if:
- It is in the
exportedstate - Its vendor has item validation enabled
- It has at least one qualifying line after filtering — invoices left with zero lines are omitted entirely
Fringe catalog entries and lines that did not match the catalog are excluded from receiver_lines.
Filters
Response
An empty result set does not mean nothing was exported. Because unmatched lines and non-item-validated vendors are filtered out, an invoice can be exported and still never appear here. Use GET /v1/invoices?status=exported to see everything that was exported.

