BAPI Part 2: Calling a BAPI — Inputs, X Structures, RETURN and Commit
Call BAPI SALESORDER CREATEFROMDAT2 step by step: fill header, item, partner and schedule structures, set the corresponding X (change flag) structures, use internal formats, evaluate RETURN, then commit with wait or roll back.
Explanation
📌 KEY POINTS
✅ Fill the data structures (…_IN) and, where the BAPI has them, the matching X structures (…_INX) with 'X' for every field you supply.
✅ Use SAP internal formats: leading zeros for customer/material numbers (ALPHA conversion), internal unit codes, dates as YYYYMMDD.
✅ After the call: check RETURN for types E and A; then BAPI_TRANSACTION_COMMIT (WAIT = 'X') or BAPI_TRANSACTION_ROLLBACK.
⚠️ Forgetting an X flag means the BAPI ignores the value — no error, just missing data.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 1 explained BAPIs. Now we call one of the most used: creating a sales order.\n\n━━━━━━━━━━━━━━━━━━━━\n▶ 1. THE PARAMETERS (BAPI_SALESORDER_CREATEFROMDAT2)\n• ORDER_HEADER_IN (BAPISDHD1): DOC_TYPE, SALES_ORG, DISTR_CHAN, DIVISION, PURCH_NO_C …
- ORDER_HEADER_INX (BAPISDHD1X): same fields as flags, plus UPDATEFLAG = 'I'.
- ORDER_ITEMS_IN / ORDER_ITEMS_INX: ITM_NUMBER, MATERIAL, TARGET_QTY …
- ORDER_PARTNERS: PARTN_ROLE ('AG' sold-to, 'WE' ship-to), PARTN_NUMB.
- ORDER_SCHEDULES_IN / _INX: ITM_NUMBER, SCHED_LINE, REQ_QTY.
- RETURN: messages; SALESDOCUMENT: the new number.
━━━━━━━━━━━━━━━━━━━━
▶ 2. X STRUCTURES
They tell the BAPI which fields you are passing (especially important in change BAPIs, where initial means "don't change"). Rule: every filled field gets 'X', key fields (ITM_NUMBER) are repeated in the X structure.
━━━━━━━━━━━━━━━━━━━━
▶ 3. INTERNAL FORMATS
- CONVERSION_EXIT_ALPHA_INPUT for KUNNR/MATNR/VBELN-like fields when input comes without zeros.
- Units: internal code (e.g. 'ST'), CONVERSION_EXIT_CUNIT_INPUT for external input.
- Partner roles: internal codes AG/WE (English SP/SH are external).
━━━━━━━━━━━━━━━━━━━━
▶ 4. AFTER THE CALL
- RETURN type E/A → error → rollback.
- Only S/W/I → commit with WAIT = 'X' and check its RETURN.
- Then the document is readable in the database.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Run the code example in a test system with valid customer/material data.
- Remove the X flag for PURCH_NO_C and see that the PO number is missing.
- Enter an invalid material and read the RETURN messages.
✅ CHECKPOINT: you can call a create BAPI with correct structures, X flags, formats and commit handling.
Code example
REPORT zbapi_so_create. PARAMETERS: p_kunnr TYPE kunnr DEFAULT '1000', p_matnr TYPE matnr DEFAULT 'M-01', p_qty TYPE kwmeng DEFAULT 5. DATA: ls_header TYPE bapisdhd1, ls_headerx TYPE bapisdhd1x, lt_items TYPE STANDARD TABLE OF bapisditm, ls_item TYPE bapisditm, lt_itemsx TYPE STANDARD TABLE OF bapisditmx, ls_itemx TYPE bapisditmx, lt_partners TYPE STANDARD TABLE OF bapiparnr, ls_partner TYPE bapiparnr, lt_sched TYPE STANDARD TABLE OF bapischdl, ls_sched TYPE bapischdl, lt_schedx TYPE STANDARD TABLE OF bapischdlx, ls_schedx TYPE bapischdlx, lt_return TYPE STANDARD TABLE OF bapiret2, ls_return TYPE bapiret2, ls_commit TYPE bapiret2, lv_vbeln TYPE vbeln_va, lv_kunnr TYPE kunnr, lv_matnr TYPE matnr, lv_error TYPE abap_bool. START-OF-SELECTION.* ===== Step 1: internal formats ===== CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT' EXPORTING input = p_kunnr IMPORTING output = lv_kunnr. CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT' EXPORTING input = p_matnr IMPORTING output = lv_matnr EXCEPTIONS OTHERS = 1. * ===== Step 2: header + X flags ===== ls_header-doc_type = 'OR'. ls_header-sales_org = '1000'. ls_header-distr_chan = '10'. ls_header-division = '00'. ls_header-purch_no_c = 'PO-4711'. ls_headerx-updateflag = 'I'. ls_headerx-doc_type = 'X'. ls_headerx-sales_org = 'X'. ls_headerx-distr_chan = 'X'. ls_headerx-division = 'X'. ls_headerx-purch_no_c = 'X'. " without this, the PO number is ignored * ===== Step 3: item + schedule line + X flags ===== ls_item-itm_number = '000010'. ls_item-material = lv_matnr. APPEND ls_item TO lt_items. ls_itemx-itm_number = '000010'. ls_itemx-updateflag = 'I'. ls_itemx-material = 'X'. APPEND ls_itemx TO lt_itemsx. ls_sched-itm_number = '000010'. ls_sched-sched_line = '0001'. ls_sched-req_qty = p_qty. APPEND ls_sched TO lt_sched. ls_schedx-itm_number = '000010'. ls_schedx-sched_line = '0001'. ls_schedx-updateflag = 'I'. ls_schedx-req_qty = 'X'. APPEND ls_schedx TO lt_schedx. * ===== Step 4: partners (internal role codes) ===== ls_partner-partn_role = 'AG'. " sold-to ls_partner-partn_numb = lv_kunnr. APPEND ls_partner TO lt_partners. * ===== Step 5: call ===== CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2' EXPORTING order_header_in = ls_header order_header_inx = ls_headerx IMPORTING salesdocument = lv_vbeln TABLES return = lt_return order_items_in = lt_items order_items_inx = lt_itemsx order_partners = lt_partners order_schedules_in = lt_sched order_schedules_inx = lt_schedx. * ===== Step 6: evaluate RETURN, then commit or roll back ===== LOOP AT lt_return INTO ls_return WHERE type = 'E' OR type = 'A'. lv_error = abap_true. WRITE: / ls_return-type, ls_return-message. ENDLOOP. IF lv_error = abap_true. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. ELSE. CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X' IMPORTING return = ls_commit. IF ls_commit-type CA 'EA'. WRITE: / 'Commit failed:', ls_commit-message. ELSE. WRITE: / 'Sales order created:', lv_vbeln. ENDIF. ENDIF.Real project scenario
An e-commerce integration created orders successfully, but customer PO numbers were missing on all of them. The mapping filled PURCH_NO_C but not the X flag in ORDER_HEADER_INX, so the BAPI ignored the value without any message.
The team added a mapping unit test comparing each filled field with its X flag, and a post-creation check reading VBAK-BSTNK for a sample of orders in monitoring.
Common mistakes
- Missing X flags (values silently ignored).
- External formats (no leading zeros, external unit or partner codes).
- Checking only SALESDOCUMENT instead of RETURN.
- No commit or commit without WAIT when reading immediately.
- Mismatched item numbers between item, X and schedule tables.
Best practices
- Map every filled field to its X flag.
- Convert external values with conversion exits.
- Evaluate all RETURN entries (E/A = error).
- Commit with WAIT = 'X' and check its RETURN.
- Test in SE37 test sequences first.
Interview angle
Questions: "How do you call BAPI_SALESORDER_CREATEFROMDAT2?", "What are X structures?", "Why is my field not saved?"
Strong answer: fill header/items/partners/schedules with internal formats, set matching X flags (UPDATEFLAG, field = 'X'), call, check RETURN for E/A, then BAPI_TRANSACTION_COMMIT WAIT = 'X' or ROLLBACK; a missing X flag makes the BAPI ignore the value; partner roles internal (AG/WE).
Practice this lesson
Quick check
1. A value is filled in ORDER_HEADER_IN but not saved and no error appears. Most likely cause?
2. Which is TRUE about BAPIs?
3. After a successful BAPI call you must…
Interview questions
1. You need to create a sales order from an external system. Which BAPI and how do you handle errors?
Answer it in your own words first, then compare.
2. Difference between BAPI and RFC.
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- BAPI Part 1: What a BAPI Is and How to Find One
- BAPI Part 10: "Success but No Document" — Debugging BAPI Problems
- BAPI Part 3: BAPI vs RFC vs OData
- BAPI Part 4: Understanding BAPI RETURN Messages
- BAPI Part 5: Commit, WAIT, Rollback and the SAP LUW
- BAPI Part 6: Mapping Header, Item, Partner and Schedule Data
- BAPI Part 7: Test Run, Simulation and Safe BAPI Execution
- BAPI Part 8: EXTENSIONIN — Saving Custom Fields with BAPIs