Introduction
SAP XI (PI/PO) developers and ABAP developers have traditionally collaborated with ease, thanks to ABAP Proxy — a convenient, well-established way to build SAP interfaces. However, when SAP Integration Suite enters the picture, that convenience quickly fades. Connectivity between ABAP systems and Integration Suite introduces a layer of complexity that many developers find challenging to navigate.
While several blogs already explain how to invoke an iFlow from an ABAP program, they largely stop there — none of them establish a central, reusable connectivity mechanism between an SAP NetWeaver application and Integration Suite. As a result, developers often end up rebuilding the same connectivity logic, again and again, for every single interface.
I saw an opportunity to bridge this gap between ABAP developers and Integration Suite developers. Instead of letting connectivity logic be reinvented for each interface, I designed a unified, pre-defined approach for invoking iFlows — one that could be reused consistently across the landscape.
Business Requirement
You want to create an interface from a NetWeaver-based application to SAP Integration Suite, using an HTTPS sender adapter on the iFlow side and any receiver adapter of your choice.
Prerequisites
Before getting started, here are a couple of assumptions:
- SAP Integration Suite service is already activated on BTP.
- An iFlow with an HTTPS sender adapter (address: /demo_iflow, User role: ESBMessaging.send) has already been created and deployed.
With these in place, let's get started.
Step 1: Establish Connectivity
a. Create a PI Runtime Instance in BTP
At the subaccount level in BTP, create a PI Runtime service instance.
b. Create a Service Key
Within the same subaccount, create a service key for the PI Runtime instance.
This key provides four key values:
clientid,clientsecret,tokenurl, andurl— you'll need these in the next steps.
c. Create an RFC Destination in NetWeaver (SM59)
Instead of hardcoding integration suite related connectivity details in your ABAP program, create a remote destination via transaction SM59:
Field Value
| Host | url from the service key |
| Port / Proxy details | Consult your Basis team |
| User | clientid from the service key |
| Password | clientsecret from the service key |
Note: SSL configuration via STRUST is also required for this connection to work. This typically needs to be handled by your Basis team.
Host = url
User = clientid , Password = clientsecret
Note:
1. To ensure that the connection is working fine, put the endpoint of iFlow in Host and perform connection test. Once validated replace it with only the url from service key. With this url the connection test will fail (status code 404) but it is ok as it will help us use the same destination for multiple iFlows programmatically.
2. This task has to be performed by basis team in every environment such as dev, qa, prd etc.
Step 2: Create a Reusable ABAP Utility
To avoid repeating this code for every interface, the next step is to encapsulate it into a single, reusable ABAP class — one that any developer can simply call, passing in the iFlow-specific details (endpoint, payload, headers, method etc.), without worrying about authentication or connectivity.
Here's the source code for the ABAP class:
class ZCL_CPI_HTTP_SENDER definition
public
create public .
public section.
methods CONSTRUCTOR
importing
!IV_URI type STRING optional
!IV_RFCDEST_ISUITE type RFCDEST default 'INTEGRATION_SUITE'
exceptions
EX_NOT_LIVE .
methods INVOKE_CPI_SYNC
importing
!IT_HTTP_HDR type TIHTTPNVP optional
!IV_HTTP_METHOD type STRING default IF_HTTP_ENTITY=>CO_REQUEST_METHOD_POST
exporting
!ES_DATA_IN type DATA
!EV_HTTP_RESP type CHAR3
exceptions
HTTP_COMMUNICATION_FAILURE .
methods PREPARE_JSON
importing
!IV_DATA type DATA
!IV_COMPRESS type /UI2/CL_JSON=>BOOL default ABAP_FALSE
!IV_PRETTY_NAME type /UI2/CL_JSON=>PRETTY_NAME_MODE default /UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE
!IV_ASSOC_ARRAYS type /UI2/CL_JSON=>BOOL default ABAP_FALSE
!IV_NUMC_AS_STRING type /UI2/CL_JSON=>BOOL default ABAP_TRUE
!IT_NAME_MAPPINGS type /UI2/CL_JSON=>NAME_MAPPINGS optional .
protected section.
private section.
data MT_NAME_MAPPINGS type /UI2/CL_JSON=>NAME_MAPPINGS .
data MV_REQ_BODY_JSON type STRING .
data MV_URI type STRING .
data MO_HTTP_CLIENT type ref to IF_HTTP_CLIENT .
methods IS_STATUS_OK
importing
!IV_RETURN_STATUS type I
returning
value(RV_OK) type BOOLEAN .
ENDCLASS.
CLASS ZCL_CPI_HTTP_SENDER IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_CPI_HTTP_SENDER->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_URI TYPE STRING(optional)
* | [--->] IV_RFCDEST_ISUITE TYPE RFCDEST (default ='INTEGRATION_SUITE')
* | [EXC!] EX_NOT_LIVE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD CONSTRUCTOR.
CALL METHOD cl_http_client=>create_by_destination
EXPORTING
destination = iv_rfcdest_isuite
IMPORTING
client = mo_http_client
EXCEPTIONS
argument_not_found = 1
destination_not_found = 2
destination_no_authority = 3
plugin_not_active = 4
internal_error = 5
OTHERS = 6.
IF sy-subrc EQ 0 AND mo_http_client IS BOUND.
cl_http_utility=>set_request_uri(
EXPORTING
request = mo_http_client->request
uri = iv_uri ).
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_CPI_HTTP_SENDER->INVOKE_CPI_SYNC
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_HTTP_HDR TYPE TIHTTPNVP(optional)
* | [--->] IV_HTTP_METHOD TYPE STRING (default =IF_HTTP_ENTITY=>CO_REQUEST_METHOD_POST)
* | [<---] ES_DATA_IN TYPE DATA
* | [<---] EV_HTTP_RESP TYPE CHAR3
* | [EXC!] HTTP_COMMUNICATION_FAILURE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD INVOKE_CPI_SYNC.
DATA: lv_response_json TYPE string,
lo_response TYPE REF TO if_rest_entity,
lv_raise_error TYPE boolean.
CHECK mo_http_client IS BOUND.
mo_http_client->request->set_method( iv_http_method ).
IF mv_req_body_json IS NOT INITIAL.
mo_http_client->request->set_cdata( EXPORTING data = mv_req_body_json ).
ENDIF.
IF it_http_hdr IS NOT INITIAL.
mo_http_client->request->set_header_fields( it_http_hdr ).
ENDIF.
mo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4 ).
IF sy-subrc EQ 0.
mo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
IF sy-subrc EQ 0.
" Get string data
mo_http_client->response->get_status( IMPORTING code = DATA(lv_code) ).
ev_http_resp = lv_code.
IF is_status_ok( lv_code ) EQ abap_true.
DATA(lo_rest_client) = NEW cl_rest_http_client( io_http_client = mo_http_client ).
IF lo_rest_client IS BOUND.
lo_response = lo_rest_client->if_rest_client~get_response_entity( ).
IF lo_response IS BOUND.
lv_response_json = lo_response->get_string_data( ).
IF lv_response_json IS NOT INITIAL.
CALL METHOD /ui2/cl_json=>deserialize
EXPORTING
json = lv_response_json
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
* assoc_arrays = C_BOOL-FALSE
* assoc_arrays_opt = C_BOOL-FALSE
name_mappings = mt_name_mappings
* conversion_exits = C_BOOL-FALSE
* hex_as_base64 = C_BOOL-TRUE
CHANGING
data = es_data_in.
ENDIF.
ENDIF.
ENDIF.
ELSE.
lv_raise_error = abap_true.
ENDIF.
CALL METHOD mo_http_client->close
EXCEPTIONS
http_invalid_state = 0
OTHERS = 0.
ELSE.
lv_raise_error = abap_true.
ENDIF.
ELSE.
lv_raise_error = abap_true.
ENDIF.
IF lv_raise_error = abap_true.
RAISE http_communication_failure.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_CPI_HTTP_SENDER->IS_STATUS_OK
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_RETURN_STATUS TYPE I
* | [<-()] RV_OK TYPE BOOLEAN
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD IS_STATUS_OK.
CLEAR rv_ok.
IF iv_return_status GE 200 AND iv_return_status LE 299. " http response status 200-299 indicate success
rv_ok = abap_true.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_CPI_HTTP_SENDER->PREPARE_JSON
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_DATA TYPE DATA
* | [--->] IV_COMPRESS TYPE /UI2/CL_JSON=>BOOL (default =ABAP_FALSE)
* | [--->] IV_PRETTY_NAME TYPE /UI2/CL_JSON=>PRETTY_NAME_MODE (default =/UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE)
* | [--->] IV_ASSOC_ARRAYS TYPE /UI2/CL_JSON=>BOOL (default =ABAP_FALSE)
* | [--->] IV_NUMC_AS_STRING TYPE /UI2/CL_JSON=>BOOL (default =ABAP_TRUE)
* | [--->] IT_NAME_MAPPINGS TYPE /UI2/CL_JSON=>NAME_MAPPINGS(optional)
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD PREPARE_JSON.
* Serialize proxy message into json
CALL METHOD /ui2/cl_json=>serialize
EXPORTING
data = iv_data
compress = iv_compress
pretty_name = iv_pretty_name
numc_as_string = iv_numc_as_string
RECEIVING
r_json = mv_req_body_json.
ENDMETHOD.
ENDCLASS.
Step: 3 Create ABAP program for invoking the iFlow
Here is a sample program simply sending an internal table ls_out-lines with sample headers lt_http_hdr to the iFlow
*&---------------------------------------------------------------------*
*& Report ZCPI_DEMO_HTTP_SEND
*&---------------------------------------------------------------------*
REPORT zcpi_demo_http_send.
TYPES: BEGIN OF ty_msg,
lines TYPE /bofu/t_demo_bupa_id,
END OF ty_msg.
DATA: lv_http_resp TYPE char3,
ls_http_hdr TYPE ihttpnvp,
lo_http_sender TYPE REF TO zcl_cpi_http_sender,
ls_out TYPE ty_msg, " has to be a structure, type can be any (ty_msg is only for demo purpose)
lt_http_hdr TYPE tihttpnvp. " can contain any headers you want to send to the iFlow
CONSTANTS:
lc_uri TYPE string VALUE '/http/demo_iflow', " address on https sender adapter
lc_rfcdest TYPE rfcdest VALUE 'INTEGRATION_SUITE'. " name of RFC destination for integration suite
ls_out-lines = VALUE /bofu/t_demo_bupa_id( ( bupa_id = 'demo line 1' ) ( bupa_id = 'demo line 2' ) ( bupa_id = 'demo line 3' ) ).
TRY.
CREATE OBJECT lo_http_sender EXPORTING iv_uri = lc_uri iv_rfcdest_isuite = lc_rfcdest.
* Prepare headers for the http request
ls_http_hdr-name = 'itfName'.
ls_http_hdr-value = 'Interface_XXX'.
APPEND ls_http_hdr TO lt_http_hdr.
CALL METHOD lo_http_sender->prepare_json EXPORTING iv_data = ls_out.
* Call iFlow
CALL METHOD lo_http_sender->invoke_cpi_sync
EXPORTING
it_http_hdr = lt_http_hdr
iv_http_method = if_http_entity=>co_request_method_get
IMPORTING
* es_proxy_in = ls_response
ev_http_resp = lv_http_resp
EXCEPTIONS
http_communication_failure = 1
OTHERS = 2.
CATCH cx_root.
ENDTRY.
Conclusion
By establishing this centralized connectivity and building a reusable ABAP utility around it, we unlock several key benefits:
Clear separation of duties — Basis, ABAP developers, and Integration Suite developers can each focus on their own area of expertise, without stepping on each other's responsibilities or duplicating effort.
Significant time savings — Connectivity and authentication logic is built once and reused everywhere, eliminating the need to reinvent it for every new interface.
Sharper developer focus — ABAP developers can shift their attention back to where it truly belongs: building robust data extraction logic, without needing to worry about the underlying connectivity mechanics.
Ultimately, this approach turns a repetitive, error-prone task into a standardized, one-time setup — making integrations with SAP Integration Suite faster, more consistent, and far easier to maintain at scale.