BAPIs (Business Application Programming Interfaces) are standardized interfaces for accessing SAP business objects. They follow strict conventions and enable uniform integration.
BAPI Conventions
| Convention | Description |
|---|---|
| Naming | BAPI_<OBJECT>_<ACTION> |
| RETURN parameter | Always BAPIRET2 or BAPIRET2_T |
| No COMMIT | Caller is responsible |
| No dialogs | No popups or messages |
| RFC-enabled | Remote-enabled function module |
BAPIRET2 Structure
| Field | Description |
|---|---|
| TYPE | S/E/W/I/A (Success/Error/Warning/Info/Abort) |
| ID | Message class |
| NUMBER | Message number |
| MESSAGE | Full message text |
| MESSAGE_V1-V4 | Variables |
| LOG_NO | Log number |
| LOG_MSG_NO | Log message number |
Examples
1. Call Standard BAPI
" BAPI to read a customerDATA: ls_address TYPE bapicustomer_04, lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2' EXPORTING customerno = '0000001000' IMPORTING customeraddress = ls_address TABLES return = lt_return.
" Error checkIF line_exists( lt_return[ type = 'E' ] ). " Handle error LOOP AT lt_return INTO DATA(ls_error) WHERE type = 'E'. WRITE: / ls_error-message. ENDLOOP.ELSE. " Success WRITE: / ls_address-name, ls_address-city.ENDIF.2. BAPI with COMMIT
DATA: lt_return TYPE TABLE OF bapiret2.
" Create purchase orderCALL FUNCTION 'BAPI_PO_CREATE1' EXPORTING poheader = ls_header poheaderx = ls_headerx TABLES poitem = lt_items poitemx = lt_itemsx return = lt_return.
" Error checkREAD TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0. " Success - perform COMMIT CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = abap_true. " Wait for commit
WRITE: / 'Purchase order created'.ELSE. " Error - ROLLBACK CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
" Output error messages LOOP AT lt_return INTO DATA(ls_msg) WHERE type CA 'EAX'. WRITE: / ls_msg-message. ENDLOOP.ENDIF.3. Create Custom BAPI
" Function module: Z_BAPI_CUSTOMER_GETLISTFUNCTION z_bapi_customer_getlist.*"----------------------------------------------------------------------*"*"Local Interface:*" IMPORTING*" VALUE(IV_COUNTRY) TYPE LAND1 OPTIONAL*" VALUE(IV_MAX_ROWS) TYPE I DEFAULT 100*" EXPORTING*" VALUE(ET_CUSTOMERS) TYPE ZTT_CUSTOMER_LIST*" TABLES*" RETURN STRUCTURE BAPIRET2*"----------------------------------------------------------------------
" Input validation IF iv_max_rows < 1 OR iv_max_rows > 10000. append_return( EXPORTING iv_type = 'E' iv_id = 'ZCUST' iv_number = '001' iv_v1 = CONV #( iv_max_rows ) CHANGING ct_return = return[] ). RETURN. ENDIF.
" Read data TRY. SELECT kunnr, name1, ort01, land1 FROM kna1 WHERE land1 = @iv_country OR @iv_country IS INITIAL INTO CORRESPONDING FIELDS OF TABLE @et_customers UP TO @iv_max_rows ROWS.
IF sy-subrc <> 0. append_return( EXPORTING iv_type = 'I' iv_id = 'ZCUST' iv_number = '002' CHANGING ct_return = return[] ). ELSE. append_return( EXPORTING iv_type = 'S' iv_id = 'ZCUST' iv_number = '003' iv_v1 = CONV #( lines( et_customers ) ) CHANGING ct_return = return[] ). ENDIF.
CATCH cx_root INTO DATA(lx_error). append_return( EXPORTING iv_type = 'E' iv_id = 'ZCUST' iv_number = '004' iv_v1 = lx_error->get_text( )(50) CHANGING ct_return = return[] ). ENDTRY.
ENDFUNCTION.
" Helper method to add RETURN entriesFORM append_return USING iv_type TYPE sy-msgty iv_id TYPE sy-msgid iv_number TYPE sy-msgno iv_v1 TYPE clike OPTIONAL iv_v2 TYPE clike OPTIONAL iv_v3 TYPE clike OPTIONAL iv_v4 TYPE clike OPTIONAL CHANGING ct_return TYPE bapiret2_t.
DATA: ls_return TYPE bapiret2, lv_text TYPE string.
MESSAGE ID iv_id TYPE iv_type NUMBER iv_number WITH iv_v1 iv_v2 iv_v3 iv_v4 INTO lv_text.
ls_return-type = iv_type. ls_return-id = iv_id. ls_return-number = iv_number. ls_return-message = lv_text. ls_return-message_v1 = iv_v1. ls_return-message_v2 = iv_v2. ls_return-message_v3 = iv_v3. ls_return-message_v4 = iv_v4.
APPEND ls_return TO ct_return.ENDFORM.4. BAPI Wrapper Class
CLASS zcl_customer_bapi DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_customer, kunnr TYPE kunnr, name1 TYPE name1_gp, ort01 TYPE ort01_gp, land1 TYPE land1_gp, END OF ty_customer, ty_customers TYPE STANDARD TABLE OF ty_customer WITH KEY kunnr.
METHODS: get_customer IMPORTING iv_kunnr TYPE kunnr RETURNING VALUE(rs_customer) TYPE ty_customer RAISING zcx_bapi_error.
METHODS: get_customers_by_country IMPORTING iv_country TYPE land1 RETURNING VALUE(rt_customers) TYPE ty_customers RAISING zcx_bapi_error.
METHODS: create_customer IMPORTING is_data TYPE ty_customer RETURNING VALUE(rv_kunnr) TYPE kunnr RAISING zcx_bapi_error.
PRIVATE SECTION. METHODS: check_return IMPORTING it_return TYPE bapiret2_t RAISING zcx_bapi_error.ENDCLASS.
CLASS zcl_customer_bapi IMPLEMENTATION. METHOD get_customer. DATA: ls_address TYPE bapicustomer_04, lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2' EXPORTING customerno = iv_kunnr IMPORTING customeraddress = ls_address TABLES return = lt_return.
check_return( lt_return ).
rs_customer = VALUE #( kunnr = iv_kunnr name1 = ls_address-name ort01 = ls_address-city land1 = ls_address-country ). ENDMETHOD.
METHOD get_customers_by_country. DATA: lt_address TYPE TABLE OF bapicustomer_04, lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST' TABLES addressdata = lt_address return = lt_return.
check_return( lt_return ).
rt_customers = VALUE #( FOR ls_addr IN lt_address WHERE ( country = iv_country OR iv_country IS INITIAL ) ( kunnr = ls_addr-customer name1 = ls_addr-name ort01 = ls_addr-city land1 = ls_addr-country ) ). ENDMETHOD.
METHOD create_customer. DATA: lt_return TYPE TABLE OF bapiret2.
" BAPI for creation... CALL FUNCTION 'BAPI_CUSTOMER_CREATE...' " Parameters... TABLES return = lt_return.
check_return( lt_return ).
" On success COMMIT CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = abap_true.
rv_kunnr = '...'. " New customer number ENDMETHOD.
METHOD check_return. " Check for errors in RETURN LOOP AT it_return INTO DATA(ls_return) WHERE type CA 'EAX'.
RAISE EXCEPTION TYPE zcx_bapi_error EXPORTING textid = zcx_bapi_error=>bapi_error msgid = ls_return-id msgno = ls_return-number msgv1 = ls_return-message_v1 msgv2 = ls_return-message_v2 msgv3 = ls_return-message_v3 msgv4 = ls_return-message_v4. ENDLOOP. ENDMETHOD.ENDCLASS.
" UsageTRY. DATA(lo_customer) = NEW zcl_customer_bapi( ). DATA(ls_customer) = lo_customer->get_customer( '0000001000' ).
WRITE: / ls_customer-name1, ls_customer-ort01.
CATCH zcx_bapi_error INTO DATA(lx_error). WRITE: / 'Error:', lx_error->get_text( ).ENDTRY.5. BAPI for Mass Processing
FUNCTION z_bapi_orders_create_mass.*"----------------------------------------------------------------------*" IMPORTING*" VALUE(IT_ORDERS) TYPE ZTT_ORDER_CREATE*" EXPORTING*" VALUE(ET_SUCCESS) TYPE ZTT_ORDER_NUMBERS*" VALUE(ET_FAILED) TYPE ZTT_ORDER_FAILED*" TABLES*" RETURN STRUCTURE BAPIRET2*"----------------------------------------------------------------------
DATA: lt_order_return TYPE TABLE OF bapiret2, lv_order_no TYPE vbeln.
LOOP AT it_orders INTO DATA(ls_order). CLEAR: lt_order_return, lv_order_no.
" Create single order CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2' EXPORTING order_header_in = ls_order-header IMPORTING salesdocument = lv_order_no TABLES return = lt_order_return order_items_in = ls_order-items order_partners = ls_order-partners.
" Check READ TABLE lt_order_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0 AND lv_order_no IS NOT INITIAL. " Success CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = abap_true.
APPEND VALUE #( order_no = lv_order_no ) TO et_success.
APPEND VALUE #( type = 'S' id = 'ZORD' number = '001' message = |Order { lv_order_no } created| ) TO return. ELSE. " Error CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
APPEND VALUE #( index = sy-tabix messages = lt_order_return ) TO et_failed.
APPEND LINES OF lt_order_return TO return. ENDIF. ENDLOOP.
" Summary APPEND VALUE #( type = 'I' id = 'ZORD' number = '002' message = |{ lines( et_success ) } successful, { lines( et_failed ) } failed| ) TO return.
ENDFUNCTION.6. BAPI Exception Class
CLASS zcx_bapi_error DEFINITION INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. INTERFACES: if_t100_message.
CONSTANTS: BEGIN OF bapi_error, msgid TYPE symsgid VALUE 'ZBAPI', msgno TYPE symsgno VALUE '001', attr1 TYPE scx_attrname VALUE 'MSGV1', attr2 TYPE scx_attrname VALUE 'MSGV2', attr3 TYPE scx_attrname VALUE 'MSGV3', attr4 TYPE scx_attrname VALUE 'MSGV4', END OF bapi_error.
DATA: msgid TYPE sy-msgid, msgno TYPE sy-msgno, msgv1 TYPE sy-msgv1, msgv2 TYPE sy-msgv2, msgv3 TYPE sy-msgv3, msgv4 TYPE sy-msgv4.
METHODS: constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL msgid TYPE sy-msgid OPTIONAL msgno TYPE sy-msgno OPTIONAL msgv1 TYPE sy-msgv1 OPTIONAL msgv2 TYPE sy-msgv2 OPTIONAL msgv3 TYPE sy-msgv3 OPTIONAL msgv4 TYPE sy-msgv4 OPTIONAL.
CLASS-METHODS: from_bapiret2 IMPORTING is_return TYPE bapiret2 RETURNING VALUE(ro_error) TYPE REF TO zcx_bapi_error.
CLASS-METHODS: from_bapiret2_table IMPORTING it_return TYPE bapiret2_t RETURNING VALUE(ro_error) TYPE REF TO zcx_bapi_error.ENDCLASS.
CLASS zcx_bapi_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ).
me->msgid = msgid. me->msgno = msgno. me->msgv1 = msgv1. me->msgv2 = msgv2. me->msgv3 = msgv3. me->msgv4 = msgv4.
IF textid IS INITIAL. if_t100_message~t100key = bapi_error. ELSE. if_t100_message~t100key = textid. ENDIF. ENDMETHOD.
METHOD from_bapiret2. ro_error = NEW #( msgid = is_return-id msgno = is_return-number msgv1 = is_return-message_v1 msgv2 = is_return-message_v2 msgv3 = is_return-message_v3 msgv4 = is_return-message_v4 ). ENDMETHOD.
METHOD from_bapiret2_table. " Use first error message LOOP AT it_return INTO DATA(ls_return) WHERE type CA 'EAX'. ro_error = from_bapiret2( ls_return ). RETURN. ENDLOOP. ENDMETHOD.ENDCLASS.7. Call BAPI via RFC
DATA: lt_return TYPE TABLE OF bapiret2.
" RFC destinationDATA(lv_destination) = 'PRD_CLNT100'.
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST' DESTINATION lv_destination TABLES addressdata = lt_address return = lt_return EXCEPTIONS communication_failure = 1 MESSAGE lv_message system_failure = 2 MESSAGE lv_message OTHERS = 3.
IF sy-subrc <> 0. WRITE: / 'RFC error:', lv_message.ELSE. " Check BAPI return check_return( lt_return ).ENDIF.8. BAPI with Update Task
FUNCTION z_bapi_document_save.*"----------------------------------------------------------------------*" IMPORTING*" VALUE(IS_DOCUMENT) TYPE TY_DOCUMENT*" TABLES*" RETURN STRUCTURE BAPIRET2*"----------------------------------------------------------------------
" Validation perform_validation( EXPORTING is_document = is_document CHANGING ct_return = return[] ).
IF line_exists( return[ type = 'E' ] ). RETURN. ENDIF.
" Save in update task CALL FUNCTION 'Z_UPDATE_DOCUMENT' IN UPDATE TASK EXPORTING is_document = is_document.
" Success message APPEND VALUE bapiret2( type = 'S' id = 'ZDOC' number = '001' message = 'Document will be saved' ) TO return.
" COMMIT is performed by the caller!
ENDFUNCTION.9. BAPI Helper Functions
CLASS zcl_bapi_helper DEFINITION. PUBLIC SECTION. " Check if RETURN contains errors CLASS-METHODS: has_errors IMPORTING it_return TYPE bapiret2_t RETURNING VALUE(rv_error) TYPE abap_bool.
" Filter messages by type CLASS-METHODS: get_messages_by_type IMPORTING it_return TYPE bapiret2_t iv_type TYPE sy-msgty RETURNING VALUE(rt_messages) TYPE bapiret2_t.
" Convert RETURN to string CLASS-METHODS: return_to_string IMPORTING it_return TYPE bapiret2_t RETURNING VALUE(rv_string) TYPE string.
" Add message CLASS-METHODS: add_message IMPORTING iv_type TYPE sy-msgty iv_id TYPE sy-msgid iv_number TYPE sy-msgno iv_v1 TYPE clike OPTIONAL iv_v2 TYPE clike OPTIONAL iv_v3 TYPE clike OPTIONAL iv_v4 TYPE clike OPTIONAL CHANGING ct_return TYPE bapiret2_t.ENDCLASS.
CLASS zcl_bapi_helper IMPLEMENTATION. METHOD has_errors. rv_error = xsdbool( line_exists( it_return[ type = 'E' ] ) OR line_exists( it_return[ type = 'A' ] ) OR line_exists( it_return[ type = 'X' ] ) ). ENDMETHOD.
METHOD get_messages_by_type. rt_messages = FILTER #( it_return WHERE type = iv_type ). ENDMETHOD.
METHOD return_to_string. LOOP AT it_return INTO DATA(ls_return). IF rv_string IS NOT INITIAL. rv_string = rv_string && cl_abap_char_utilities=>newline. ENDIF. rv_string = rv_string && |{ ls_return-type }: { ls_return-message }|. ENDLOOP. ENDMETHOD.
METHOD add_message. DATA: ls_return TYPE bapiret2, lv_text TYPE string.
MESSAGE ID iv_id TYPE iv_type NUMBER iv_number WITH iv_v1 iv_v2 iv_v3 iv_v4 INTO lv_text.
ls_return = VALUE #( type = iv_type id = iv_id number = iv_number message = lv_text message_v1 = iv_v1 message_v2 = iv_v2 message_v3 = iv_v3 message_v4 = iv_v4 ).
APPEND ls_return TO ct_return. ENDMETHOD.ENDCLASS.
" UsageDATA: lt_return TYPE bapiret2_t.
zcl_bapi_helper=>add_message( EXPORTING iv_type = 'S' iv_id = 'ZMSG' iv_number = '001' iv_v1 = 'Success' CHANGING ct_return = lt_return).
IF zcl_bapi_helper=>has_errors( lt_return ). DATA(lv_errors) = zcl_bapi_helper=>return_to_string( lt_return ). MESSAGE lv_errors TYPE 'E'.ENDIF.10. BAPI Explorer (BAPI)
Transaction: BAPI
1. Select Business Object (e.g., Customer)2. Display methods (GetList, GetDetail, Create, etc.)3. View documentation and parameters4. Determine function module name5. Test option via SE3711. Important Standard BAPIs
" CustomersCALL FUNCTION 'BAPI_CUSTOMER_GETLIST'. " List customersCALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2'. " Customer detailsCALL FUNCTION 'BAPI_CUSTOMER_CREATEFROMDAT1'. " Create customer
" VendorsCALL FUNCTION 'BAPI_VENDOR_GETLIST'. " List vendorsCALL FUNCTION 'BAPI_VENDOR_GETDETAIL'. " Vendor details
" MaterialsCALL FUNCTION 'BAPI_MATERIAL_GETLIST'. " List materialsCALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL'. " Material details
" Purchase ordersCALL FUNCTION 'BAPI_PO_CREATE1'. " Create purchase orderCALL FUNCTION 'BAPI_PO_CHANGE'. " Change purchase orderCALL FUNCTION 'BAPI_PO_GETDETAIL'. " Purchase order details
" Sales ordersCALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'. " Create sales orderCALL FUNCTION 'BAPI_SALESORDER_GETLIST'. " List sales ordersCALL FUNCTION 'BAPI_SALESORDER_CHANGE'. " Change sales order
" PostingsCALL FUNCTION 'BAPI_ACC_DOCUMENT_POST'. " Post FI document
" Transaction controlCALL FUNCTION 'BAPI_TRANSACTION_COMMIT'. " CommitCALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. " RollbackBAPI Checklist
✓ Function module is RFC-enabled✓ RETURN parameter of type BAPIRET2✓ No COMMIT WORK in BAPI✓ No MESSAGE statements✓ No dialog calls (popups)✓ Complete error handling✓ Parameter documentation✓ Authorization check implemented✓ Input validation present✓ Testable via SE37Important Notes / Best Practice
- COMMIT WORK never in BAPI – the caller decides.
- Always fill RETURN with meaningful messages.
- Mark as RFC-enabled for remote calls.
- No MESSAGE statements – only populate RETURN.
- Implement authorization check in BAPI.
- Input validation before processing.
- Wrapper classes for easy usage.
- Use BAPI Explorer (transaction BAPI) for documentation.
- Mass processing with individual COMMITs per record.
- Combine with Exception Classes for OO integration.