Primary reference: https://help.sap.com/docs/integration-suite Cloud Integration: https://help.sap.com/docs/cloud-integration Creating integration flows: https://help.sap.com/docs/integration-suite/sap-integration-suite/creating-integration-flow Integration Flow Design Guidelines: https://help.sap.com/docs/cloud-integration (see "Integration Flow Design Guidelines")
SAP Integration Suite is SAP's open, modular iPaaS. The Cloud Integration capability designs and runs integration flows (iFlows) for application-to-application (A2A), business-to-business (B2B), and business-to-government (B2G) scenarios across cloud, on-premise, and hybrid landscapes.
Anatomy of an integration flow
Sender ──▶ [Start] ──▶ processing steps ──▶ [End] ──▶ Receiver
(adapter) Content Modifier (adapter)
Message Mapping
Router / Splitter
Request-Reply / Script
- Sender / Receiver adapters connect the runtime to systems. Common adapters:
HTTPS,SOAP,OData V2,OData V4,IDoc,SFTP,FTP,Mail,JMS,AMQP,AS2/AS4,Kafka,SuccessFactors,Ariba, andProcessDirect(flow-to-flow reuse). - Processing steps transform and route the message: Content Modifier, Message Mapping, Router, Splitter, Gather, Content Enricher, Filter, Request-Reply, Script.
Content Modifier — set headers, properties, and body
Use a Content Modifier to shape the message. Prefer exchange properties for values used later in the flow and headers for values sent to the receiver.
Message Header: X-Correlation-ID = ${header.SAP_MessageProcessingLogID}
Exchange Property: orderType = constant: STANDARD
Body: ${property.mappedPayload}
Groovy script — the message processing API
Scripts implement com.sap.gateway.ip.core.customdev.util.Message. Read/write the body,
headers, and properties; return the Message.
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// Read the body as a String (streaming-safe types are also supported)
def body = message.getBody(java.lang.String) as String
// Read headers and exchange properties
def headers = message.getHeaders()
def props = message.getProperties()
// ... transform ...
def transformed = body.trim()
// Write back
message.setBody(transformed)
message.setHeader("X-Processed", "true")
message.setProperty("status", "OK")
return message
}
Externalize configuration — never hardcode endpoints
Externalize environment-specific values (URLs, addresses, credential names) so the same iFlow moves cleanly across DEV/TEST/PROD without editing steps.
Address: {{receiver_endpoint_url}}
Credential Name: {{receiver_credential_alias}}
Maintain the values under the iFlow's Externalized Parameters.
Security material — reference secrets, don't embed them
Store secrets centrally under Monitor → Manage Security Material and reference them by name from adapters. Never place passwords, tokens, or keys inside a script or a header.
User Credentials— basic auth username/passwordOAuth2 Credentials/OAuth2 Authorization Code— token-based outbound authKeystore— X.509 key pairs and certificates for TLS / client-certificate auth
Error handling — Exception Subprocess
Wrap the integration process with an Exception Subprocess so failures are caught, logged, and (optionally) rethrown, instead of failing silently.
[Integration Process]
└── Exception Subprocess
[Error Start] ──▶ Content Modifier (capture ${exception.message})
──▶ Script (log / build fault) ──▶ [Error End]
Access the cause with the reserved property ${exception.message} (and the
CamelExceptionCaught header for the exception object).
Monitoring
Every processed message produces a Message Processing Log (MPL) in Monitor → Monitor Message Processing. Set custom MPL headers/properties for traceable correlation IDs. Enable payload logging only in non-productive tenants.
Common mistakes to avoid
- ❌ Hardcoding credentials, tokens, or endpoint URLs inside a Groovy script or Content Modifier — ✅ use Security Material + Externalized Parameters
- ❌ Loading huge payloads fully into memory in a script — ✅ split large messages (Splitter) and stream where possible
- ❌ No Exception Subprocess — a failure aborts the flow with no diagnostic context;
✅ always add one and capture
${exception.message} - ❌ Assuming exactly-once delivery — retries can redeliver; ✅ make receivers idempotent (e.g. key on a correlation ID)
- ❌ Logging full payloads with sensitive data in productive tenants — ✅ disable payload logging or mask fields
- ❌ Duplicating the same logic across iFlows — ✅ extract shared steps into a
ProcessDirect-connected flow - ❌ Setting values as headers when they are only needed internally — ✅ use exchange properties for in-flow state, headers only for what the receiver needs