---
# === IDENTITY ===
id: business/erp-integration/sap-bapi-rfc-integration/2026
canonical_question: "What are SAP BAPIs and RFC types (sRFC, aRFC, tRFC, qRFC, bgRFC) and when to use each?"
aliases:
  - "SAP BAPI vs RFC function module differences"
  - "Which SAP RFC type should I use for integration — synchronous, transactional, or background?"
  - "How do SAP RFC connectors JCo NCo PyRFC work?"
  - "SAP BAPI commit and rollback patterns for external integration"
entity_type: erp_integration
domain: business > erp-integration > sap-bapi-rfc-integration
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "SAP S/4HANA"
    vendor: "SAP"
    version: "2023 FPS02 / 2024"
    edition: "On-Premise / Private Cloud"
    deployment: hybrid
    api_surface: "RFC (sRFC, aRFC, tRFC, qRFC, bgRFC)"
  - name: "SAP ECC 6.0"
    vendor: "SAP"
    version: "EHP8"
    edition: "All"
    deployment: on-premise
    api_surface: "RFC (sRFC, aRFC, tRFC, qRFC, bgRFC)"

# === VERIFICATION ===
last_verified: 2026-03-01
confidence: 0.92
version: 1.0
first_published: 2026-03-01

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: "SAP Note 2aborting 3 series — bgRFC replaces tRFC/qRFC as recommended default (NetWeaver 7.0+)"
  next_review: 2026-08-28
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "BAPIs require explicit BAPI_TRANSACTION_COMMIT — no auto-commit; forgetting this is the #1 integration bug"
  - "tRFC and qRFC are deprecated in favor of bgRFC for all new development (SAP NetWeaver 7.0+)"
  - "RFC connections require SAP system user with S_RFC authorization object — wildcard (*) values are a critical security risk"
  - "sRFC blocks the caller until the remote function returns — not suitable for high-latency or high-volume scenarios"
  - "SAP NW RFC SDK, JCo, NCo, and PyRFC all require a valid SAP license — no standalone redistribution allowed"
  - "Dialog work process limit: a single sRFC call occupies one dialog work process on the target system for its entire duration"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs SAP OData or REST API integration (S/4HANA Cloud)"
    use_instead: "business/erp-integration/sap-odata-rest-api/2026"
  - condition: "User needs IDoc-based EDI integration"
    use_instead: "business/erp-integration/sap-idoc-integration/2026"
  - condition: "User needs SAP Event Mesh or Cloud Events"
    use_instead: "business/erp-integration/sap-event-mesh/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: integration_pattern
    question: "What integration pattern do you need?"
    type: choice
    options:
      - "real-time sync (individual records, <1s latency)"
      - "batch/bulk (scheduled, high volume)"
      - "event-driven (webhook, CDC, platform events)"
      - "file-based (CSV/XML import/export)"
  - key: data_volume
    question: "What's your daily data volume?"
    type: choice
    options:
      - "< 1,000 records/day"
      - "1,000-100,000 records/day"
      - "> 100,000 records/day"
  - key: direction
    question: "What's the data flow direction?"
    type: choice
    options:
      - "inbound (writing to SAP)"
      - "outbound (reading from SAP)"
      - "bidirectional sync"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/sap-bapi-rfc-integration/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-01)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "business/erp-integration/sap-odata-rest-api/2026"
      label: "SAP OData and REST API for S/4HANA Cloud"
    - id: "business/erp-integration/sap-idoc-integration/2026"
      label: "SAP IDoc-based EDI integration"
  solves: []
  alternative_to:
    - id: "business/erp-integration/sap-odata-rest-api/2026"
      label: "OData API — preferred for S/4HANA Cloud public edition"
  often_confused_with:
    - id: "business/erp-integration/sap-idoc-integration/2026"
      label: "IDocs use a different transport layer and are document-oriented, not function-oriented"

# === SOURCES (8 authoritative sources) ===
sources:
  - id: src1
    title: "RFC Variants — SAP Help Portal"
    author: SAP
    url: https://help.sap.com/doc/saphelp_nw73ehp1/7.31.19/en-US/48/99b53cee2b73e7e10000000a42189b/content.htm
    type: official_docs
    published: 2024-01-15
    reliability: authoritative
  - id: src2
    title: "SAP Java Connector (JCo) — SAP Support Portal"
    author: SAP
    url: https://support.sap.com/en/product/connectors/jco.html
    type: official_docs
    published: 2025-05-28
    reliability: authoritative
  - id: src3
    title: "SAP BAPI Transactions Walkthrough — Microsoft Tech Community"
    author: Microsoft
    url: https://techcommunity.microsoft.com/blog/integrationsonazureblog/sap-bapi-transactions-walkthrough/1772148
    type: technical_blog
    published: 2020-11-12
    reliability: high
  - id: src4
    title: "BAPI_TRANSACTION_COMMIT versus COMMIT WORK — SAP Help"
    author: SAP
    url: https://help.sap.com/docs/SUPPORT_CONTENT/abap/3353526184.html
    type: official_docs
    published: 2023-06-01
    reliability: authoritative
  - id: src5
    title: "Understanding Different Types of RFC Calls in SAP ABAP — SAP Community"
    author: SAP Community
    url: https://community.sap.com/t5/application-development-and-automation-blog-posts/understanding-different-types-of-rfc-calls-in-sap-abap/ba-p/13745585
    type: community_resource
    published: 2024-03-15
    reliability: moderate_high
  - id: src6
    title: "bgRFC Advantages over tRFC and qRFC — SAP Community"
    author: SAP Community
    url: https://community.sap.com/t5/application-development-and-automation-discussions/bgrfc-advantages-over-trfc-and-qrfc/m-p/10574954
    type: community_resource
    published: 2023-09-20
    reliability: moderate_high
  - id: src7
    title: "Technical Analysis of Optimizing tRFC and qRFC Using bgRFC — Oreate AI Blog"
    author: Oreate AI
    url: https://www.oreateai.com/blog/technical-analysis-of-optimizing-trfc-and-qrfc-calls-in-sap-systems-using-bgrfc/b7ee54449025ac08b1eba9d65e5c1556
    type: technical_blog
    published: 2025-01-10
    reliability: moderate_high
  - id: src8
    title: "Best Practice — How to Analyze and Secure RFC Connections — SAP Wiki"
    author: SAP
    url: https://wiki.scn.sap.com/wiki/display/Security/Best+Practice+-+How+to+analyze+and+secure+RFC+connections
    type: official_docs
    published: 2024-02-01
    reliability: high
