SAP Integration: RFC, OData, REST, IDoc — or Events?
SAP Integration

SAP Integration: RFC, OData, REST, IDoc — or Events?

If you've spent any time doing SAP integration work, you've almost certainly stared at a whiteboard asking yourself: should this be an RFC call, an OData service, a plain REST endpoint, an IDoc — or should it just be an event? In 2026, that question is more loaded than ever. S/4HANA, clean core mandates, and event-driven architectures have reshuffled the deck considerably. Let me walk you through how I think about this decision — not from a spec sheet, but from real projects.

A note on this update: after this piece went out, a few working SAP architects pushed back in the comments — correctly. The original version treated RFC as a one-way arrow out of SAP, and it skipped event-driven integration entirely. Both were real gaps. This version fixes them, and it's a better piece for it. Credit where it's due: that's exactly what technical writing should survive.

Why Choosing the Right SAP Integration Pattern Still Matters

Every integration pattern carries a different set of trade-offs: coupling, latency, error handling, transaction semantics, and tooling support. Picking the wrong one early means you're either refactoring six months later or building increasingly fragile workarounds. I've seen both. Neither is fun.

The good news is that the decision tree is actually quite manageable once you understand what each mechanism is really designed for, who has to support it on the other end, and where it breaks down under load or under change.

One framing mistake is worth naming up front: this is not a "pick one" decision. A single S/4HANA landscape will typically run RFC internally, OData for Fiori and partner APIs, IDoc for EDI, and events for real-time notification — all at once, all legitimately. The question isn't "which protocol wins," it's "which protocol fits this specific integration."

RFC: The Veteran That Still Has a Job

Remote Function Calls have been around since the R/3 days. They're synchronous, tightly coupled, and use SAP's proprietary ABAP-to-ABAP or JCo/NCo-based protocol.

Here's the detail that's easy to get wrong, and worth stating precisely: RFC is not something SAP "sends out" to any consumer that wants it — it's a two-sided contract. Both ends need to speak RFC, meaning the consumer needs the JCo (Java) or NCo (.NET) connector library, or needs to be another ABAP system entirely. If your "external consumer" is a modern microservice, a partner's REST API, or basically anything outside the SAP/JCo/NCo world, RFC is off the table before you even get to the architecture debate — not because it's a bad fit, but because the other side literally cannot speak the protocol. That's a harder constraint than a trade-off.

In 2026, my take is this: RFC is not dead, but its domain is shrinking, and it's shrinking specifically to the ABAP-to-ABAP corner it was built for.

When RFC still makes sense:

  • ABAP-to-ABAP calls within your own SAP landscape (e.g., ECC satellite calling S/4HANA hub)
  • Wrapping BAPIs that aren't yet exposed via OData or RAP
  • Legacy integration middleware (ALE, EDI converters) that already use RFC as a transport, and already has the JCo/NCo dependency in place

Where RFC hurts you:

  • Non-SAP consumers — anything outside the JCo/NCo library world becomes a non-starter, not just painful
  • Clean core — custom RFCs in S/4HANA Cloud go against the grain immediately
  • Firewall traversal — RFC ports are non-standard and often blocked in DMZ setups

If you're on S/4HANA and a colleague proposes a new RFC-based interface for a third-party system, check one thing first: can that system actually call RFC? If the answer is "we'd build a JCo bridge for it," that's the red flag — you're building infrastructure to work around the constraint, not working with it.

" Example: Calling a BAPI via RFC from ABAP
DATA: lt_return TYPE TABLE OF bapiret2.

CALL FUNCTION 'BAPI_MATERIAL_GETLIST'
  DESTINATION 'REMOTE_SYSTEM'
  TABLES
    matnrselection = lt_selection
    return         = lt_return
  EXCEPTIONS
    communication_failure = 1
    system_failure         = 2
    OTHERS                 = 3.

IF sy-subrc <> 0.
  " Handle the transport-level failure — this is separate
  " from any application-level error in lt_return below.
ENDIF.

IF line_exists( lt_return[ type = 'E' ] ).
  " Handle the application-level error
ENDIF.

Notice there are two error layers here, not one: the EXCEPTIONS block catches transport-level failures (the connection itself), and the RETURN table carries application-level errors. Teams that only check the return table and skip the EXCEPTIONS clause are the ones who get paged when the network blips and the job silently does nothing. That's a maintenance burden at scale, and it's avoidable.

OData: The Standard for UI-Facing and Structured APIs

OData (v2 and v4) is SAP's preferred HTTP-based protocol for structured data exchange, especially when the consumer is a Fiori app or any REST-capable client. If you're building or exposing data services in S/4HANA, OData is usually your first stop — and it's worth being precise about what OData actually is: a structured, metadata-driven convention built on top of REST, not a separate category next to it. That distinction matters for the next section.

