# SAP MM BAPI for PO Create and Change: BAPI_PO_CREATE1 and BAPI_PO_CHANGE

> Source: https://netray.co/erp-help/sap-mm-bapi-po-create1-bapi-po-change-how-to
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: ERP Help

## Short answer

Use BAPI_PO_CREATE1 to create a purchase order and BAPI_PO_CHANGE to change one. Each takes a data structure and a matching X-structure that flags which fields to apply, returns messages in the RETURN table, and only persists after you call BAPI_TRANSACTION_COMMIT when no error message came back.

## Kind

how-to

## System

sap

## Erp

SAP ECC / S/4HANA

## Module

MM Purchasing / ABAP BAPI

## Query

sap mm bapi for po create and change

## Alternate Queries

- BAPI_PO_CREATE1 example
- BAPI_PO_CHANGE example
- BAPI_PO_CREATE1 POHEADERX POITEMX

## Applies To

SAP ECC 6.0 and S/4HANA on-premise; BAPI_PO_CREATE1 replaces the older BAPI_PO_CREATE

## Steps

### How to create and change a PO with BAPIs

**Items:**

- Fill POHEADER with company code, document type, vendor, purchasing organization and group, and set the matching flags in POHEADERX.
- Fill POITEM with item number (00010, 00020), material, plant, quantity and price, and set the same fields to 'X' in POITEMX, along with the item number.
- Fill POSCHEDULE (item, schedule line, delivery date, quantity) and POSCHEDULEX, since the PO needs a schedule line to be deliverable.
- Call BAPI_PO_CREATE1; check the RETURN table for messages of type E or A. If there are none, call BAPI_TRANSACTION_COMMIT, otherwise call BAPI_TRANSACTION_ROLLBACK.
- Read the new number from EXPPURCHASEORDER.
- To change, call BAPI_PO_CHANGE with PURCHASEORDER and only the structures you need, again flagging every changed field in the X-structure.
- Use TESTRUN = 'X' in create to simulate without saving.

## Sections

### Minimal create example

**Body:**

The pattern below is the common minimum for a material PO. Field names follow the BAPI structures (BAPIMEPOHEADER, BAPIMEPOITEM, BAPIMEPOSCHEDULE); confirm them in SE37 or SE11 for your release, because available fields differ between versions.

The X-structure is the part that causes the most bugs: any field you do not flag with 'X' is ignored, even if its value is set.

**Code:**

- DATA: ls_header  TYPE bapimepoheader,
-       ls_headerx TYPE bapimepoheaderx,
-       lt_item    TYPE TABLE OF bapimepoitem,
-       lt_itemx   TYPE TABLE OF bapimepoitemx,
-       lt_sched   TYPE TABLE OF bapimeposchedule,
-       lt_schedx  TYPE TABLE OF bapimeposchedulx,
-       lt_return  TYPE TABLE OF bapiret2,
-       lv_po      TYPE bapimepoheader-po_number.
- 
- ls_header-comp_code = '1000'.  ls_headerx-comp_code = 'X'.
- ls_header-doc_type  = 'NB'.    ls_headerx-doc_type  = 'X'.
- ls_header-vendor    = '0000100001'. ls_headerx-vendor = 'X'.
- ls_header-purch_org = '1000'.  ls_headerx-purch_org = 'X'.
- ls_header-pur_group = '001'.   ls_headerx-pur_group = 'X'.
- 
- APPEND VALUE #( po_item = '00010' material = 'RM-1001' plant = '1000'
-                 quantity = 100 net_price = '12.50' ) TO lt_item.
- APPEND VALUE #( po_item = '00010' po_itemx = 'X' material = 'X'
-                 plant = 'X' quantity = 'X' net_price = 'X' ) TO lt_itemx.
- APPEND VALUE #( po_item = '00010' sched_line = '0001'
-                 delivery_date = sy-datum + 14 quantity = 100 ) TO lt_sched.
- APPEND VALUE #( po_item = '00010' sched_line = '0001' po_itemx = 'X'
-                 sched_linex = 'X' delivery_date = 'X' quantity = 'X' ) TO lt_schedx.
- 
- CALL FUNCTION 'BAPI_PO_CREATE1'
-   EXPORTING poheader = ls_header poheaderx = ls_headerx
-   IMPORTING exppurchaseorder = lv_po
-   TABLES return = lt_return poitem = lt_item poitemx = lt_itemx
-          poschedule = lt_sched poschedulex = lt_schedx.
- 
- READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
- IF sy-subrc = 0.
-   CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
- ELSE.
-   CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
- ENDIF.

### Changing a PO with BAPI_PO_CHANGE

**Body:**

BAPI_PO_CHANGE takes PURCHASEORDER plus POHEADER/POHEADERX, POITEM/POITEMX and POSCHEDULE/POSCHEDULEX. To change a price, pass the item number with the new NET_PRICE and flag NET_PRICE in POITEMX. To delete an item, set DELETE_IND = 'L' with the flag, rather than removing the row.

The BAPI locks the PO while it runs. If a user has it open in ME22N, you get a lock message in RETURN. Handle it by retrying after a delay, not by ignoring it.

Released orders may be reset by changes to value-relevant fields, depending on your release strategy, so test your change against an order that is already released.

### Error handling and commit

**Body:**

A BAPI does not commit. Calling BAPI_TRANSACTION_COMMIT with WAIT = 'X' makes the update synchronous, so a following read or change sees the PO. See the related page on the commit step for the common mistakes.

Read all RETURN lines, not just the first. Type W messages are warnings, and some, such as missing account assignment defaults, point to a PO that will later fail in release or invoice.

## Pitfalls

- Setting values but not flagging them in the X-structure, so they are silently ignored.
- Not committing, or committing after an error message, which saves a half-formed PO.
- Missing schedule lines, which creates a PO that cannot be received against.
- Using BAPI_PO_CREATE1 in a loop with a commit per order without checking locks and number ranges.
- Assuming field names from an older release; check the BAPI structures in your system.

## Ai Angle

Developers often need to see what an existing PO actually looks like before coding against it. Netray's ERPray can run this kind of lookup in plain language against your own SAP system, read-only by default, showing the query it ran and respecting SAP authorizations, with the model served on your own hardware when the system is on-prem. It explains and finds the data; it does not replace configuration decisions or post documents without human approval.

## Faq

### What is the difference between BAPI_PO_CREATE and BAPI_PO_CREATE1?

**Answer:** BAPI_PO_CREATE1 is the newer version and the one SAP recommends. It supports more of what ME21N can do, including enhancements and conditions. BAPI_PO_CREATE is obsolete, so use CREATE1 for new development.

### Why are my PO fields not saved?

**Answer:** Most often the matching field in the X-structure was not set to 'X'. The BAPI only applies fields that are flagged, so check POHEADERX, POITEMX and POSCHEDULEX for every field you set.

### Do I need BAPI_TRANSACTION_COMMIT?

**Answer:** Yes. The BAPI itself does not commit the database. Call BAPI_TRANSACTION_COMMIT after confirming no error messages were returned, with WAIT = 'X' if later code depends on the saved PO.

### Can I add conditions through the BAPI?

**Answer:** Yes, using the POCOND and POCONDX tables to set condition types such as freight at item level. Make sure the condition type exists in the calculation schema, or it will not be applied.

## Search terms

BAPI_PO_CREATE1, BAPI_PO_CHANGE, sap mm bapi for po create and change, POHEADERX POITEMX, sap purchase order bapi example, BAPI_TRANSACTION_COMMIT po, sap create po abap, sap bapi purchase order change price

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
