SAP Business One loads purchase orders through the Data Transfer Workbench, and DTW expects two CSV files: a header file and a lines file, linked by a RecordKey column you have to build yourself. PurchaseOrders handles the part DTW cannot do. It reads the supplier purchase order in whatever layout it arrived in and returns the order number, supplier, dates, item codes, quantities and prices as clean CSV or Excel you can shape into the oPurchaseOrders templates. Upload a real purchase order below.
Submit your purchase orders
Drop documents here, or click to file
Up to 50 files per batch
Uploading...
B1 has three separate ways to create a purchase order from data you already hold. Every one of them starts from structured columns, and none of them can open the PDF sitting in your inbox.
A purchase order is a marketing document, so the oPurchaseOrders object splits into a header file and a lines file. The two are joined by a RecordKey value you invent, and LineNum restarts at 0 for every RecordKey. Get either column wrong and DTW either rejects the file or silently attaches lines to the wrong order.
OPOR carries both. DocEntry is the internal key that joins the header to POR1, and DocNum is the human-readable order number your buyers quote. New B1 teams map the supplier PO number onto the wrong one and then cannot find their orders again.
POR1 carries BaseEntry and BaseLine, which is how a purchase order line points back to the purchase request line it came from. Load a PO without those and the order posts fine but the flow from PRQ1 is broken, so the request stays open forever.
All of that mechanics assumes the data is already in columns. Supplier order confirmations and customer POs arrive as PDFs, scans and phone photos, so somebody retypes each one before the import file exists at all.
PurchaseOrders is a document data capture layer. It reads a purchase order and returns structured fields you can map into a DTW template or a Service Layer payload. It does not connect to SAP Business One, does not run DTW, and does not write to OPOR, POR1 or any other B1 table. The load stays yours to run.
The AI pulls the order number, supplier, order date, delivery date, currency and buyer reference, which is the same set the Documents file needs for CardCode, DocDate, DocDueDate and DocNum.
Each line comes back with the item code, description, quantity, unit of measure, unit price and discount, so the Document_Lines file can be populated from a single extraction instead of a screen-by-screen retype.
Supplier documents usually print the supplier part number, not yours. That value is what you reconcile against OITM before the import, and it is the most common reason an otherwise clean file fails on item code.
DTW takes comma-delimited CSV. The Service Layer takes JSON. The same extraction feeds either route, so a scripted pipeline and a one-off migration use the same data.
B1 follows one naming convention throughout: the header table starts with O, and the row table shares the document abbreviation with a numeric suffix. Learning the pairs below is most of the work of writing a B1 purchasing query.
| Table | What it holds | Key notes |
|---|---|---|
| OPOR | Purchase order headers | DocEntry is the internal key, DocNum is the visible order number |
| POR1 | Purchase order rows | Joined to OPOR on DocEntry, LineNum starts at 0 |
| OPRQ and PRQ1 | Purchase request header and rows | The document that normally precedes a PO |
| OPDN and PDN1 | Goods receipt PO header and rows | Receipt against the order |
| OPCH and PCH1 | A/P invoice header and rows | The final step in the purchasing flow |
| OCRD | Business partner master | CardCode identifies the supplier |
| OITM | Item master | ItemCode has to exist before the line will post |
| OITW | Item warehouse rows | Controls which warehouses an item can be ordered into |
The extraction removes the typing. The import stays yours to run inside B1, with your own templates and your own authorizations.
Drag in the PDF, scan or photo exactly as it arrived. There is no template to configure first and no layout to teach the system.
Tip: Multi-page orders and mixed suppliers in one batch are fine.
Check the order number, supplier, dates and the line table before you export. Correcting a quantity here takes seconds, while finding it in a DTW error log after a partial load takes far longer.
Tip: Check the unit of measure, because B1 tracks purchasing and inventory units separately.
Take the CSV or Excel output, put the header fields in the Documents file and the line fields in the Document_Lines file, then add the RecordKey column that ties them together and number LineNum from 0 within each order.
Tip: Run DTW in simulation mode first so validation errors surface before anything posts.
Purchase order headers are stored in OPOR and the order rows in POR1. The two join on DocEntry, which is the internal document key. OPOR also carries DocNum, the order number users actually see, and POR1 carries LineNum, a row counter that starts at 0 for each document and increments by one.
Use the Data Transfer Workbench with the oPurchaseOrders object. Because a purchase order has a header and rows, DTW expects two comma-delimited CSV files, one for the document and one for the document lines. You link them with a RecordKey column, run the import in simulation first, then post it once the validation is clean.
RecordKey is the column that ties a line row to its header row inside one import run. You assign the same RecordKey value to a header record and to every line that belongs to it. It is not stored in B1 afterwards, it exists only so DTW knows which lines build which document.
LineNum starts at 0 for the first line of each document and increases by one for every following line. The counter restarts at 0 with each new RecordKey, not across the whole file. This mirrors how POR1 stores LineNum in the database, so the values you import are the values you will query later.
The Data Transfer Workbench ships with a template for every object it supports, installed under the Templates folder in the DTW program directory, typically C:\Program Files (x86)\SAP\Data Transfer Workbench\Templates. A separate data preparation examples folder holds filled-in sample files, including one for oPurchaseOrders, which is the fastest way to see the expected column order.
Yes. The Service Layer exposes purchase orders as an OData collection, so a POST to /b1s/v1/PurchaseOrders with CardCode, the document dates and a DocumentLines array containing ItemCode, Quantity and Price creates the order. A 201 response means it posted. This is usually the better route for an ongoing feed, while DTW suits a one-time load.
Because the link between documents lives in the row table, not the header. POR1 carries BaseEntry and BaseLine, which point at the DocEntry and LineNum of the source row in PRQ1. If those columns are empty, B1 posts a standalone purchase order and the original request stays open with nothing consuming it.
Almost always master data rather than file format. The CardCode has to exist in OCRD and be a supplier, the ItemCode has to exist in OITM, and the item needs a row in OITW for the warehouse on the line. Posting periods, blocked business partners and a closed period on DocDate are the next most common causes.
No. PurchaseOrders reads purchase order documents and returns the data as CSV, Excel, JSON or API output. It does not connect to B1, does not run the Data Transfer Workbench, and does not write to OPOR, POR1 or any other table. You run the import yourself, which keeps your authorizations and audit trail intact.
S/4HANA and ECC purchase order loads.
The Business Central configuration package route.
Sage 100 and its Visual Integrator import.
Turn a PO into plain CSV columns.
The general ERP load pattern.
Capture the full line table.
Same fields as JSON for a scripted feed.