OData v2 vs v4 — a quick reality check:

Feature OData v2 OData v4
Payload format JSON / XML (XML default) JSON (preferred)
SAP tooling SEGW gateway, legacy CDS RAP, modern CDS
Batch requests Yes (limited) Yes (improved)
Deep insert/update Limited First-class support
Recommended for new dev No (maintain only) Yes

If you're starting a new service today, go OData v4 via RAP. The ABAP RESTful Application Programming model gives you a clean, testable, annotation-driven path from CDS view to exposed service.

OData is not the right choice when:

  • You need high-throughput bulk data transfer (100k+ records) — pagination overhead kills you
  • You need fire-and-forget async messaging — OData is synchronous by nature
  • The consumer can't handle OData's metadata document convention
  • The integration is really a notification, not a data request — see Events, below

REST: Custom HTTP Services in ABAP

Here's where a lot of teams get confused, and where one of the sharper comments on this piece landed: OData is REST — it's the structured, contract-driven flavour of it. When people say "REST" in the SAP context as something distinct from OData, they usually mean custom HTTP handlers built with CL_REST_HTTP_HANDLER or the newer ICF-based approach, deliberately built without OData's metadata contract. So the real choice at this layer isn't "REST vs OData" — it's "structured REST (OData) vs unstructured REST (custom handlers)."

Custom REST services in ABAP give you full control over your URL design, payload schema, and HTTP verbs. That flexibility is both the draw and the danger.

When custom REST makes sense:

  • Event webhooks or callback endpoints (receiving inbound HTTP from external systems)
  • Lightweight status/health check APIs
  • Non-entity-based operations (trigger a process, not read/write a dataset)
  • When you want full JSON control without OData's metadata contract overhead
" Minimal ABAP REST handler skeleton (ICF-based)
CLASS zcl_rest_handler DEFINITION
  PUBLIC FINAL
  INHERITING FROM cl_rest_resource.

  PUBLIC SECTION.
    METHODS if_rest_resource~get REDEFINITION.
ENDCLASS.

CLASS zcl_rest_handler IMPLEMENTATION.
  METHOD if_rest_resource~get.
    DATA(lo_response) = mo_response.

    lo_response->set_status(
      cl_rest_status_code=>gc_success_ok ).

    lo_response->create_entity( )->set_string_data(
      '{"status":"ok","system":"S4H_PRD"}' ).
  ENDMETHOD.
ENDCLASS.

The downside: you lose SAP's metadata framework entirely. Documentation, versioning, and consumer discovery are now your problem. For internal use cases that's acceptable; for externally published APIs, OData v4 gives you better structure out of the box.

One practical note — if you're building AI-driven pipelines that call SAP over HTTP, custom REST endpoints are often the cleanest integration point, precisely because there's no metadata contract for the model to misinterpret.

IDoc: Async Messaging Done the SAP Way

IDocs (Intermediate Documents) are SAP's native asynchronous messaging format. They predate everything else on this list and are deeply embedded in ALE (Application Link Enabling) and EDI processes. In 2026 they're not trendy, but they're absolutely still in production at thousands of companies.

IDocs are the right tool when:

  • You need guaranteed delivery with built-in retry (WE05/BD87 monitoring)
  • You're doing EDI-based document exchange (orders, invoices, ASNs) via EDIFACT or X12
  • Integrating with legacy ECC systems that speak ALE natively
  • Decoupled posting is required — the sender doesn't wait for the receiver to finish

IDocs are the wrong tool when:

  • You need real-time bidirectional data exchange
  • Your partner is a modern microservice that speaks JSON
  • You want to avoid SAP-proprietary formats for clean core compliance
  • What you actually need is a lightweight notification, not a structured document — again, see Events

One thing teams often overlook: IDocs have excellent operational tooling. Error re-processing, status tracking, and volume monitoring are built in. For bulk async posting (goods movements, invoice batches), that operational transparency is genuinely valuable — even if the format feels dated.

Events: AMQP, SAP Event Mesh, and Standard Business Events

This is the gap in the original version of this piece, and it's a real one. Two readers flagged it independently, and they're both right: IDoc is not the only async option, and for new development it's often not the right one.

SAP's modern event-driven layer runs on AMQP (Advanced Message Queuing Protocol) via SAP Event Mesh (part of the BTP Integration Suite), and increasingly via Advanced Event Mesh for higher-throughput, broker-based pub/sub. On top of that transport, S/4HANA ships a growing catalog of Standard Business Events — pre-defined events fired by standard business objects (a sales order is created, a delivery is confirmed, a material's stock changes) that you subscribe to instead of building custom logic to detect.

