How to do an ME21N mass upload from Excel
PostNow.ai does an ME21N mass upload from Excel through BAPI_PO_CREATE1: each purchase order is one H row with D rows for its items, and the template fills the item, schedule-line and account-assignment structures and their X flags. Validate checks the file, Simulate runs the BAPI and rolls back, and Run writes each PO number back as a link to ME23N.
- The BAPI is the default route. SAP does not support batch input for ME21N (Note 217437), and the BAPI takes any number of items without a recording.
- Pilot before volume. Post one order, open it in ME23N, then run the rest. To prove after a change that PO postings still work, see SAP regression tests for purchase orders.
This page covers purchase orders only. For choosing a method across SAP objects, see SAP mass upload from Excel; for a first upload click by click, see how to upload data into SAP from Excel.
ME21N mass upload: BAPI_PO_CREATE1 or a recording
PostNow.ai can post a purchase order template in two ways: through BAPI_PO_CREATE1, or by replaying an ME21N recording. For purchase orders we start with the BAPI almost every time, and the table shows why.
| Route | Use it when | Where it breaks |
|---|---|---|
PostNow.ai, BAPI mode on BAPI_PO_CREATE1 | Standard, consumable and account-assigned POs with several items, from one sheet. Header/detail rows group the items into orders, and the X flags are filled for you. | Fields that exist only on a screen. Custom fields need EXTENSIONIN, which PostNow.ai lets you declare. |
| PostNow.ai, recording mode on ME21N | A simple, single-item order where you want the exact screens your buyers use | SAP does not support batch input for ME21N SAP Note 217437. Multi-item orders need a recording that filters the item overview to each item number, proven in Debug; the BAPI needs neither. |
Nothing writes into EKKO or EKPO directly. PostNow.ai's ABAP reads with SELECT only, and every order is created by the BAPI under your own SAP user, so your purchasing authorisations and release strategy apply as they would in ME21N. For the same question on other transactions, see BAPI vs BDC.
One template on BAPI_PO_CREATE1, run from Excel
A designer builds the template once against your live system. Buyers fill rows and run it, and each order comes back with SAP's answer beside it.
Header columns to POHEADER, item columns to POITEM, POSCHEDULE and POACCOUNT. The X flags are filled from the dictionary.
Validate the file, confirm vendors and materials exist in SAP, then Simulate every order with a rollback.
The BAPI runs under your SAP login. The order is committed only when SAP returns no E or A message.
The PO number or SAP's message goes beside each order. The number links to ME23N.
Header and item rows in one sheet: multi-item purchase orders from Excel
PostNow.ai builds multi-item purchase orders from header/detail rows. A marker column labels each row H or D. The H row carries the order header, and the D rows below it are that order's items. AutoMap H/D creates the marker and the columns for the fields you pick. One H row with four D rows becomes one BAPI_PO_CREATE1 call with four POITEM lines, so 30 H rows post 30 purchase orders, however many items sit under them.

