How SAP MIRO mass invoice posting works
MIRO in SAP is the logistics invoice verification transaction: it posts a supplier invoice against a purchase order and, where the order item is set for goods-receipt-based invoice verification, against a specific goods receipt. PostNow.ai does SAP MIRO mass invoice posting from Excel through BAPI_INCOMINGINVOICE_CREATE, one header row per invoice and one detail row per PO item. Validate checks the sheet, Simulate lets SAP check every invoice and rolls it back, and Run writes each invoice document number back to its row. SAP applies the same tolerances, tax calculation and payment blocks as in MIRO.
- A blocked invoice has posted. A variance above tolerance blocks the invoice for payment; it does not fail it. Release it in MRBR, never post it again.
- Check duplicates before the run. SAP KBA 1859210 describes that logistics invoice verification does not run its duplicate check for invoices created through BAPI, EDI or API, so compare supplier references with SAP first.
This page covers one job: posting supplier invoices that refer to a purchase order, in bulk, from Excel. Invoices with no purchase order belong in FB60 mass upload. How the price and quantity match is designed is covered in SAP invoice matching, and the wider payables process in SAP accounts payable automation.
How PostNow.ai posts MIRO invoices from Excel
PostNow.ai treats MIRO mass upload as a template: a designer builds it once against your SAP system and publishes it, and AP clerks run their own invoice files through it, each under their own SAP login on their own computer. When invoices arrive as PDFs, OCR reads them before the MIRO posting; how that capture works is explained in SAP invoice OCR.
- Start from the template or the BAPI. Download the free MIRO supplier invoice template, whose columns are already mapped to
BAPI_INCOMINGINVOICE_CREATE, or search for the BAPI by name in the add-in. Typing "MIRO" into Find with AI suggests the same BAPI. If your team already has an invoice sheet, Mapping AI matches its column headers to the BAPI fields; it reads the headers only, never the amounts. - Group the header and the lines. A marker column turns one
Hrow (the invoice header: company code, dates, supplier reference, gross amount) and itsDrows (one per PO item) into one invoice. A grouping key such as Invoice Ref keeps each invoice's rows together. - Validate the sheet. Validate checks every cell offline: required fields, type, length, date format, decimals and allowed values, such as an allow-list of tax codes. Checks that need SAP, such as whether a PO item or goods receipt exists, happen in Simulate.
- Simulate. PostNow.ai calls the BAPI for every invoice and then
BAPI_TRANSACTION_ROLLBACKinstead of a commit, so SAP's own messages (balance, PO item, goods receipt reference, closed period) appear per invoice and nothing posts. - Run. For each invoice PostNow.ai calls the BAPI and commits with
BAPI_TRANSACTION_COMMITonly when SAP returned no error; otherwise it rolls back. The H row gets "Invoice number posted successfully" by default, with the SAP user, time and system. If an approval policy covers the template, Run waits until an approver releases that exact data. - Check the blocks, then re-run only what failed. The Run Log tells you the invoice exists; whether it is blocked for payment is read in the Blocked Invoices report of the PostNow.ai Report Library. A second Run on the same sheet first lists the rows that already posted, with Skip posted rows, Post again or Cancel. Retry Failed re-posts only rows marked ERROR.