---

# SAP BAPIs and RFC Integration

## TL;DR

- **Bottom line**: BAPIs are SAP's stable, business-object-oriented API layer built on top of RFC. Use bgRFC for all new asynchronous/transactional integrations; sRFC only for real-time lookups requiring immediate response. [src1]
- **Key limit**: sRFC blocks one dialog work process per call for the entire duration; tRFC/qRFC are deprecated — migrate to bgRFC which offers 40% better throughput via parallel queue scheduling. [src1, src7]
- **Watch out for**: Forgetting to call BAPI_TRANSACTION_COMMIT after BAPI calls — without it, no data persists. BAPI_TRANSACTION_ROLLBACK cannot reverse a previous commit. [src3, src4]
- **Best for**: System-to-system integration with SAP ECC or S/4HANA on-premise/private cloud where OData is not available or ABAP function modules are the primary interface.
- **Authentication**: RFC connections use SAP system user credentials (user/password or SNC certificate) via SM59 destination configuration; authorize with S_RFC object. [src8]

## System Profile

This card covers SAP's Business Application Programming Interface (BAPI) and Remote Function Call (RFC) integration layer, applicable to both SAP ECC 6.0 (all EHP levels) and SAP S/4HANA on-premise/private cloud editions. BAPIs are methods of SAP Business Objects defined in the Business Object Repository (BOR, transaction BAPI/SWO1) that wrap RFC-enabled function modules with standardized interfaces, stable naming, and guaranteed backward compatibility. [src1, src5]

RFC is the underlying transport protocol. Five variants exist: synchronous (sRFC), asynchronous (aRFC), transactional (tRFC), queued (qRFC), and background (bgRFC). This card does NOT cover SAP Cloud Integration Suite, SAP BTP destinations, or S/4HANA Cloud public edition APIs (which use OData/REST exclusively).