- Header fields live on the H row only. Document type, vendor, purchasing organisation, purchasing group, company code, currency and document date go in
POHEADER. Don't repeat them on D rows and hope they agree. - Every D row carries its item number. Map
PO_ITEM(10, 20, 30) onPOITEM. PostNow.ai copies it into the schedule-line and account-assignment line built from the same D row, so you don't map the item number three times. Without that copy, SAP rejects the line with MEPO 085, "Check item number &1 in table &2". - Header-level tables can be read once. Partner functions (
POPARTNER) or header conditions (POCONDHEADER) are TABLES parameters, but they belong to the order rather than the item. Set them to Header scope in the mapping pane and they are read once from the H row. - One D row is one item with one schedule line. The template puts the delivery date and quantity of each D row into one
POSCHEDULEline for that item. If an item needs two delivery dates, that is a different template design. Don't add a second D row with the same item number. - Keep stock and account-assigned orders apart. One template for stock items, one for cost-centre or order items, so each sheet carries only columns that mean something for its rows.
PostNow.ai also has flat rows (every row an item, a column change starts a new order), but for purchase orders H/D is easier to check, because a buyer sees each order as a block. Our free ME21N purchase order template uses it.
BAPI_PO_CREATE1 parameters and the X structure pattern
PostNow.ai reads BAPI_PO_CREATE1's parameters from your own system, so you map against your release. These are the ones a PO upload uses.
| Parameter | What it carries | Excel side |
|---|---|---|
POHEADER / POHEADERX | Company code, document type, vendor, purchasing organisation and group, currency, document date | H row |
POITEM / POITEMX | Item number, material or short text, plant, storage location, quantity, order unit, net price, price unit, tax code, material group, account assignment category, requisition number and item | One D row per item |
POSCHEDULE / POSCHEDULEX | Item number, schedule line, delivery date, scheduled quantity | Same D row |
POACCOUNT / POACCOUNTX | Item number, sequential number (SERIAL_NO), G/L account, cost centre, order, WBS element, asset | Same D row, account-assigned items only |
POCOND / POCONDX, POCONDHEADER | Item and header conditions: condition type, rate, currency, change type | D row, or H row with Header scope |
EXTENSIONIN | Customer fields on header or item | Declared as extensions in the template |
TESTRUN, NO_PRICE_FROM_PO | Test indicator; "No adoption of price from last document" | Fixed values, if used |
EXPPURCHASEORDER, RETURN | The new PO number; SAP's messages | Written back to the row |
What the X structures do
Every data structure has a twin with the same field names and an X on the end. A value in POITEM-NET_PRICE only counts if POITEMX-NET_PRICE holds an X. A missing flag raises no error; the value just never takes effect. On SAP Community, the usual answer to "BAPI_PO_CREATE1 ignores my field" is "set the X field".
The key fields are the exception. In POITEMX, PO_ITEM carries the item number itself (10, not X), and a separate PO_ITEMX carries the flag. POSCHEDULEX and POACCOUNTX work the same way for the schedule line and the account-assignment sequence number.
PostNow.ai handles both kinds from the dictionary. When you tick a field, its one-character X twin is set to X. Key fields of the same length, such as PO_ITEM, are copied across at run time. Anything that doesn't fit either rule goes to Review X-pairs for you to decide. Nothing is guessed silently.
Account assignment in a PO upload: K, F, P and A
PostNow.ai sends the account assignment category in POITEM-ACCTASSCAT and the cost object in a POACCOUNT line built from the same D row. Which fields SAP then insists on is set per category in your system's purchasing Customizing, so treat the table as the usual pattern, not a rule.
| Category | Cost object | POACCOUNT fields usually needed |
|---|---|---|
| K | Cost centre | GL_ACCOUNT, COSTCENTER |
| F | Order | GL_ACCOUNT, ORDERID |
| P | Project | GL_ACCOUNT, WBS_ELEMENT |
| A | Asset | ASSET_NO (and sub-number where used) |
| blank | Stock item | No POACCOUNT line |
- Give
SERIAL_NOa value. Each account-assignment line needs a sequence number. For one assignment per item, a default value of 01 does it. - Pad the cost objects. Set leading zeros with a target length on cost centre and G/L account columns. A cost centre typed as 4120 in Excel is
0000004120in SAP. - The material can force a category. If a material is set up so it can't be ordered to stock, SAP answers ME 062, "Account assignment mandatory for material & (enter acc. ass. cat.)". The fix is in the data or the material, not a retry.
Split account assignment, such as one item spread 60/40 over two cost centres, needs a distribution indicator and two POACCOUNT lines for one item. That doesn't fit the one-D-row-one-line shape, so do those orders by hand or design and test a separate template.
Prices and conditions: why the net price in your file gets replaced
PostNow.ai posts the price exactly as you map it. Whether SAP keeps it is a pricing question, and it catches more PO uploads than any other.
When an item has an info record, a contract or a last purchase order, SAP's pricing can determine the price itself. SAP has a knowledge base article for exactly this symptom: "Net price entered in BAPI_PO_CREATE1 is ignored". It names POITEM-PO_PRICE among its keywords SAP KBA 2577898. That field's dictionary text is "Price Adoption: 1 = Gross, 2 = Net". It tells the BAPI how to treat NET_PRICE.
- Want SAP's price? Leave the price column empty and let the info record or contract supply it. You can then compare the price SAP chose against the source file in the check step below.
- Want the file's price? Map
NET_PRICE,PRICE_UNITandPO_PRICEwith their X flags, then Simulate one item that has an info record before you trust it at volume. Mind the price unit: 50 per 100 pieces is not 50 per piece, and SAP accepts both. - Surcharges and discounts go in
POCOND. Use one line per item and condition type, with the change type set. Header conditions such as freight on the whole order go inPOCONDHEADER, read once from the H row. NO_PRICE_FROM_POis narrower than it sounds. Its short text is "No adoption of price from last document". It is not a general "use my price" switch.
If the price is missing altogether, SAP answers 06 218, "Net price must be greater than 0". Don't put in 0.01 to get the order through. Find out why pricing found nothing for that vendor, material and plant. For pricing condition records themselves, the master data behind all this, see VK11 upload from Excel.
Why an ME21N BDC recording is hard to replay
PostNow.ai records any transaction through SHDB and replays it by CALL TRANSACTION. ME21N is the transaction where that approach is weakest, for reasons that are SAP's, not ours.
- SAP doesn't support it. ME21N is an Enjoy transaction, and SAP Note 217437 says batch input isn't supported for it. A recording that works today is relying on behaviour SAP doesn't promise to keep.
- The screen is built from controls. The item overview and the tabbed header and item details use the ABAP Control Framework. These controls need SAP GUI, which is why PostNow.ai runs every recording in an SAP GUI session on your PC. That makes a simple order possible, and multi-item orders take several Debug rounds, so the BAPI is the steadier route at volume.
- Item lines are where it breaks. A plain recording of a two-item order captures the cursor positions and grid rows of that one order. An order with seven items takes a different path, and the replay drifts. A recording made item by item, filtering the item overview to each item number, can be looped over the D rows, and PostNow.ai's designer flags leftover cursor rows and screens SAP skipped. Getting there takes several Debug rounds, which is why we put multi-item orders on
BAPI_PO_CREATE1. - Updates are synchronous. Recorded rows post with synchronous update and the BAPI path commits with wait, so on either route a PO number in the Run Log is already in EKKO. The BDC recording guide covers recordings in depth.
If a field your buyers need exists on the ME21N screen but not in BAPI_PO_CREATE1, check EXTENSIONIN with your developers before you fall back to a recording.
Worked example: 12 consumable items into 3 purchase orders
PostNow.ai runs this one with a single BAPI template on BAPI_PO_CREATE1, H/D rows, and account assignment K. Company code 1010, purchasing organisation 1010, purchasing group 001, document type NB, plant 1010, currency EUR. Vendors 100045 and 100046. Every item goes to cost centre 4120 on G/L account 400000.
Lay out the sheet
3 H rows (PO-A and PO-C for vendor 100045, PO-B for 100046) and 12 D rows below them: item 10 to 50 under PO-A, 10 to 40 under PO-B, 10 to 30 under PO-C. D rows carry material (TG-1001 style) or short text, quantity, unit, net price, delivery date, ACCTASSCAT K, G/L account and cost centre. SERIAL_NO is a fixed 01. Vendor, G/L and cost centre columns get leading zeros to 10 characters.
Validate
Validate flags 3 cells: two delivery dates pasted as text, and a category typed "Q", which the Restrict list (K, blank) rejects. Pre-Validation on the vendor and cost centre columns confirms both vendors and the cost centre exist.
Simulate
PO-A and PO-C come back clean. PO-B fails with 06 027, "Vendor & has not been created for purch. organization &". Vendor 100046 exists, so Pre-Validation passed, but it has no purchasing data for 1010, which an existence check can't see. PO-B waits for the vendor master team.
Pilot, then run
Run Scope covers PO-A's rows only. The PO number lands beside the H row. Click it, and ME23N shows five items, the K assignment on each, and the expected price. Then run the rest. PO-C posts. PO-B is left for later.
Retry only what failed
Two days later, purchasing data for 100046 exists. Set Start Row back to 2 and use Retry Failed. Only PO-B's rows have an ERROR Run Log, so only PO-B is sent.
Retry Failed scans from the current Start Row down. That is why it is reset to 2 after a pilot. If someone clicks Run on the whole range instead, PostNow.ai reads the Run Log first, finds PO numbers on the H rows of PO-A and PO-C, and offers Skip posted rows, Post again or Cancel. Skip leaves out each posted order as a whole block, header and items, so only PO-B is sent.
Checklist before a purchase order upload
PostNow.ai checks a PO file in layers: Validate, Pre-Validation, Simulate, pilot. This is the list we go through before a production run.
- One H row per intended PO. Count H rows against the number of orders the requester expects. A missing H row merges two orders.
- Item numbers unique within each order (10, 20, 30).
- Leading zeros and date formats set explicitly on vendor, G/L, cost centre and delivery date. In
BAPIMEPOSCHEDULE,DELIVERY_DATEis a 10-character field (data element EEIND), not a date-type field. Confirm the format your system accepts with Simulate. - Simulate green on every order. Simulate calls
BAPI_PO_CREATE1and thenBAPI_TRANSACTION_ROLLBACKinstead of a commit, so no PO is kept. - Release workload expected. Orders created by the BAPI are subject to release strategy determination just like ME21N orders (SAP KBA 1497235 covers cases where the strategy isn't found for both). Tell the approvers before 200 orders land in their queue.
- Approval in PostNow.ai, if your team uses one. If a portal policy covers the template, Run waits until someone other than the preparer approves that exact data.
BAPI_PO_CREATE1 errors: return messages and fixes
PostNow.ai writes SAP's RETURN messages into the Run Log beside the order. BAPI_PO_CREATE1 usually returns a summary plus the detail behind it, so read past the first line. If a message is still unclear, AI Review explains it from SAP's messages and the field structure, by default without your cell values.
| Message | What it means | Fix |
|---|---|---|
| 06 017 & created under the number & | Success: "Standard PO created under the number …" | Nothing. PostNow.ai writes the number back with $DOC_NO. |
| BAPI 001 No instance of object type PurchaseOrder has been created | A wrapper. The order was not created, and the real reason is in the other lines. | Read the messages below it in the Run Log |
| MEPO 000 Purchase order still contains faulty items / MEPO 002 PO header data still faulty | Summaries for the item or header level | Look for the item-level message (ME, 06) with the item number |
| MEPO 085 Check item number &1 in table &2 | A schedule, account or X line has no item number, or one that matches no POITEM line | Map PO_ITEM on POITEM. PostNow.ai copies it to the other lines of the same D row. |
| ME 083 Enter & & | A required field is empty. The variables name it, for example the G/L account or order unit. | Add the column, or set the X flag if the value was there |
| 06 027 Vendor & has not been created for purch. organization & | The vendor exists but has no purchasing data for that purchasing organisation | Vendor master team extends it, then Retry Failed |
| ME 046 Material & not maintained by Purchasing / ME 034 Plant & not created for material & | The material lacks the purchasing view, or the plant | Extend the material (MM01), then retry |
| 06 218 Net price must be greater than 0 | No price in the file and none found by pricing | Fix the info record or contract, or supply the price with PO_PRICE |
| 06 436 In case of account assignment, please enter acc. assignment data for item | ACCTASSCAT is set but no POACCOUNT line reached SAP | Map POACCOUNT, including SERIAL_NO and the X twin |
| "No master record exists for vendor" | Often the vendor went in without leading zeros | Leading zeros to 10 characters on the vendor column |
Message texts are SAP's short texts; your release may word some of them slightly differently. Message type (error or warning) can depend on your system's message settings.
Checking the result: ME23N, EKKO, EKPO and the release queue
PostNow.ai writes each PO number beside its H row, and clicking it opens ME23N for that order in display mode. That covers spot checks. For the whole load, check the tables.
| Check | Where | What to compare |
|---|---|---|
| Orders created | PostNow.ai Run Log, then EKKO by PO number | One number per H row; vendor, purchasing organisation, document type |
| Items | EKPO (one row per item) | Item count per order, material, plant, quantity, unit, net price, account assignment category |
| Delivery dates | EKET (schedule lines) | Delivery date and scheduled quantity per item |
| Account assignment | EKKN | G/L account and cost object per item |
| Prices that SAP determined | ME23N conditions tab; in S/4HANA the pricing result sits in PRCD_ELEMENTS rather than KONV | Price SAP used vs the price expected |
| Release status | ME23N header, release strategy tab | Which orders are waiting and for whom |
To check the whole load in one sheet instead of table by table, the SAP purchase order report in Excel lists the created POs with their items, schedule lines and PO history.
Keep the posted workbook: with the PO numbers in it, it is the record of what this run created.
What to plan for in an ME21N mass upload
PostNow.ai creates purchase orders through BAPI_PO_CREATE1, so SAP's own purchasing rules decide every result. Plan for these points.
- Post again means post again. Run offers to skip orders that already show a PO number, but choosing Post again creates new purchase orders for them.
- Correct created orders in SAP. Stop cancels the orders still to come; created POs stay in SAP. Change or delete them in ME22N, or with a
BAPI_PO_CHANGEtemplate. - Keep the posted workbook. PostNow.ai knows what it posted from the Run Log, so the workbook with its PO numbers is the duplicate guard. If the answer from SAP is lost mid-order, the row is marked UNKNOWN, and Retry Failed leaves it alone. Look the order up in SAP before you post that row again.
- Design a separate template for multi-line items. One D row gives one line per table; several schedule lines per item, or distributed account assignment, need their own design.
- Give service POs their own template. Service and limit items use
POSERVICESand related tables, not the item layout on this page. - Keep the PostNow.ai portal reachable for approved templates. The approval check runs against the portal; if the portal cannot be reached, the check lets the run through. SAP's release strategy still applies to every order.
Next in the chain: goods receipts in MIGO and invoices in MIRO. The whole procure-to-pay sequence is in SAP process automation, and the other MM objects in SAP MM mass upload. If your orders start as requisitions, see ME51N. For handing this template to buyers with roles and approvals, see Excel to SAP automation.