BAPI_INCOMINGINVOICE_CREATE: what goes in each structure
PostNow.ai posts MIRO invoices through BAPI_INCOMINGINVOICE_CREATE ("Invoice Verification: Post Incoming Invoice"). Each Excel column maps to one field in one of its structures:
| Structure | One per | Fields a MIRO upload usually fills |
|---|---|---|
HEADERDATA | Invoice | INVOICE_IND (X = invoice, blank = credit memo), COMP_CODE, DOC_TYPE, DOC_DATE, PSTNG_DATE, REF_DOC_NO (the supplier's invoice number), GROSS_AMOUNT, CURRENCY, CALC_TAX_IND, PMNTTRMS, BLINE_DATE, PMNT_BLOCK, DEL_COSTS, DIFF_INV |
ITEMDATA | PO item invoiced | INVOICE_DOC_ITEM, PO_NUMBER, PO_ITEM, REF_DOC / REF_DOC_YEAR / REF_DOC_IT (the goods receipt), QUANTITY, PO_UNIT, ITEM_AMOUNT, TAX_CODE, SHEET_NO (service entry sheet), FINAL_INV, DE_CRE_IND (subsequent debit/credit) |
GLACCOUNTDATA | Direct G/L line | A cost on the same invoice that is not on the PO: GL_ACCOUNT, ITEM_AMOUNT, DB_CR_IND, COSTCENTER, TAX_CODE |
TAXDATA | Tax code | TAX_CODE, TAX_AMOUNT, when you pass the supplier's tax instead of letting SAP calculate it |
WITHTAXDATA | Withholding tax type | WI_TAX_TYPE, WI_TAX_CODE, base and amount |
RETURN | Message | SAP's messages; any E or A means the invoice was not posted |
| Exports | Invoice | INVOICEDOCNUMBER and FISCALYEAR: the new invoice document, which PostNow.ai writes back to the H row |
Two details trip up first-time builds. The goods receipt item field is REF_DOC_IT, not REF_DOC_ITEM. And the BAPI does not save on its own: the caller has to commit, which PostNow.ai does after a clean RETURN.
BAPI_INCOMINGINVOICE_CREATE is SAP's interface for the same posting, which is why PostNow.ai's MIRO template, including the free one, uses it. The wider choice between the two methods is covered in BAPI vs BDC in SAP.GR-based invoice verification: when the file must name the goods receipt
GR-based invoice verification means each invoice item is matched to one specific goods receipt, not just to the PO item. In a PostNow.ai MIRO template that decides whether the D rows need the three goods receipt columns: material document, year and item.
The switch sits on the purchase order item (EKPO-WEBRE, "GR-Bsd IV"), and it can default from the supplier master. When it is set, the goods receipt must be posted before the invoice, and each invoice line names the receipt it pays (SAP Help). That is the right setting when one PO item is delivered in several parts, because each partial receipt is invoiced on its own.
- Fill the receipt only where the flag is set. SAP's supplier invoice API rejects a goods receipt reference on a PO item without GR-based IV, with the message "Only fill fields 'ReferenceDocument, -FiscalYear, -Item' … if GR-based IV is active" (KBA 3537312). Build the BAPI template the same way: fill
REF_DOC,REF_DOC_YEARandREF_DOC_ITfor flagged items, leave them blank for the rest, and confirm on the first Simulate. - Take the receipt numbers from SAP, not from the supplier. The supplier's delivery note is not the material document. The GR/IR Reconciliation report in the PostNow.ai Report Library lists each PO item's history with the goods receipt documents (
EKBE) and the GR-Based IV flag in one sheet, which is where the D-row references come from. - No receipt yet means no invoice line. Hold those invoices back until receiving posts; the PO side is covered in MIGO goods receipt upload.
Invoice tolerances and payment blocks: a blocked invoice has already posted
When an invoice differs from the PO or the goods receipt by more than the tolerance limits, SAP still posts it and blocks it for payment. In PostNow.ai that row shows a document number like any other, so the Run Log answers "did it post?" and the Blocked Invoices report answers "can it be paid?".
SAP's rules, per its invoice verification course (SAP Learning): within tolerance, the invoice posts with no message and no block. Above the upper limit, SAP issues a message, the invoice can still be posted, and SAP blocks it for payment automatically. The block covers the whole invoice, even if only one item has the variance, and the invoice must be released in a separate step before it can be paid. SAP marks the block with payment block R in the vendor line of the accounting document (SAP Help).
| Tolerance key (OMR6) | Variance it limits | What it usually means in a bulk file |
|---|---|---|
PP | Price variance against the PO net price | The supplier billed a new price, or the PO price is stale |
DQ, DW | Quantity variance; DW when the received quantity is zero | Receiving has not posted yet, or the supplier billed more than arrived |
ST | Date variance: amount × days before the planned delivery date | The invoice is entered well before the agreed delivery date |
KW, PS | Condition value; price against an estimated PO price | Freight or surcharge conditions, or estimated prices on the PO |
AN, AP | Amount of an item without or with order reference | One line whose amount is above the review limit your company set per item |
BD | Small differences in the invoice balance | Rounding; SAP posts the difference automatically within the limit |
The limits are set per company code in OMR6 (Materials Management → Logistics Invoice Verification → Invoice Block → Set Tolerance Limits). Read your own limits there before a backlog run; do not copy numbers from another system.
Reading the blocks after a run
The Blocked Invoices report reads the invoice header (RBKP) with its payment block ZLSPR and the item block reasons for price, quantity and date (RSEG-SPGRP, SPGRM, SPGRT). Filter it to the company code and posting date of the run to get the posted-but-blocked invoices with the reason per item, ready to hand to buyers. Operators can run it, and on the first run it is worth comparing its list with MRBR for the same selection.
Release blocked invoices with MRBR
PostNow.ai posts the invoices; releasing the blocked ones stays in SAP, in transaction MRBR, after the business decision is made. The Blocked Invoices report from the run tells you which documents to look at.
- Automatic release works for invoices blocked due to variances, once the blocking reasons no longer apply: for example after the missing goods receipt has posted (quantity) or the PO price has been changed or a subsequent credit has arrived (price).
- Manual release lets AP select the invoices and delete the blocking reasons or release whole invoices after the variance is accepted.
- A manual header block stops automatic release. SAP's course notes that a manual payment block at header level keeps an invoice from being released automatically, even when every item's variance has cleared (SAP Learning). If your file fills
PMNT_BLOCK, plan a manual release for those invoices. MRBR reports the leftovers with messageM8 659, "& invoices were released, & still contain a manual block".
Duplicate invoice check in SAP: what a bulk upload must add
PostNow.ai stops the same sheet from posting twice with its already-posted check, and the Invoice Receipts (MIRO) 360 report lets AP compare a new file with the supplier references already in SAP. Both matter, because SAP's own duplicate check is built for invoices entered on screen.
In MIRO, SAP compares a new invoice with existing ones on supplier, currency, company code, gross amount, reference document number and invoice date. The supplier needs the Chk double inv. flag in its accounting data, Customizing (Logistics Invoice Verification → Incoming Invoice → Set Check for Duplicate Invoices) can drop company code, reference or invoice date from the comparison, and the check runs only for invoices that carry a reference; credit memos and subsequent debits or credits are not checked (SAP Help). The messages are M8 462 "Check if invoice already entered as logistics inv. doc. number & &" and M8 108 "Check if invoice already entered under accounting doc. no. & &".
For interfaces the picture is different. SAP KBA 1859210, "BAPI/EDI/API: Duplicate Invoice Check", states that logistics invoice verification does not check for duplicate invoices created through BAPI, EDI or API, and KBA 2036775 describes how the check can be enabled for such automatic processes (both on SAP for Me). Ask your MM team which applies in your system, and plan for no check until they confirm.
- Check the file against SAP. Run Invoice Receipts (MIRO) 360 for the suppliers in the file and the last months; it returns each invoice's supplier, reference (
XBLNR), gross amount, invoice date and payment block. ACOUNTIFSon supplier and reference in Excel flags every row that already exists. - Check the file against itself. Two copies of one supplier invoice in the same file are both absent from SAP until the first one posts.
- Normalise before you compare, but post the supplier's real reference. "INV-0447" and "inv 0447" are one invoice. Blanking the reference to get past the warning takes that invoice out of the check, so a later copy of it will not be caught either.
- Re-run from the same workbook. A second Run on the same sheet offers Skip posted rows before anything is sent. A copied file with the same invoices has no Run Log, so only the SAP-side comparison above protects it.
Tax codes, gross amount and "Balance not zero"
In a PostNow.ai MIRO template the header carries the gross amount and each D row carries a net amount and a tax code, so the arithmetic has to work before SAP will post. Two settings decide which arithmetic applies.
| Setup | What the file sends | The rule |
|---|---|---|
SAP calculates tax (CALC_TAX_IND = X) | Net ITEM_AMOUNT and TAX_CODE per line, GROSS_AMOUNT on the header | Sum of net lines + tax SAP calculates = gross amount |
The supplier's tax is passed (TAXDATA) | Net lines plus one TAXDATA line per tax code with TAX_AMOUNT | Sum of net lines + passed tax = gross amount |
When the sums disagree, the BAPI returns M8 534 "Balance not zero" or M8 186 "Balance is not equal to zero" (KBA 3310518). The usual causes in a bulk file: the gross amount repeated on every D row and summed, a tax code missing on one line, a credit memo built with negative amounts (send it with INVOICE_IND blank and positive amounts), and rounding when the supplier rounds tax per line and SAP per code. Simulate shows the message on the first affected invoice, before anything posts.
Unplanned delivery costs in MIRO
Unplanned delivery costs are freight or handling charges on the invoice that the PO did not plan. In BAPI_INCOMINGINVOICE_CREATE they go in the header field DEL_COSTS, with their own tax code in DEL_COSTS_TAXC; the free PostNow.ai template has an Unplanned Delivery Costs column for it. Where the amount lands is configuration (Logistics Invoice Verification → Incoming Invoice → Configure How Unplanned Delivery Costs Are Posted): either spread over the invoice items, or posted to a separate G/L account, without debiting stock or the account assignment (SAP Help). Remember to include them in the gross amount.
Worked example: 40 supplier invoices at month-end in company code 1010
PostNow.ai handles this with one published MIRO template and one run. AP in company code 1010 has 40 PO-based invoices from 12 suppliers to post on 30.10.2026, 96 lines in all, currency EUR. One invoice from supplier 100045 looks like this in the sheet:
| Row | Invoice Ref | Header fields | Line fields |
|---|---|---|---|
| H | IV-0007 | INVOICE_IND X, company code 1010, invoice date 20261028, posting date 20261030, reference INV-0447, gross 1,190.00 EUR, calculate tax X | |
| D | IV-0007 | Item 00001, PO 4500001872 item 00010, GR 5000012345 / 2026 / 0001, 100 EA, 600.00, tax code V1 | |
| D | IV-0007 | Item 00002, PO 4500001872 item 00020, GR 5000012345 / 2026 / 0002, 50 EA, 400.00, tax code V1 |
Tax code V1 carries 19% input tax in this company code, so 1,000.00 net + 190.00 tax = 1,190.00 gross.
- Duplicates. The operator runs Invoice Receipts (MIRO) 360 for the 12 suppliers and the last six months. A
COUNTIFSon supplier and reference finds two invoices already posted in September; they come out of the file. 38 invoices remain. - Validate. Three cells are flagged: a tax code outside the allow-list, a posting date typed as 30/10/2026, and a blank PO item. All three are fixed in the sheet.
- Simulate. 35 invoices pass. Two return
M8 534because the gross amount was copied onto their D rows and summed by a formula; one rejects a goods receipt reference on a PO item without GR-based IV. All three are corrected and pass a second Simulate. - Run. All 38 post. Each H row now holds its invoice document number, from
5105600411to5105600448, with user, time and system. - Blocks. The Blocked Invoices report for company code 1010 and posting date 30.10.2026 lists four invoices. Three carry a price block on PO
4500002210, where the supplier billed a new price list; the buyer confirms the new price, and AP releases those three manually in MRBR. One carries a quantity block because 20 of 120 units have not been received; once receiving posts them, MRBR releases it automatically.
Nothing was posted twice, and the four blocked invoices stayed out of payment until someone accepted the variance or the goods arrived.
MIRO or FB60: which one for a supplier invoice
Use MIRO, and in PostNow.ai the BAPI_INCOMINGINVOICE_CREATE template, whenever a purchase order exists. Use FB60 only for invoices that never had one.
| Question | MIRO (logistics invoice verification) | FB60 (FI vendor invoice) |
|---|---|---|
| Basis | Purchase order item, and the goods receipt where GR-based IV is set | No purchase order; the G/L account and cost object come from the invoice |
| Matching and tolerances | Price, quantity and date checked against the PO and receipt; variances above tolerance block payment | None against a PO; any review happens before posting, for example by parking the invoice and releasing it |
| GR/IR clearing account | Cleared against the goods receipt | Not touched |
| BAPI PostNow.ai uses | BAPI_INCOMINGINVOICE_CREATE | BAPI_ACC_DOCUMENT_POST |
| Reversal | MR8M | FB08 |
Posting a PO invoice through FB60 records the liability but leaves the PO open for invoicing and the goods receipt uncleared in GR/IR. Non-PO invoices are covered in FB60 mass upload.
Reverse a MIRO invoice with MR8M, one at a time or in bulk
PostNow.ai reverses invoices in bulk with a second template on BAPI_INCOMINGINVOICE_CANCEL, the BAPI behind MR8M: one row per invoice document with its fiscal year, a reversal reason and, if needed, a posting date. Its exports return the reversal document number and year.
- Reverse, don't delete. MR8M posts a reversal document; the original invoice and the reversal both stay visible for audit.
- Pick the reversal reason deliberately. The reason controls the reversal's posting date and period. Use the reasons your FI team has configured.
- Cleared invoices must be reset first. If the vendor line has already been cleared, for example by a payment run, MR8M stops with
F5 802"Document already contains cleared items - reversal not possible" (KBA 2445866). Reset the clearing first. - Check the first reversal in MIR4 before the rest of the file runs.
MIRO upload errors and how to fix them
PostNow.ai writes SAP's message to each failed invoice's row, so the fix starts from the message text. These are the ones a bulk MIRO run meets most:
| Message | What it means | Fix |
|---|---|---|
M8 534 Balance not zero / M8 186 Balance is not equal to zero | Gross amount ≠ net lines + tax (+ unplanned delivery costs) | Recalculate the gross per invoice; check every D row has a tax code and the gross is not repeated on D rows |
| "Only fill fields 'ReferenceDocument …' if GR-based IV is active" (API wording) | A goods receipt reference was sent for a PO item without GR-based IV | Clear the GR columns for that item, or have purchasing set GR-based IV on the PO before receipt |
M8 462 / M8 108 Check if invoice already entered… | Where the duplicate check runs, SAP found an invoice with the same supplier, reference, date and amount | Look up the named document; if it is the same invoice, take the row out |
F5 802 Document already contains cleared items | MR8M cannot reverse an invoice whose vendor line is cleared | Reset the clearing, then reverse |
M8 659 & invoices were released, & still contain a manual block | MRBR released the variance blocks but a manual block remains | Release the manual payment block in MRBR with the manual-block selection |
| Run Log: UNKNOWN (PostNow.ai) | SAP's answer was lost after the invoice was sent, so it may have posted | Look the reference up in MIR4 or the Invoice Receipts (MIRO) 360 report before posting the row again; Retry Failed leaves UNKNOWN rows alone |
Checklist before a MIRO mass upload
PostNow.ai checks formats and allowed values and keeps operators on the published template; this list covers the decisions that stay with AP and purchasing.
- Every invoice refers to a purchase order; non-PO invoices are in a separate FB60 file.
- Goods receipts are posted for every GR-based item, and the D rows carry their material document, year and item.
- The file has been compared with SAP on supplier and reference, and with itself.
- Each H row carries the supplier's real invoice number in the reference column.
- Gross amounts equal net lines plus tax plus unplanned delivery costs, per invoice.
- Tax codes are on every line, or the supplier's tax is passed per code in
TAXDATA. - The posting period is open for the posting date in the file.
- Your tolerance limits in
OMR6are known, and an owner is named for price and quantity blocks. - Simulate has run clean on the whole file, or on a sample of each supplier.
- Treasury has seen the due-date profile: old invoice dates and baseline dates can make a backlog due on the day it posts.
What to plan for in a MIRO mass upload
PostNow.ai posts through SAP's invoice verification BAPI, so SAP's own matching, tax and blocking rules decide every result.
- Run SAP's checks in Simulate. Validate checks formats, lengths and allowed values in Excel; balance, PO and goods receipt checks start when SAP sees the invoice in Simulate.
- Plan your own duplicate check. Compare the file with SAP's posted references before the run, as described above, until your MM team confirms the interface check is enabled.
- Hand blocks to owners the same day. The Blocked Invoices report gives the list; buyers, receiving and AP each take their reason.
- Keep re-runs in the same workbook. The re-post check reads this sheet's Run Log, and UNKNOWN rows are checked in SAP before anyone posts them again.
- 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.
Making a template like this repeatable for a team (designers who build, operators who only run, a published template in the central library) is covered in Excel to SAP automation.
MIRO mass upload on S/4HANA
PostNow.ai uses the same template on S/4HANA: MIRO, MRBR, MR8M and BAPI_INCOMINGINVOICE_CREATE are all there, and SAP's knowledge base articles on this BAPI (for example KBA 3310518) are filed for both SAP ERP and SAP S/4HANA.
- Suppliers are Business Partners. The invoice still names the supplier through the PO; supplier data such as the duplicate-check flag and payment terms is maintained in transaction
BPin the supplier role. - SAP also offers an OData API.
API_SUPPLIERINVOICE_PROCESS_SRVcreates supplier invoices from external systems (KBA 3439469). It follows the same rules, including the GR-based IV rule above. - Re-test the configuration, not just the file. Tolerance limits, duplicate-check settings and tax codes are company-code configuration; confirm them in the S/4HANA system before the first production run.
Free MIRO supplier invoice template
PostNow.ai publishes a free MIRO supplier invoice template: H rows for the invoice header and D rows for the PO lines, sample invoices, and a field guide that maps every column to its BAPI_INCOMINGINVOICE_CREATE field, including the goods receipt columns and unplanned delivery costs. It is listed with the purchasing, goods movement and invoice templates on the SAP MM upload templates page. Purchase orders themselves are covered in ME21N mass upload, and choosing a method for other SAP objects in SAP mass upload from Excel.