| Property | Value |
|---|---|
| **Vendor** | SAP |
| **System** | SAP S/4HANA 2023/2024 + SAP ECC 6.0 EHP8 |
| **API Surface** | RFC (sRFC, aRFC, tRFC, qRFC, bgRFC) + BAPIs |
| **Current API Version** | SAP NetWeaver RFC SDK 7.50+ / JCo 3.1 / NCo 3.1 / PyRFC 3.x |
| **Editions Covered** | All on-premise and private cloud editions |
| **Deployment** | On-Premise / Private Cloud / Hybrid |
| **API Docs URL** | [SAP Help — RFC Variants](https://help.sap.com/doc/saphelp_nw73ehp1/7.31.19/en-US/48/99b53cee2b73e7e10000000a42189b/content.htm) |
| **Status** | GA (bgRFC recommended; tRFC/qRFC maintenance-only) |

## API Surfaces & Capabilities

BAPIs are the application-level API; RFC variants are the transport-level protocol beneath them. Choosing the right RFC variant is critical. [src1, src5]

| RFC Variant | Protocol | Best For | Delivery Guarantee | Ordering | Real-time? | Target Availability Required? |
|---|---|---|---|---|---|---|
| **sRFC** (Synchronous) | RFC/CPIC or WebSocket | Real-time lookups, immediate-response operations | None (call fails if target down) | N/A | Yes | Yes — both systems must be online |
| **aRFC** (Asynchronous) | RFC/CPIC | Parallel processing, non-critical background calls | None (lost if target unreachable) | No | Partial | Yes — target must be reachable at call time |
| **tRFC** (Transactional) | RFC/CPIC | Exactly-once delivery (legacy) | Exactly-once via TID | No | No | No — queued in sender DB |
| **qRFC** (Queued) | RFC/CPIC | Ordered exactly-once delivery (legacy) | Exactly-once + FIFO | Yes (per queue) | No | No — queued in sender DB |
| **bgRFC** (Background) | RFC/CPIC or WebSocket | All new async/transactional work (replaces tRFC+qRFC) | Exactly-once, optional FIFO | Configurable | No | No — queued in sender DB |

[src1, src5, src6]

## Rate Limits & Quotas

RFC does not have API call quotas like REST APIs. Instead, limits are defined by system resources — dialog work processes, memory, and RFC connection parameters. [src1]

### Per-Request Limits

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Dialog work process time | 600s default (parameter rdisp/max_wprun_time) | sRFC calls | Exceeded = TIME_OUT dump; adjust in profile parameters |
| Maximum RFC connections | Configurable per destination (SM59) | All RFC types | Default varies by system sizing |
| Memory per work process | Extended memory (em/initial_size_MB) + heap | sRFC, aRFC | Large BAPI payloads can exhaust work process memory |
| tRFC/qRFC payload size | Stored in ARFCSSTATE/ARFCSDATA tables | tRFC, qRFC | Large volumes bloat database; monitor with SM58 |
| bgRFC unit size | Stored in BGRFC* tables | bgRFC | More efficient storage than tRFC tables |

[src1, src7]

### System Resource Limits

| Limit Type | Value | Window | Configuration |
|---|---|---|---|
| Dialog work processes | Typically 10-40 per app server | Concurrent | Profile parameter rdisp/wp_no_dia; each sRFC occupies one |
| RFC connection pool | Configurable per JCo/NCo destination | Concurrent | JCo: jco.destination.pool_capacity (default 1) |
| bgRFC scheduler threads | Configurable per application server | Per scheduler | Transaction SBGRFCCONF; multiple schedulers supported |
| SM58 stuck entries | N/A | Rolling | tRFC entries stuck >24h indicate connectivity issues |

[src1, src2, src7]

### Transaction / Governor Limits

| Limit Type | Per-Transaction Value | Notes |
|---|---|---|
| Dialog step timeout | 600s (configurable) | sRFC runs within a dialog step — long-running calls hit this |
| Max internal tables size | Limited by extended memory allocation | BAPIs returning large datasets can cause STORAGE_PARAMETERS_WRONG_SET |
| Commit work frequency | 1 per LUW (logical unit of work) | Multiple BAPIs in one LUW require a single BAPI_TRANSACTION_COMMIT at end |
| RFC callback depth | No hard limit, but recursive RFC calls consume work processes | Avoid circular RFC patterns that exhaust dialog processes |

[src1, src4]

## Authentication

RFC authentication is configured at the SAP system level via SM59 (RFC destination maintenance) and is fundamentally different from token-based REST authentication. [src8]

| Method | Use When | Security Level | MFA Support | Notes |
|---|---|---|---|---|
| **User/Password** | Development, testing | Low | No | Stored in SM59 destination; visible to admins |
| **SNC (Secure Network Communication)** | Production — all environments | High | Via PKI | X.509 certificates; snc/only_encrypted_rfc=1 to enforce |
| **Trusted RFC (SMT1/SMT2)** | SAP-to-SAP system communication | Medium-High | N/A | S_RFCACL authorization required; avoid wildcard values |
| **SSO via Kerberos/SPNEGO** | Windows domain environments | High | Via domain | Requires SAP Secure Login Server or CommonCryptoLib |

[src8]

### Authentication Gotchas

- **S_RFC wildcard authorization is a critical security risk**: Many systems still have S_RFC = * which grants access to ALL remote-enabled function modules. Use UCON (Unified Connectivity) enforcement mode to whitelist only required function modules. [src8]
- **SNC certificate mismatch silently downgrades to unencrypted**: If snc/only_encrypted_rfc is not set to 1, failed SNC negotiation falls back to plaintext — you won't notice until an audit. [src8]
- **Service user password expiration breaks integrations**: Use system users (type B) for RFC connections — they don't expire. Dialog users (type A) have password policies that will break unattended integrations. [src8]
- **Trusted RFC (S_RFCACL) with wildcards enables privilege escalation**: An attacker on a trusted system can impersonate any user. Define exact user mappings. [src8]

## Constraints
<!-- Agents: read this section before recommending any integration approach from this unit.
     These are hard constraints that must not be violated. -->

- **BAPI_TRANSACTION_COMMIT is mandatory**: No BAPI call persists data without an explicit commit. This is not auto-committed like REST APIs. Forgetting it is the #1 BAPI integration bug. [src3, src4]
- **tRFC and qRFC are deprecated**: SAP recommends bgRFC for all new development since NetWeaver 7.0 (2004s). tRFC/qRFC remain functional but receive no performance improvements. [src1, src6]
- **sRFC blocks caller and target work process**: Unsuitable for high-volume or high-latency scenarios. Each concurrent sRFC call ties up one dialog work process on both sender and receiver. [src1]
- **RFC SDK licensing**: SAP NW RFC SDK, JCo 3.1, NCo 3.1, and PyRFC require a valid SAP license. They cannot be redistributed or bundled in open-source projects without SAP's permission. [src2]
- **BAPI_TRANSACTION_ROLLBACK cannot undo a prior commit**: If you call COMMIT after step 1 and ROLLBACK after step 2, step 1 remains committed. Structure all steps in a single LUW. [src3, src4]
- **No native webhook/push from RFC**: RFC is pull-based. For event-driven patterns, combine with SAP Event Mesh, ALE/IDocs, or bgRFC with custom scheduling. [src1]

## Integration Pattern Decision Tree

```
START — User needs to integrate with SAP via BAPI/RFC
|
+-- What's the integration pattern?
|   |
|   +-- Real-time (individual records, <1s latency)
|   |   +-- Need immediate response (read/lookup)?
|   |   |   +-- YES --> sRFC: call BAPI directly, get RETURN immediately
|   |   |   +-- NO --> bgRFC with high-priority queue (if fire-and-forget OK)
|   |   +-- Need to write data with confirmation?
|   |       +-- YES --> sRFC: call BAPI + check RETURN + BAPI_TRANSACTION_COMMIT
|   |       +-- NO --> bgRFC unit with commit bundled
|   |
|   +-- Batch/Bulk (scheduled, high volume)
|   |   +-- Records < 1,000 per batch?
|   |   |   +-- YES --> sRFC loop with commit per batch (simple)
|   |   |   +-- NO --> bgRFC units with parallel queues (40% faster than tRFC)
|   |   +-- Need guaranteed ordering?
|   |       +-- YES --> bgRFC with single named queue (FIFO)
|   |       +-- NO --> bgRFC with multiple parallel queues
|   |
|   +-- Event-driven
|   |   +-- SAP triggers the call?
|   |   |   +-- YES --> bgRFC outbound from SAP to registered RFC server
|   |   |   +-- NO --> Not native RFC — use SAP Event Mesh or IDoc
|   |   +-- Need exactly-once delivery?
|   |       +-- YES --> bgRFC (replaces tRFC exactly-once semantics)
|   |       +-- NO --> aRFC (but data lost if target unreachable)
|   |
|   +-- File-based
|       +-- Not applicable to RFC/BAPI — use IDoc, FBDI, or BW extractors
|
+-- Which connector?
|   +-- Java application --> SAP JCo 3.1
|   +-- .NET application --> SAP NCo 3.1
|   +-- Python application --> PyRFC 3.x (via SAP NW RFC SDK)
|   +-- Node.js application --> node-rfc (archived) or SAP Cloud SDK
|   +-- Other language --> SAP NW RFC SDK (C/C++ library with bindings)
|
+-- Error tolerance?
    +-- Zero-loss required --> bgRFC + monitor with SBGRFCMON + dead letter handling
    +-- Best-effort --> aRFC (fastest, no persistence)
```

## Quick Reference

### Common BAPIs for Integration

| BAPI | Module | Operation | Key Parameters | Notes |
|---|---|---|---|---|
| BAPI_SALESORDER_CREATEFROMDAT2 | SD | Create sales order | ORDER_HEADER_IN, ORDER_ITEMS_IN, ORDER_PARTNERS | Most-used SD BAPI; requires BAPI_TRANSACTION_COMMIT |
| BAPI_PO_CREATE1 | MM | Create purchase order | POHEADER, POITEM, POSCHEDULE | Replaces older BAPI_PO_CREATE; supports all item categories |
| BAPI_MATERIAL_SAVEDATA | MM | Create/change material master | HEADDATA, CLIENTDATA, PLANTDATA | Single BAPI for create + change; set CLIENTDATAX flags for changes |
| BAPI_CUSTOMER_CREATEFROMDATA1 | SD/FI | Create customer master | PI_PERSONALDATA, PI_COPYREFERENCE | Returns CUSTOMERNO on success |
| BAPI_GOODSMVT_CREATE | MM | Goods movement (receipt/issue) | GOODSMVT_HEADER, GOODSMVT_ITEM | Movement type in GM_CODE determines operation |
| BAPI_ACC_DOCUMENT_POST | FI | Post accounting document | DOCUMENTHEADER, ACCOUNTGL, CURRENCYAMOUNT | Replaces direct FB01 posting for integrations |
| BAPI_EMPLOYEE_GETDATA | HR | Read employee master data | EMPLOYEE_ID, TIMEFRAME | Read-only; no commit needed |
| BAPI_COMPANYCODE_GETLIST | FI | List company codes | (none) | Useful for initial configuration/validation |
| BAPI_TRANSACTION_COMMIT | Cross | Commit BAPI transaction | WAIT = 'X' for synchronous commit | ALWAYS call after write BAPIs; WAIT='X' recommended for integrations |
| BAPI_TRANSACTION_ROLLBACK | Cross | Rollback BAPI transaction | (none) | Only rolls back uncommitted changes in current LUW |

[src3, src4, src5]

### RFC Variant Quick Comparison

| Feature | sRFC | aRFC | tRFC | qRFC | bgRFC |
|---|---|---|---|---|---|
| Delivery guarantee | None | None | Exactly-once | Exactly-once + FIFO | Exactly-once, optional FIFO |
| Target must be online | Yes | Yes | No | No | No |
| Caller blocked | Yes | No | No | No | No |
| Data persisted before send | No | No | Yes (TID in DB) | Yes (queue in DB) | Yes (unit in DB) |
| Ordering guaranteed | N/A | No | No | Yes (per queue) | Configurable (per queue) |
| SAP recommended for new dev | Yes (reads) | Limited | No (deprecated) | No (deprecated) | Yes (all async) |
| Monitoring transaction | SM58 | SM58 | SM58 | SMQ1/SMQ2 | SBGRFCMON |

[src1, src5, src6]

## Step-by-Step Integration Guide

### 1. Configure RFC Destination (SM59)

Create an RFC destination in the SAP system to define the connection parameters for external systems. This is the foundation of all RFC communication. [src1]

```
Transaction: SM59
1. Create new destination → Type: T (TCP/IP) for external programs, or Type: 3 for SAP-to-SAP
2. Set connection parameters:
   - Activation Type: "Registered Server Program" (for external RFC servers)
   - Program ID: Must match the program ID your external application registers with
3. Test connection → green light = success
4. For SNC: Technical Settings tab → set SNC partner name and QoP level
```

**Verify**: SM59 → select destination → "Connection Test" button → expected: green status, round-trip time displayed

### 2. Call a BAPI via sRFC with JCo (Java)

Use SAP JCo 3.1 to invoke a BAPI synchronously from a Java application. JCo handles connection pooling, data type conversion, and RFC protocol details. [src2]

```java
// Input:  JCo destination configured in jcoDestination properties file
// Output: List of company codes from SAP

import com.sap.conn.jco.*;

// Step 1: Get destination (reads from {destName}.jcoDestination file)
JCoDestination destination = JCoDestinationManager.getDestination("SAP_SYSTEM");

// Step 2: Get function template from SAP metadata
JCoFunction function = destination.getRepository()
    .getFunction("BAPI_COMPANYCODE_GETLIST");
if (function == null) throw new RuntimeException("BAPI not found in SAP");

// Step 3: Execute synchronous RFC call
function.execute(destination);

// Step 4: Read RETURN parameter for errors
JCoStructure returnStructure = function.getExportParameterList()
    .getStructure("RETURN");
if ("E".equals(returnStructure.getString("TYPE"))) {
    throw new RuntimeException("BAPI error: " + returnStructure.getString("MESSAGE"));
}

// Step 5: Process results table
JCoTable companyCodes = function.getTableParameterList()
    .getTable("COMPANYCODE_LIST");
for (int i = 0; i < companyCodes.getNumRows(); i++) {
    companyCodes.setRow(i);
    System.out.println(companyCodes.getString("COMP_CODE") + " - "
        + companyCodes.getString("COMP_NAME"));
}
```

**Verify**: Run application → expected: list of company codes printed; no exceptions

### 3. Call a Write BAPI with Commit Pattern

Write BAPIs require explicit BAPI_TRANSACTION_COMMIT. Never call COMMIT WORK directly when using BAPIs — it skips BAPI-specific buffer refresh logic (BUFFER_REFRESH_ALL). [src3, src4]

```java
// Input:  Sales order header and line item data
// Output: Sales order number or error messages

JCoDestination dest = JCoDestinationManager.getDestination("SAP_SYSTEM");

// Step 1: Prepare the BAPI call
JCoFunction createSO = dest.getRepository()
    .getFunction("BAPI_SALESORDER_CREATEFROMDAT2");

// Set header data
JCoStructure header = createSO.getImportParameterList()
    .getStructure("ORDER_HEADER_IN");
header.setValue("DOC_TYPE", "TA");     // Standard order
header.setValue("SALES_ORG", "1000");
header.setValue("DISTR_CHAN", "10");
header.setValue("DIVISION", "00");

// Set line items
JCoTable items = createSO.getTableParameterList()
    .getTable("ORDER_ITEMS_IN");
items.appendRow();
items.setValue("ITM_NUMBER", "000010");
items.setValue("MATERIAL", "MAT-001");
items.setValue("TARGET_QTY", "10");

// Step 2: Execute the BAPI
createSO.execute(dest);

// Step 3: Check RETURN for errors BEFORE committing
JCoTable returnTable = createSO.getTableParameterList()
    .getTable("RETURN");
boolean hasErrors = false;
for (int i = 0; i < returnTable.getNumRows(); i++) {
    returnTable.setRow(i);
    String msgType = returnTable.getString("TYPE");
    if ("E".equals(msgType) || "A".equals(msgType)) {
        hasErrors = true;
        System.err.println("Error: " + returnTable.getString("MESSAGE"));
    }
}

// Step 4: Commit or Rollback
if (!hasErrors) {
    JCoFunction commit = dest.getRepository()
        .getFunction("BAPI_TRANSACTION_COMMIT");
    commit.getImportParameterList().setValue("WAIT", "X"); // Synchronous commit
    commit.execute(dest);
    String orderNumber = createSO.getExportParameterList()
        .getString("SALESDOCUMENT");
    System.out.println("Order created: " + orderNumber);
} else {
    JCoFunction rollback = dest.getRepository()
        .getFunction("BAPI_TRANSACTION_ROLLBACK");
    rollback.execute(dest);
    throw new RuntimeException("BAPI errors — transaction rolled back");
}
```

**Verify**: SE16 → table VBAK → expected: new sales order number visible with correct header data

### 4. Implement bgRFC for Guaranteed Async Delivery

Use bgRFC when you need exactly-once delivery without blocking the caller. bgRFC replaces tRFC and qRFC with better performance and monitoring. [src1, src6, src7]

```abap
" ABAP: Send a function call via bgRFC with guaranteed delivery
" Input:  Function module name and parameters
" Output: bgRFC unit ID for tracking

DATA: lo_dest    TYPE REF TO if_bgrfc_destination_outbound,
      lo_unit    TYPE REF TO if_bgrfc_unit_outbound,
      lv_unit_id TYPE bgrfc_unit_id.

" Step 1: Get bgRFC destination (configured in SBGRFCCONF)
lo_dest = cl_bgrfc_destination_outbound=>create( 'RFC_DESTINATION_NAME' ).

" Step 2: Create a bgRFC unit (equivalent to tRFC TID)
lo_unit = lo_dest->create_trfc_unit( ).  " Use create_qrfc_unit( queue_name ) for ordered delivery
lv_unit_id = lo_unit->unit_id.

" Step 3: Call function module within the bgRFC unit
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
  IN BACKGROUND UNIT lo_unit
  EXPORTING
    order_header_in = ls_header
  TABLES
    order_items_in  = lt_items
    order_partners  = lt_partners
    return          = lt_return.

" Step 4: The unit is persisted to DB on next COMMIT WORK
COMMIT WORK.

" The bgRFC scheduler will deliver the unit when target is available
WRITE: / 'bgRFC unit submitted:', lv_unit_id.
```

**Verify**: SBGRFCMON → expected: unit ID visible with status "Executed" or "Waiting" (if target offline)

## Code Examples

### Python: Read Material Master via PyRFC

```python
# Input:  SAP connection parameters, material number
# Output: Material description and base unit of measure

# Requires: pyrfc>=3.3 + SAP NW RFC SDK installed
from pyrfc import Connection

# Connection parameters (use sapnwrfc.ini or environment variables in production)
conn = Connection(
    ashost='sap-server.example.com',
    sysnr='00',
    client='100',
    user='RFC_USER',
    passwd='secure_password',  # Use SNC in production instead
    lang='EN'
)

# Call BAPI — sRFC (synchronous, blocking)
result = conn.call('BAPI_MATERIAL_GETDETAIL', MATERIAL='MAT-001', PLANT='1000')

# Check RETURN structure for errors
ret = result.get('RETURN', {})
if ret.get('TYPE') == 'E':
    raise RuntimeError(f"BAPI error: {ret['MESSAGE']}")

# Extract material data
mat_desc = result['MATERIAL_GENERAL_DATA']['MATL_DESC']
base_uom = result['MATERIAL_GENERAL_DATA']['BASE_UOM']
print(f"Material: {mat_desc}, UoM: {base_uom}")

conn.close()
```

### JavaScript/Node.js: Call BAPI via node-rfc

```javascript
// Input:  SAP connection parameters
// Output: List of company codes
// Requires: node-rfc@3.x + SAP NW RFC SDK

const noderfc = require('node-rfc');

const client = new noderfc.Client({
    ashost: 'sap-server.example.com',
    sysnr: '00',
    client: '100',
    user: 'RFC_USER',
    passwd: 'secure_password',
    lang: 'EN'
});

async function getCompanyCodes() {
    try {
        await client.open();

        // sRFC call — blocks until SAP responds
        const result = await client.call('BAPI_COMPANYCODE_GETLIST', {});

        // Check RETURN
        if (result.RETURN?.TYPE === 'E') {
            throw new Error(`BAPI error: ${result.RETURN.MESSAGE}`);
        }

        // Process results
        for (const cc of result.COMPANYCODE_LIST) {
            console.log(`${cc.COMP_CODE} — ${cc.COMP_NAME}`);
        }
    } finally {
        await client.close();
    }
}

getCompanyCodes().catch(console.error);
```

### cURL: N/A — RFC is not HTTP-based

```
RFC is a binary protocol, not HTTP. You cannot use cURL to call BAPIs directly.

For HTTP-based SAP integration:
- Use SAP API Business Hub (api.sap.com) with OData/REST
- Use SAP Cloud Connector + BTP Destination for RFC-over-HTTP tunneling
- Use SAP Gateway (transaction SEGW) to expose BAPIs as OData services
```

## Data Mapping

### BAPI Parameter Structure Reference

| Parameter Type | ABAP Type | Direction | Example | Notes |
|---|---|---|---|---|
| IMPORT | Scalar/Structure | In | ORDER_HEADER_IN | Single values or flat structures passed to BAPI |
| EXPORT | Scalar/Structure | Out | SALESDOCUMENT | Return values from BAPI |
| TABLES | Internal Table | In/Out | ORDER_ITEMS_IN, RETURN | Tabular data; RETURN table contains error messages |
| CHANGING | Structure | In/Out | (rare in BAPIs) | Modified by the BAPI and returned |

### BAPI RETURN Structure (BAPIRET2)

| Field | Type | Values | Purpose |
|---|---|---|---|
| TYPE | CHAR 1 | S=Success, E=Error, W=Warning, I=Info, A=Abort | Message severity — check for E or A before commit |
| ID | CHAR 20 | Message class (e.g., 'V1') | SAP message class for lookup in SE91 |
| NUMBER | NUMC 3 | Message number (e.g., '311') | Combined with ID for unique message identification |
| MESSAGE | CHAR 220 | Human-readable text | The actual error/success message |
| LOG_NO | CHAR 20 | Application log number | For detailed error investigation via SLG1 |
| MESSAGE_V1-V4 | CHAR 50 | Variable replacements | Dynamic parts of the message text |

[src3, src5]

### Data Type Gotchas

- **SAP dates are CHAR 8 (YYYYMMDD), not ISO 8601**: Convert '20260301' to '2026-03-01' in your middleware. Empty date in SAP = '00000000', not null. [src5]
- **SAP amounts are stored without decimal places in some BAPIs**: Check the CURRENCY field to determine decimal positioning. JPY has 0 decimals; USD has 2. Use BAPI_CURRENCY_CONV_TO_EXTERNAL for safe conversion. [src5]
- **SAP internal character encoding is non-Unicode on some older systems**: Verify your target system's code page (transaction SM21). JCo/NCo handle conversion automatically; raw RFC SDK requires manual handling. [src2]
- **Leading zeros in SAP IDs**: Material numbers, customer numbers, and vendor numbers have leading zeros (e.g., '0000001000'). Use CONVERSION_EXIT_ALPHA_INPUT/OUTPUT or BAPI_CONVERSION functions. [src5]

## Error Handling & Failure Points

### Common Error Codes

| Error | Meaning | Cause | Resolution |
|---|---|---|---|
| COMMUNICATION_FAILURE | Cannot reach SAP system | Network issue, SAP system down, wrong hostname/port | Check SM59 connection test; verify network; check SAP dispatcher (sapcontrol) |
| SYSTEM_FAILURE | ABAP runtime error on target | Short dump in SAP — division by zero, type mismatch, etc. | Check ST22 on target system for short dump details |
| RFC_ERROR_LOGON_FAILURE | Authentication failed | Wrong user/password, locked user, expired password | Check SU01 user status; use system user type B for integrations |
| TABLE_ENTRIES_EXCEED_LIMIT | Too much data returned | BAPI query returns more rows than internal table limit | Add filter parameters to restrict result set; paginate |
| BAPI RETURN TYPE='E' | Business logic error | Invalid data, missing required fields, authorization failure | Read MESSAGE field; fix input data; check SU53 for missing authorizations |
| RFC_ERROR_SYSTEM_NOT_AVAILABLE | System unreachable during tRFC/bgRFC | Target system down when scheduler tries delivery | Entries remain in queue; check SBGRFCMON or SM58; will auto-retry |

[src1, src2, src5]

### Failure Points in Production

- **Missing BAPI_TRANSACTION_COMMIT**: Data appears to save (no error in RETURN) but disappears after dialog step ends. Fix: `Always call BAPI_TRANSACTION_COMMIT with WAIT='X' after checking RETURN for errors`. [src3, src4]
- **tRFC queue buildup (SM58 stuck entries)**: Thousands of stuck tRFC entries consume database space and degrade performance. Fix: `Migrate to bgRFC (SBGRFCCONF); bgRFC uses more efficient storage and parallel schedulers`. [src6, src7]
- **Connection pool exhaustion in JCo**: Under load, all pooled connections are used and new requests fail with JCoException. Fix: `Set jco.destination.peak_limit > pool_capacity; implement connection timeout (jco.destination.expiration_time)`. [src2]
- **SNC certificate expiration breaks all RFC connections**: Integration stops silently when the X.509 certificate used for SNC expires. Fix: `Monitor certificate expiry with STRUST; set calendar reminders 30 days before expiration; use certificate auto-renewal where possible`. [src8]
- **Partial commit in multi-BAPI transactions**: Calling BAPI_TRANSACTION_COMMIT between BAPIs means a later failure cannot roll back earlier commits. Fix: `Call ALL BAPIs first, check ALL RETURN tables, then issue a single COMMIT or ROLLBACK for the entire LUW`. [src3, src4]
- **aRFC data loss**: aRFC calls to an unreachable system are silently lost — no error, no retry. Fix: `Never use aRFC for business-critical data; use bgRFC instead for guaranteed delivery`. [src1]

## Anti-Patterns

### Wrong: Calling COMMIT WORK instead of BAPI_TRANSACTION_COMMIT

```abap
" BAD — COMMIT WORK skips BAPI buffer refresh logic
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2' ...
COMMIT WORK.  " <-- Missing BUFFER_REFRESH_ALL, stale buffers
```

### Correct: Always use BAPI_TRANSACTION_COMMIT

```abap
" GOOD — BAPI_TRANSACTION_COMMIT calls BUFFER_REFRESH_ALL internally
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2' ...
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
  EXPORTING WAIT = 'X'.  " Synchronous — waits for DB commit
```

[src4]

### Wrong: Committing inside a loop of BAPI calls

```java
// BAD — each iteration is a separate LUW; cannot rollback on later failure
for (Item item : items) {
    function.execute(destination);           // Call BAPI
    commitFunction.execute(destination);     // COMMIT per item -- WRONG
}
```

### Correct: Batch all calls, single commit at end

```java
// GOOD — all items in one LUW; single commit/rollback decision
boolean hasErrors = false;
for (Item item : items) {
    function.execute(destination);
    if (checkReturnForErrors(function)) { hasErrors = true; break; }
}
if (!hasErrors) {
    commitFunction.execute(destination);     // Single commit for all
} else {
    rollbackFunction.execute(destination);   // Rollback everything
}
```

[src3, src4]

### Wrong: Using tRFC for new integration projects

```abap
" BAD — tRFC is deprecated; single scheduler, poor performance
CALL FUNCTION 'Z_SEND_ORDER'
  IN BACKGROUND TASK
  DESTINATION 'TARGET_SYSTEM'
  ...
COMMIT WORK.
```

### Correct: Use bgRFC for all new async integrations

```abap
" GOOD — bgRFC: multiple schedulers, parallel queues, 40% better throughput
DATA(lo_dest) = cl_bgrfc_destination_outbound=>create( 'TARGET_SYSTEM' ).
DATA(lo_unit) = lo_dest->create_trfc_unit( ).  " or create_qrfc_unit( ) for ordering
CALL FUNCTION 'Z_SEND_ORDER'
  IN BACKGROUND UNIT lo_unit
  DESTINATION 'TARGET_SYSTEM'
  ...
COMMIT WORK.
```

[src6, src7]

## Common Pitfalls

- **Forgetting WAIT='X' on BAPI_TRANSACTION_COMMIT**: Without WAIT='X', the commit is asynchronous — your next sRFC call may read stale data because the DB write hasn't completed yet. Fix: `Always pass WAIT='X' for integrations that read back data after writing`. [src4]
- **Not handling the full RETURN table**: Some BAPIs return multiple messages. Checking only RETURN (structure) misses errors in RETURN[] (table). Fix: `Always iterate the RETURN table, not just the RETURN export structure`. [src3]
- **Using dialog users for RFC integration accounts**: Dialog users (type A) have password expiration policies that break unattended integrations. Fix: `Create system users (type B) in SU01 for all RFC integration accounts`. [src8]
- **Connection pooling misconfiguration in JCo**: Default pool_capacity=1 causes serialization under load. Fix: `Set jco.destination.pool_capacity to match expected concurrency; set peak_limit 2-3x pool_capacity for burst handling`. [src2]
- **Ignoring SM58/SBGRFCMON monitoring**: Stuck tRFC/bgRFC entries silently accumulate, consuming DB space and eventually causing performance degradation. Fix: `Set up periodic monitoring jobs; alert on entries stuck >1h; implement automatic retry scheduling`. [src6, src7]
- **Hardcoding SAP field lengths**: SAP field lengths can change between releases (e.g., material number extended to 40 chars in S/4HANA). Fix: `Use JCo/NCo metadata APIs to dynamically determine field lengths; never hardcode CHAR(18) for MATNR`. [src2]

## Diagnostic Commands

```bash
# SAP transaction codes for RFC diagnostics (run in SAP GUI)

# Check RFC destination connectivity
SM59 → select destination → "Connection Test"

# Monitor stuck tRFC entries (legacy)
SM58 → filter by date/destination → check error messages

# Monitor bgRFC units and queues
SBGRFCMON → filter by destination/status → check unit details

# bgRFC unit history and performance
SBGRFCHIST → historical execution data
SBGRFCPERFMON → throughput and latency statistics

# Check short dumps from failed RFC calls
ST22 → filter by date/user → look for RFC-related dumps

# Check RFC system resource usage
SM66 → shows running RFC work processes and their status
SM04 → shows active RFC sessions

# Verify authorization for RFC function modules
SU53 → shows last authorization failure (run after failed call)

# Check SAP NW RFC SDK version (external)
# JCo version check:
java -cp sapjco3.jar com.sap.conn.jco.JCo

# PyRFC version check:
python -c "import pyrfc; print(pyrfc.__version__)"

# Test RFC connection from Python
python -c "
from pyrfc import Connection
c = Connection(ashost='host', sysnr='00', client='100', user='USER', passwd='PASS')
print('Connected:', c.get_connection_attributes())
c.close()
"
```

## Version History & Compatibility

| Component | Version | Status | Key Changes | Notes |
|---|---|---|---|---|
| bgRFC | NetWeaver 7.0+ (2004s) | Current, recommended | Replaces tRFC/qRFC; parallel schedulers | Use for all new async development |
| tRFC | All NetWeaver versions | Deprecated (functional) | Original async RFC with exactly-once | Migrate to bgRFC; no new features |
| qRFC | NetWeaver 6.20+ | Deprecated (functional) | Added FIFO ordering on top of tRFC | Migrate to bgRFC create_qrfc_unit() |
| sRFC | All versions | Current | Synchronous calls — unchanged since inception | Still correct choice for real-time lookups |
| aRFC | All versions | Current (limited use) | No delivery guarantee | Use only for non-critical parallel calls |
| JCo 3.1 | 3.1.x (2025) | Current | WebSocket RFC support, bgRFC support | Minimum Java 8; supports sRFC, tRFC, qRFC, bgRFC |
| NCo 3.1 | 3.1.x (2025) | Current | .NET 6+ support, WebSocket RFC | Replaces NCo 3.0; supports bgRFC |
| PyRFC | 3.3+ (2024) | Current | Python 3.8+ required | Archived on GitHub but still functional with SAP NW RFC SDK |
| SAP NW RFC SDK | 7.50+ | Current | Required by all external connectors | Download from SAP Support Portal (S-user required) |

[src1, src2]

### Deprecation Policy

SAP does not formally deprecate RFC variants via a sunset date — tRFC and qRFC remain functional indefinitely. However, all SAP documentation, training, and new feature development targets bgRFC exclusively. SAP Note 1889823 recommends bgRFC migration for all customers. The NW RFC SDK and connectors (JCo, NCo, PyRFC) follow SAP's standard product maintenance policy aligned with their host NetWeaver release. [src1, src6]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Integrating with SAP ECC or S/4HANA on-premise/private cloud | Using S/4HANA Cloud public edition | OData V4 APIs via SAP API Business Hub |
| Calling existing ABAP function modules or BAPIs | Building new APIs from scratch on S/4HANA | RAP (RESTful ABAP Programming) + OData |
| Need exactly-once async delivery (bgRFC) | Need real-time event streaming/webhooks | SAP Event Mesh or ALE/IDocs |
| Using Java, .NET, Python, or C/C++ client | Need browser-based or mobile integration | SAP Gateway OData services or SAP BTP APIs |
| Batch processing with guaranteed ordering | High-frequency, low-latency microservices | SAP Cloud SDK + API Management |
| Operating in a landscape without SAP BTP | Full cloud-native architecture on SAP BTP | SAP Integration Suite + Cloud Connector |

## Important Caveats

- **tRFC/qRFC are deprecated but not removed**: They will continue to work, but SAP invests zero effort in performance improvements. Plan bgRFC migration for any system on NetWeaver 7.0+. [src6]
- **RFC SDK licensing is strict**: JCo, NCo, PyRFC, and the NW RFC SDK cannot be bundled in commercial products without SAP licensing agreement. Verify your SAP license covers connector usage. [src2]
- **S/4HANA Cloud public edition does NOT support RFC**: Only OData, REST, and SOAP APIs are available. This entire card is irrelevant for S/4HANA Cloud public edition customers. [src1]
- **Performance varies dramatically by network latency**: sRFC round-trip time is directly affected by WAN latency. For cross-region integrations, consider SAP Cloud Connector or co-located middleware. [src1]
- **BAPI behavior can differ between ECC and S/4HANA**: Some BAPIs have extended or changed parameters in S/4HANA (e.g., extended material number to 40 chars). Always test against the target system version. [src2]

## Related Units

- [SAP OData and REST API for S/4HANA Cloud](/business/erp-integration/sap-odata-rest-api/2026)
- [SAP IDoc-based EDI Integration](/business/erp-integration/sap-idoc-integration/2026)
- [SAP Event Mesh Integration](/business/erp-integration/sap-event-mesh/2026)