This matters for clean core specifically: instead of writing a BAdI or an enhancement to notice that something happened and then calling out via RFC or a custom REST callback, you subscribe to a standard event. No custom code in the core system, no enhancement to maintain across upgrades — which is exactly what clean core asks for.

Events make sense when:

  • You need to notify multiple consumers about something happening, without SAP needing to know who they are (true decoupling — the sender doesn't hold a list of receivers)
  • The integration is a fact of something having happened, not a request for data or an action to perform
  • You're building near-real-time dashboards, alerting, or triggering downstream automation (including AI agents watching for specific business events)
  • You want to avoid polling — instead of an OData consumer checking "did anything change?" every 30 seconds, it gets told

Events are the wrong tool when:

  • You need a synchronous answer to a specific question — that's OData or REST
  • You need guaranteed, ordered, auditable document exchange with a trading partner — that's still IDoc/EDI territory
  • The consumer needs the full current state, not just a delta notification — events tell you that something changed, they're a poor fit for transferring the entire changed dataset

The practical pattern I use: fire a Standard Business Event over Event Mesh to say "sales order 4500001234 just changed," and let the consumer decide whether to pull the full detail via an OData v4 read. Event for the "what happened," OData for the "give me the details." Treating events as a replacement for IDoc-style document transfer, rather than a complement to request/response APIs, is the mistake to avoid here.

The Decision Matrix: Which One When

Scenario Recommended Approach
Fiori UI, entity CRUD OData v4 via RAP
Third-party REST consumer, structured data OData v4 or custom REST
ABAP-to-ABAP, existing BAPI RFC (with migration plan)
EDI / bulk async document exchange IDoc + ALE
Event trigger / webhook inbound Custom REST (ICF handler)
Notify multiple unknown consumers something happened SAP Event Mesh + Standard Business Events
AI/LLM calling SAP functions Custom REST or OData v4
New S/4HANA Cloud integration OData v4 + Events only (clean core)

What About Performance?

This comes up constantly. RFC is often cited as "faster" than HTTP-based protocols. That's partially true for small payloads and tightly coupled ABAP-to-ABAP calls — the serialization overhead is lower. But at scale, with proper HTTP/2, connection pooling, and server-side pagination, OData v4 holds up well. Event-driven flows sidestep the comparison entirely for the notification piece, since you're not polling in the first place.

The performance question that actually matters more: how does the underlying ABAP code perform? A poorly optimized RFC function module will be slower than a well-tuned OData service. For OData services specifically, the data retrieval layer (usually a CDS view) is where most bottlenecks live.

Versioning and Long-Term Maintainability

This is where I see the most technical debt accumulate. RFC function modules get copied and modified. IDoc extensions get stacked on top of each other. Custom REST endpoints diverge from any agreed-upon schema. Event payloads, if you're not careful, drift silently because nobody versions a notification the way they'd version an API.

OData v4 with RAP gives you the best story for long-term API governance: the behavior definition is versioned alongside your CDS artifacts, annotations drive the contract, and SAP's tooling enforces compatibility checks. Standard Business Events are versioned by SAP itself, which is a genuine advantage over rolling your own — one more reason to prefer them over custom-built notification logic.

Practical Recommendation for New Projects in 2026

If you're starting fresh today:

  • Default to OData v4 for any service that exposes business entities or supports a UI
  • Default to Standard Business Events over SAP Event Mesh for anything that's a notification rather than a request
  • Use custom REST for action-oriented or event-webhook endpoints where OData's entity model doesn't fit
  • Keep RFC for internal ABAP-to-ABAP where you own both sides and BAPIs aren't yet modernized
  • Retain IDocs for EDI and guaranteed-delivery async document scenarios — don't rewrite what's working
  • Avoid net-new RFC interfaces for any external consumer — the other side needs to speak RFC, and increasingly, it can't

The biggest mistake I see teams make is treating this as a purely technical decision. It's also an operational one. Ask yourself: who monitors failed messages? Who retries them? Who owns the schema contract with the consumer, or the event contract with the subscriber? The answers often point to the right pattern before you even look at throughput numbers.

Final Thoughts

There's no single winner in the RFC vs OData vs REST vs IDoc vs Events debate. Each mechanism exists because a specific set of requirements drove it into existence. Your job as an architect is to match pattern to context — not to pick a favourite and apply it everywhere, and not to assume the list of options is closed.

What I do know from experience: the projects that age well are the ones where the integration layer is explicit, monitored, and understood by more than one person. Whether that's an IDoc queue in BD87, an OData v4 endpoint with proper error propagation, or an event subscription with a clear owner, operational clarity beats technical elegance every time.

Further reading: for a concrete case study of these integration principles on the shop floor, see SAP MES Integration with PP/QM: Building a Real-Time Production Monitoring Architecture.