Purchase orders and vendor invoices via API
Purchase orders and vendor invoices are standalone supporting documents β inbound POs from your customers and generic (non-freight) vendor AP invoices. You upload a PDF through the same presigned-URL flow as other documents; Upwell parses it asynchronously and creates the structured record you can then list, search, and patch. This page covers the end-to-end workflow. For the complete request and response schemas, see the API Reference entries under Purchase Orders and Vendor Invoices.These are not freight carrier invoices (
carrier_invoices) and not customer AR invoices (invoices). For those flows see Submitting carrier invoices via API and Managing customer invoices (AR).Prerequisites
- An API key on every request (
Authorization: YOUR_API_KEYβ aBearerprefix also works). See Authentication. - A PDF of the purchase order or vendor invoice. Standalone supporting-doc uploads are PDF-only, but a single upload can hold more than one document of the same type stacked together β Upwell detects the boundaries and splits it into separate records (see Combined-PDF uploads below).
The flow
1
Request a presigned upload URL
POST /api/rest/generate-upload-presigned-url with associationType of PURCHASE_ORDER or VENDOR_INVOICE. Omit associationId β the parsed record is created from the upload, not attached to an existing entity.2
PUT the PDF bytes
Upload the raw file to
uploadUrl. Content-Type must match the mimeType you declared (application/pdf).3
Poll until the parsed record appears
GET /api/rest/documents/{documentId}/purchase-orders or .../vendor-invoices returns an empty list until parsing finishes (typically within a couple of minutes). Bound the poll β see Step 3.4
Read, search, or update
Use the list / get / search / patch endpoints below once the record exists.
Step 1 β Request a presigned URL
Standalone supporting-doc ingestion uses a dedicatedassociationType and no associationId:
Pass
sourceSystem + sourceSystemId so retries are safe: re-requesting an already-uploaded document returns 400 DOCUMENT_ALREADY_UPLOADED; re-requesting one whose upload never completed returns a fresh uploadUrl for the same document.
input to VENDOR_INVOICE. Read uploadUrl and documentId from generateUploadPresignedUrl β not from the response root.
Step 2 β Upload the PDF
UPLOAD_CONTENT_REJECTED and is never parsed β check GET /api/rest/documents/{documentId}. Rejection is terminal for that sourceSystem + sourceSystemId; re-upload with a new sourceSystemId.
Step 3 β Poll for the parsed record
GET /api/rest/documents/{documentId} shows status: "UPLOAD_CONTENT_REJECTED" (invalid PDF; terminal for that sourceSystem + sourceSystemId).
Combined-PDF uploads
If your upload actually contains several purchase orders or vendor invoices stacked into one PDF, Upwell detects the boundaries and splits it into one child document per document found, rather than trying to parse the whole stack as a single record. The container document (the one you uploaded) moves through its own status sequence while this happens, whichGET /api/rest/documents/{documentId} on the original documentId will show:
You donβt need to look up the individual child documents yourself:
GET /api/rest/documents/{documentId}/purchase-orders and .../vendor-invoices β the same polling endpoint from Step 3 β already match records from split children of that container as well as the container itself, so keep polling the original documentId you got from the presigned-URL response. Expect to see more than one record in the list once splitting has produced multiple documents; a PROCESSING_FAILED container may still have some purchase-order/vendor-invoice records from the children that succeeded before one of their siblings failed permanently.
Find by your source ids
If you storedsourceSystem + sourceSystemId at presign time, you can look up the parsed record without the document id:
POST /api/rest/vendor-invoices/search for vendor invoices β same body shape.
Step 4 β List, get, and update
List endpoints accept an optional
limit query parameter. Get-one responses include line items and party addresses; vendor invoices also include the matched purchase order when one exists.
Patch body shape
Updates use{ "input": { ...fields to set... } } with the recordβs camelCase field names. Amounts are integer cents. System-managed columns (ids, tenant/document linkage, party references, match state) are not updatable and are rejected.
Related
- Integration patterns β presigned upload, integer cents,
sourceSystempairs - How documents flow through Upwell
- API Reference: Purchase Orders, Vendor Invoices

