Contents
- Five Questions to Ask Before Picking a Technology
- The Technology Map
- IDoc: Asynchronous, Traceable, Reprocessable
- RFC and BAPI: Synchronous Calls Between SAP Systems
- OData: Exposing SAP to the Outside
- Outbound REST Calls from ABAP
- Event-Driven Integration
- Point-to-Point or Middleware?
- Error Handling and Monitoring
- Quick Decision Table by Scenario
- Common Mistakes
- Conclusion
"Should we do this integration with REST or with IDocs?" is usually asked in the first five minutes of the meeting and usually answered with whatever the team knows best. The result is familiar: fragile chains of synchronous calls, flows whose failures nobody notices, and investigations into "why were duplicate orders created last night?".
SAP offers plenty of tools for talking to the outside world; the problem isn't a lack of tools but choosing without a reason. In this article I describe where each tool is strong, where it typically breaks in the field and how to handle errors.
Five Questions to Ask Before Picking a Technology
- Direction: Is SAP calling the other side, or is the other side calling SAP? Or are both talking to an intermediary?
- Response expectation: Does the caller need the result right now (synchronous), or is "received, will process" enough (asynchronous)? Is a user waiting on screen?
- Volume and frequency: Ten documents a day or ten thousand an hour? Real time or nightly batch?
- Delivery guarantee: What happens if a message is lost? What if the same message is processed twice? Does order matter?
- The other side: What can it speak? Another SAP system, a modern REST API, an old system that can only drop files?
The Technology Map
| Technology | Style | Where it's strong | Watch out |
|---|---|---|---|
| IDoc / ALE | Asynchronous, document-based | Master data and document distribution between SAP systems, EDI; status tracking and reprocessing built in | SAP-specific format; non-SAP partners usually need an intermediary |
| RFC / BAPI | Synchronous (asynchronous with tRFC/qRFC/bgRFC) | Immediate calls between SAP systems, standard business functions | Couples systems tightly; needs network and authorization design |
| OData (V2/V4) | Synchronous, HTTP | Fiori and external apps reading and writing SAP data | Not suited to bulk data transfer |
| HTTP/REST client | Synchronous, HTTP | SAP calling external APIs: carriers, banks, e-document providers | Retries and logging are your responsibility |
| SOAP (Enterprise Services) | Synchronous or asynchronous | Existing SOAP contracts, some standard SAP scenarios | Generally not preferred for new development |
| Events (business events) | Asynchronous, publish/subscribe | Telling several systems about a change | Requires an event broker |
| Files (SFTP) | Asynchronous, batch | Legacy systems, high-volume nightly transfers | Weak error feedback; monitoring is built by hand |
IDoc: Asynchronous, Traceable, Reprocessable
IDocs may look old, but the problem they solve is still current: moving a document to another system reliably. Every IDoc has a number, a status history and a reprocessing path. The monitoring and retry infrastructure you would have to build from scratch for a REST integration comes out of the box with IDocs.
Creating a custom outbound IDoc takes a few lines. Which receiver, which port and when to send come not from code but from the partner profile (WE20):
DATA communication TYPE STANDARD TABLE OF edidc WITH EMPTY KEY.
DATA data_records TYPE STANDARD TABLE OF edidd WITH EMPTY KEY.
DATA(control) = VALUE edidc( mestyp = 'ZSHIPMENT'
idoctp = 'ZSHIPMENT01'
rcvprt = 'LS'
rcvprn = 'CARRIER01' ).
" The segment structure must be flat and character-like
data_records = VALUE #( ( segnam = 'Z1SHIPHDR'
sdata = shipment_header ) ).
CALL FUNCTION 'MASTER_IDOC_DISTRIBUTE'
EXPORTING
master_idoc_control = control
TABLES
communication_idoc_control = communication
master_idoc_data = data_records
EXCEPTIONS
error_in_idoc_control = 1
error_writing_idoc_status = 2
error_in_idoc_data = 3
sending_logical_system_unknown = 4
OTHERS = 5.
IF sy-subrc = 0.
" The IDoc becomes persistent with the caller's commit
COMMIT WORK.
ENDIF.The communication table returns the IDoc numbers created; storing them against your own document lets you answer "which IDoc did this shipment go out with?" in seconds later on.
Everyday IDoc tools
WE02 / WE05: IDoc list and segment content. BD87: fix and reprocess failed IDocs. WE20 / WE21: partner profile and port. WE19: create a test IDoc from an existing one. A support team that knows these four screens resolves most integration errors before they ever reach a developer.
RFC and BAPI: Synchronous Calls Between SAP Systems
When two SAP systems need "create this document now and tell me its number", a BAPI called over RFC is still the shortest route. But two kinds of error must be told apart:
DATA return TYPE STANDARD TABLE OF bapiret2 WITH EMPTY KEY.
DATA rfc_msg TYPE c LENGTH 200.
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
DESTINATION 'ERP_PROD'
EXPORTING
order_header_in = header
IMPORTING
salesdocument = sales_document
TABLES
return = return
order_items_in = items
order_partners = partners
EXCEPTIONS
system_failure = 1 MESSAGE rfc_msg
communication_failure = 2 MESSAGE rfc_msg
OTHERS = 3.
IF sy-subrc <> 0.
" Technical error: network, remote system, authorization. A retry may help.
RETURN.
ENDIF.
IF line_exists( return[ type = 'E' ] ) OR line_exists( return[ type = 'A' ] ).
" Business error: the data is wrong. Retrying won't change the outcome.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK' DESTINATION 'ERP_PROD'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' DESTINATION 'ERP_PROD'
EXPORTING
wait = abap_true.
ENDIF.Three things are critical here. BAPIs don't commit by themselves; BAPI_TRANSACTION_COMMIT must be called with the same destination, i.e. in the same RFC session. Committing without checking the RETURN table can leave a faulty document half-done. And technical and business errors must be handled separately: automatically retrying a call with bad data just produces the same error a hundred times.
When the answer isn't needed immediately but delivery must be guaranteed, prefer bgRFC (background RFC) over synchronous RFC: the call is queued, delivered later if the remote system is down, and order is preserved depending on the queue type. It is the modern infrastructure replacing the older tRFC and qRFC; its monitor is SBGRFCMON.
OData: Exposing SAP to the Outside
When a Fiori app, a mobile app or a web portal needs to read and write SAP data in real time, OData is the right tool. On S/4HANA, new services are written with CDS and RAP; the same business object can be exposed to Fiori through a UI binding and to external systems through a Web API binding. That way the external system goes through the same validations as the Fiori user.
I explain how to build the service in the OData V4 and CDS article and how to write the business rules in the RAP guide. From an integration point of view, two warnings are enough:
- OData is not a bulk transfer tool. Pulling a hundred thousand records page by page over OData every night is possible but needlessly strains both SAP and the other side. For bulk data, replication, files or analytical extraction tools fit better.
- Give external consumers their own service. Handing a UI service written for Fiori to an external system breaks the integration when the screen's needs change. A Web API binding and a separate projection keep the contract independent.
Outbound REST Calls from ABAP
A very common scenario in projects in Turkey runs in this direction: SAP calling the API of a carrier, a bank or an e-document provider. The example below sends a shipment to a carrier API. The address and credentials aren't in the code; they live in the HTTP destination in SM59:
TRY.
DATA(destination) = cl_http_destination_provider=>create_by_http_destination(
i_name = 'Z_CARRIER_API' ).
DATA(client) = cl_web_http_client_manager=>create_by_http_destination( destination ).
DATA(payload) = xco_cp_json=>data->from_abap( shipment
)->apply( VALUE #( ( xco_cp_json=>transformation->underscore_to_camel_case ) )
)->to_string( ).
DATA(request) = client->get_http_request( ).
request->set_uri_path( '/v1/shipments' ).
request->set_header_field( i_name = 'Content-Type' i_value = 'application/json' ).
" If the same shipment is sent twice, the other side must not create a second record
request->set_header_field( i_name = 'Idempotency-Key' i_value = shipment-shipment_id ).
request->set_text( payload ).
DATA(response) = client->execute( if_web_http_client=>post ).
DATA(status) = response->get_status( ).
DATA(body) = response->get_text( ).
client->close( ).
IF status-code <> 201.
log_error( external_id = shipment-shipment_id
text = |Carrier API returned { status-code }: { body }| ).
ENDIF.
CATCH cx_http_dest_provider_error cx_web_http_client_error INTO DATA(error).
log_error( external_id = shipment-shipment_id
text = error->get_text( ) ).
ENDTRY.The error is written not as a message that vanishes from the screen, but to the application log (SLG1). With the released BALI classes it takes a few lines; the log object (ZINTEGRATION) must be defined beforehand:
METHOD log_error.
TRY.
DATA(log) = cl_bali_log=>create_with_header(
cl_bali_header_setter=>create( object = 'ZINTEGRATION'
subobject = 'CARRIER'
external_id = CONV #( external_id ) ) ).
log->add_item( cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_error
text = CONV #( text ) ) ).
cl_bali_log_db=>get_instance( )->save_log( log = log ).
CATCH cx_bali_runtime.
" Even if the log can't be written, don't stop the actual work
ENDTRY.
ENDMETHOD.Three deliberate decisions in this example
Destination: URL, certificate and credentials live in configuration; test and production go to different addresses with the same code. Keeping the password in code or in a Z table is both a security and an audit problem. Idempotency key: on a network timeout the request may already have reached the other side; it prevents duplicates when you retry (if the remote API supports it). External ID: SLG1 can be searched by shipment number; support finds the error from the document.
Event-Driven Integration
Solving "when a request is approved, notify HR, payroll and the notification service" with three separate synchronous calls makes SAP dependent on all three systems being up. In the event-driven approach, SAP only publishes the "request approved" event; it doesn't know who is listening.
On current S/4HANA releases, the way to do this is RAP business events. The event is defined in the behavior definition:
define behavior for ZR_LeaveRequest alias LeaveRequest
// ... other definitions
{
event LeaveApproved;
}and raised in the save phase — when the data is actually being persisted. This is the with additional save scenario from the RAP guide:
METHOD save_modified.
RAISE ENTITY EVENT zr_leaverequest~LeaveApproved
FROM VALUE #( FOR request IN update-leaverequest
WHERE ( Status = 'A' AND %control-Status = if_abap_behv=>mk-on )
( %key = request-%key ) ).
ENDMETHOD.For the event to reach the outside world you need an event binding and an event broker (SAP Event Mesh, Advanced Event Mesh, or whichever broker your organisation uses). Raising the event in the save phase matters: if the transaction is rolled back, the event never goes out, and listeners don't react to an approval that doesn't exist.
Point-to-Point or Middleware?
With two systems and a single flow, a direct connection is usually enough and means fewer moving parts. Middleware (SAP Integration Suite, SAP PO or another integration platform) pays for itself when:
- The same data goes to several systems, each wanting a different format.
- Format mapping, routing rules or protocol translation (IDoc → REST, file → OData) are needed.
- You want to monitor, alert on and reprocess every flow from one place.
- You talk standard protocols such as EDI with external partners.
A note for organisations still on SAP PO: according to SAP's published maintenance schedule, mainstream maintenance for PO 7.5 ends at the end of 2027. Rather than growing new flows on PO, it makes sense to design them as part of a move to Integration Suite; confirm the current dates against SAP's maintenance strategy.
Error Handling and Monitoring
An integration's quality shows not when everything works but when something breaks. These four questions should be answered at design time:
1. Technical or business error?
Timeouts, connection errors, a 503 from the other side: retryable. A missing customer, a closed period, an invalid material: retrying won't help; someone has to fix the data. The two kinds of error should go to different queues and different people.
2. Is a retry safe?
If processing the same message twice creates a duplicate document, automatic retry just turns one error into another. A unique-key check on the receiving side or an idempotency key closes that risk.
3. How does the error reach someone?
An error written to the application log that nobody looks at is no different from an error never written. Either a monitoring screen is checked regularly, or critical errors go to the owner as email or alerts.
4. Can a document's journey be traced?
The SAP document number, the IDoc number, the remote system's reference and the log entry must be linked. If "did this order reach the other side?" requires searching several screens, hours are lost in the first serious incident.
| Technology | Monitoring | Reprocessing |
|---|---|---|
| IDoc | WE02, WE05 | BD87 |
| tRFC / qRFC | SM58, SMQ1, SMQ2 | From the same screens |
| bgRFC | SBGRFCMON | SBGRFCMON |
| Gateway / OData | /IWFND/ERROR_LOG, /IWFND/TRACES | On the client side |
| Custom HTTP calls | SLG1 (application log) | Whatever mechanism you design |
Note the last row: your own REST integrations have no reprocessing mechanism; you build it. A simple but effective approach is to write records that couldn't be sent to a table with their status and retry them with a periodic background job.
Quick Decision Table by Scenario
| Scenario | Recommended approach |
|---|---|
| A Fiori or web app reads and writes SAP data in real time | OData V4 (CDS + RAP) |
| An external system creates a document in SAP and expects the result immediately | Web API binding on RAP; BAPI over RFC between SAP systems |
| Master data distribution between SAP systems | IDoc / ALE |
| High-volume document flow, delay acceptable | IDoc or bgRFC; files at very high volume |
| SAP calls an external API (carrier, bank, e-document) | HTTP client + destination + application log |
| A change must be announced to several systems | RAP business event + event broker |
| Many systems, format mapping, central monitoring | Integration Suite (or existing middleware) |
Common Mistakes
Building synchronous chains
The user presses save, SAP calls system A, system A calls B. The slowest link sets the speed of the whole flow, the most fragile link its availability. If the user doesn't need the result immediately, break the chain with an asynchronous step.
Keeping credentials in code or a table
An API key written in code travels with every transport to every system and to everyone with source access. Credentials belong in SM59 destinations or communication arrangements, certificates in STRUST.
Measuring success by HTTP 200 alone
Some APIs return business errors in the body of a 200 response. Read the contract; check the result field in the response body as well as the status code.
Embedding the integration inside the screen
Making the external API call directly inside the user's save slows the SAP screen whenever the other side slows down, and puts the record itself at risk on failure. Save the document, and leave sending to a separate step (bgRFC, background job, event).
Connecting to a live API from a test system
A call from a test system to a live carrier or bank API can create a real shipment or a real payment instruction. Every environment needs its own destinations, and after a system copy, destinations should be the first item on the checklist.
Conclusion
There is no "best technology" in SAP integration; there is the technology that fits the scenario. IDocs are still the most traceable way to move documents, RFC is still the shortest route for immediate calls between SAP systems, OData is the way to open SAP to applications, the HTTP client the way to reach external APIs, and events the way to decouple systems.
What drives the choice are the questions asked before the technology: is the answer needed now, what happens if a message is lost or arrives twice, who does the error reach? Once those answers are clear, the technology choice usually follows on its own. You can find the scope I offer on integration projects on the integration services page.
Get support on integration architecture, reviewing existing flows and ABAP-side development.
Request an Initial Consultation